Contributing

Manual Curation Pipeline

The exact commands to take a skill from discovery to a closed intake. No AI required. Every phase with every command, typed by a human.

⚡ Quick path — 2 approvals, everything else automated
gaia curate https://github.com/owner/repo [--generic <id>] [--discover]
🛑 Gate 1 — Topology Confirm mapping + upstream URL. ~30 sec.
→
🛑 Gate 2 — Evidence + Stars Approve verified rows + auto-computed rating.
→
✅ Auto-merged CI green → merge → docs.

The reference below explains what runs inside each gate. Use it when you need full control or are debugging a step.

Pipeline overview

#PhaseWhat you produceGate
1gaia-curateA discovery-packet-v2 JSON in registry-for-review/discovery-packets/Human L4
2L4 ReviewYou append l4Resolution to the packetHard stop — must be you
3gaia push → PRIntake issue opened; draft PR on a review/meta branchCI green
4ev-pipelineVerified evidence lake ready for ingestHuman approves evidence
5gaia-ingestEvidence rows written, TM appraised, stars calibratedHuman approves calibration
6ClosePR merged, intake issue closed with findings commentDone
1

gaia-curate — Discover & package the skill

You have a real repo with a SKILL.md. Run prefill, apply the 6-rule mapping decision, write the packet, validate. Nothing touches the registry yet.

Step 1 — Preflight

bashclick to copy
# confirm gaia CLI is installed
gaia --version

# confirm gh CLI is authenticated
gh auth status

# confirm python3 available
python3 --version

Step 2 — Snapshot the generic list

Save this file. It's the trust anchor for packet validation. Don't overwrite it mid-run.

bashclick to copy
gaia dev list --generic --json > /tmp/generic-snapshot.json
wc -l /tmp/generic-snapshot.json

Step 3 — Run prefill against the SKILL.md URL

bashclick to copy
gaia dev prefill contributor/skill-name \
  --name "Skill Name" \
  --description "Verbatim from SKILL.md frontmatter" \
  --url "https://github.com/owner/repo/blob/main/SKILL.md" \
  --stdout > /tmp/prefill-output.json

cat /tmp/prefill-output.json | python3 -m json.tool | head -80
ℹ

Drop --stdout and gaia dev prefill writes the packet straight to registry-for-review/discovery-packets/<candidate-id-slug>.json — there is no --output flag.

Step 4 — Apply the 6-rule mapping decision

Rule (first match wins)DecisionWhen
1NOT_A_SKILLartifactGate != "valid-skill"
2DUPLICATEexactDedupe != null
3DEFERambiguity != null
4NEW_GENERICnTotal == 0
5MAPnStrong == 1 — use that genericId
6DEFERAll other cases (weak only, or nStrong ≥ 2)
ℹ

Count nStrong = entries with matchTier == "strong" in mappingOptions[]. Count nTotal = total entries. Do not re-rank.

Step 5 — Write and validate the discovery-packet-v2

Update the packet at registry-for-review/discovery-packets/owner--skill-name.json with your Step 4 decision. Key fields (matching what validate_discovery_packet.py actually checks — decision is an object, not a string, and the top-level field is contractVersion, not schemaVersion):

json — minimum required fieldsclick to copy
{
  "contractVersion": "discovery-packet-v2",
  "candidateId": "owner/skill-name",
  "source": { "canonicalUrl": "<blob-url>", "sourceLane": "source-repository" },
  "normalized": { "name": "verbatim from frontmatter", "description": "verbatim" },
  "exactDedupe": { "matched": false },
  "mappingOptions": [ /* copy from prefill-output.json — each needs genericId, rationale, similarity, matchTier */ ],
  "decision": { "value": "MAP", "reasonCode": "MAP_EXISTING_GENERIC", "genericId": "<id from strong option>" },
  "flags": [ /* copy from prefill-output.json */ ],
  "genericSnapshot": { "capturedAt": "<ISO timestamp>", "command": "gaia dev list --generic --json", "contentSha256": "<hash>", "mappingOptionsSha256": "<hash>", "generics": [ /* snapshot contents */ ] },
  "lifecycle": [ "discovered", "fetched", "parsed", "normalized", "deduped", "mapped", "review-ready" ]
}
⚠

The "review-ready" lifecycle end state requires the full six-stage prefix shown above. gaia dev prefill (Step 3) only ever emits ["discovered", "deferred"] — that's by design, not a gap: prefill just ranks mapping options, it never fetches or reads anything. Advancing to "fetched" and "parsed" is on you, the curator who actually opened the URL. Add source.hostRepository (the repo URL), source.fetchedAt (an ISO timestamp for when you fetched it), and source.contentSha256 (a SHA-256 of the raw SKILL.md text — sha256sum <file> or shasum -a 256 <file>) for "fetched"; add source.frontmatter.name and source.frontmatter.description — the same verbatim values you already passed to Step 3's --name/--description — for "parsed". Run the validator after every edit rather than guessing.

bash — validateclick to copy
python3 .agents/skills/gaia-curate/scripts/validate_discovery_packet.py \
  --generic-snapshot /tmp/generic-snapshot.json \
  registry-for-review/discovery-packets/owner--skill-name.json

# Must exit 0 with no MALFORMED_PACKET or MISSING_REQUIRED_FIELD errors
🛑
Stop — L4 Human Gate

Review the packet carefully before continuing. The next step writes it to the intake queue.

2

L4 Review — You ratify the topology

No one else does this step. Check the packet, append l4Resolution, re-validate.

What to check

  • Mapping decision is correct — does selectedGenericId match the skill's actual capability?
  • If NEW_GENERIC: is the proposed name and description vendor-neutral and falsifiable?
  • source.url is a real blob/ GitHub URL — not tree/ or a listing page.
  • normalized.description is verbatim from the SKILL.md frontmatter — not paraphrased.
  • Similarity score (mappingOptions[].similarity) and matchTier make sense.

Append l4Resolution

json — append to packetclick to copy
"l4Resolution": {
  "generic": { "id": "final-generic-id", "name": "Human Readable Name", "description": "Vendor-neutral, falsifiable.", "type": "basic", "prerequisites": [] },
  "named": { "contributor": "github-handle", "skillName": "kebab-case-name" },
  "upstreamSkillFileUrl": "https://github.com/owner/repo/blob/main/SKILL.md"
}
bash — re-validate after appendingclick to copy
python3 .agents/skills/gaia-curate/scripts/validate_discovery_packet.py \
  --generic-snapshot /tmp/generic-snapshot.json \
  registry-for-review/discovery-packets/owner--skill-name.json
3

gaia push → Draft PR — Open the intake issue

bashclick to copy
git checkout -b review/meta/github-handle--skill-name

# Dry run first
gaia push --from-file registry-for-review/discovery-packets/owner--skill-name.json --dry-run

# Real run — opens intake issue (auto-labels: intake + needs-triage)
gaia push --from-file registry-for-review/discovery-packets/owner--skill-name.json

git add registry-for-review/discovery-packets/owner--skill-name.json
git commit -m "feat(intake): curate contributor/skill-name [closes #ISSUE]"
git push -u origin review/meta/github-handle--skill-name
gh pr create --draft --title "feat(intake): ..." --body-file /tmp/pr-body.md

intake:* label lifecycle

These are machine gates — intake-approval.yml watches for them and fires automatically.

LabelWho appliesWhat it triggers
intakeAuto (gaia push)Routes into intake queue
needs-triageAuto (gaia push)Marks as awaiting review
intake:topology-approvedMaintainer onlyWorkflow fires: adds evidence-review, removes needs-triage
intake:evidence-reviewAuto (workflow)Signals agent to prepare Stage-1 seed
intake:evidence-readyAgent / youEvidence plan ready for human approval
intake:evidence-approvedMaintainer onlyOpens the single draft promotion PR
intake:rejectedMaintainer onlyCloses intake; no automation fires
⚠

intake:evidence-approved requires both intake:evidence-review and intake:evidence-ready to already be present. The workflow errors if either is missing.

bash — approve topology when ready (maintainer only)click to copy
gh issue edit <ISSUE_NUMBER> --add-label "intake:topology-approved"
# Fires intake-approval.yml — watch it:
gh run list --workflow=intake-approval.yml
4

ev-pipeline — Verify evidence before ingesting

Operates on evidence/by-type/ files only. Never touches registry/. Each phase produces review artifacts; you decide what to approve.

Phase 0 — ev-discovery (skippable)

The only phase that searches the web for new evidence. Skip for routine Stage-1 intakes. Run when you need benchmark-result, arxiv, peer-review, or richer social-signal rows.

⚠

No gaia CLI command runs this phase — there is no gaia dev discover. Trigger the ev-discovery agent skill directly (/ev-discovery in Claude Code), naming the skill id, source repo, and evidence types needed. It requires FIRECRAWL_API_KEY and skips gracefully if absent. This is the one phase on this page that needs an AI agent — every other phase is a plain command.

Discovered rows get appended to evidence/by-type/<type>.md under the same source-input format Phase 1 already reads — see Phase 1 below.

Phase 1 — ev-collection

⚠

This runs on the entire registry — not just your new skill. generate_source_dump.py reads all named-skill evidence rows across every skill in registry/named/. Your new skill's rows appear alongside all others. That is expected.

bashclick to copy
python3 evidence/scripts/generate_source_dump.py \
  --output-dir evidence --by-type-dir evidence/by-type

python3 evidence/scripts/compile_data_lake.py \
  --sources evidence/by-type --lake evidence

Phase 2 — ev-star-verification

bashclick to copy
# Check auth first — zero stars from an unauth'd call is poison data
gh auth status
gh api repos/OWNER/REPO --jq '.stargazers_count'
# Flag rows where recorded stars differ from live count. Do NOT silently update.

Phase 3 — ev-adversarial-audit

bash — check for common issuesclick to copy
# Find github tree/ URLs that should be blob/
grep -rn "github.com/.*/tree/" evidence/by-type/

# Find subjective wording not backed by source
grep -rni "elite\|high-quality\|best-in-class\|leading" evidence/by-type/

Phase 4 — ev-link-validation

bashclick to copy
python3 evidence/scripts/validate_sources.py
# Or a 10-URL sample first:
python3 evidence/scripts/validate_sources.py 10
🛑
Human Evidence Gate

Review the source report. Approve rows to ingest. Remove dead-link, subjective, or type-mismatched rows. Only pass live, correctly scoped rows to Phase 5.

5

gaia-ingest — Write evidence to the named skill

First time mutating registry/. Docs rebuild is skipped by default — no flag needed. Run gaia dev build once after all rows, or pass --build on a single row instead. You approve calibration before it runs.

Ingest each approved evidence row

bash — repo-ownclick to copy
GAIA_OPERATOR_OVERRIDE=1 gaia dev evidence contributor/skill-id \
  "https://github.com/owner/repo" \
  --type repo-own --commits 847 --contributors 12 \
  --notes "Official upstream repo. Counts verified via GitHub API." \
  --source-started-at 2024-03-01
bash — github-stars-ownclick to copy
GAIA_OPERATOR_OVERRIDE=1 gaia dev evidence contributor/skill-id \
  "https://github.com/owner/repo/blob/main/SKILL.md" \
  --type github-stars-own --stars 3421 --skill-count-in-repo 1 \
  --notes "Official SKILL.md. Star count verified live via gh api." \
  --source-started-at 2024-03-01
bash — build + appraise + calibrateclick to copy
# Single build after all rows are written
GAIA_OPERATOR_OVERRIDE=1 gaia dev build

# Appraise Trust Magnitude
PYTHONPATH=src python3 scripts/trust_appraise.py --skill contributor/skill-id

# Only after you approve the proposed calibration:
GAIA_OPERATOR_OVERRIDE=1 gaia dev calibrate contributor/skill-id 2★
GAIA_OPERATOR_OVERRIDE=1 gaia dev validate

TM grade reference

Trust Magnitude is the sole promotion gate under Yggdrasil II. Thresholds sourced from src/gaia_cli/grading.py and META.md §1.1.

GradeTM floorStars it gatesNotes
ungraded< 201★–2★Stage-1 minimum (Awakened / Named baseline)
C≥ 20up to 3★Badge unlock floor at 2★ Named
B≥ 50up to 3★Solid adoption signals (Evolved)
A≥ 100gates 4★4★ Extra/Unique gate — Origin + TM ≥ 100
S≥ 250 + diversitygates 5★–6★Diversity gate: ≥3 evidence types + non-self-producible row. 5★ = TM ≥ 250. 6★ Apex adds 6-predicate gate.
ℹ

The per-star Evidence Floor is retired. TM is the sole gate. But the Star Bar (installability, 3★+ requires a verified GitHub blob/ link) still applies.

6

Close — Merge PR & post intake comments

bashclick to copy
gh pr ready <PR_NUMBER>
gh pr checks <PR_NUMBER>

# When CI is green:
gh pr merge <PR_NUMBER> --subject "feat(registry): ingest contributor/skill-name [closes #ISSUE]"

# Post findings comment on PR (evidence table + TM + badge status)
gh pr comment <PR_NUMBER> --body-file /tmp/pr-close-comment.md

# Post closing comment on intake issue (path-to-promotion, @contributor tag)
gh issue comment <ISSUE_NUMBER> --body-file /tmp/issue-close-comment.md
gh issue close <ISSUE_NUMBER>

# Regenerate Class S site artifacts
GAIA_OPERATOR_OVERRIDE=1 gaia dev docs
git add docs/graph/ && git commit -m "chore: regenerate Class S artifacts" && git push

Common errors

UNTRUSTED_GENERIC_SNAPSHOT

The contentSha256 in the packet doesn't match the snapshot file passed to --generic-snapshot.

bash — recompute the hashclick to copy
python3 -c "import json,hashlib; d=json.load(open('/tmp/generic-snapshot.json')); print(hashlib.sha256(json.dumps(d,sort_keys=True,separators=(',',':')).encode()).hexdigest())"

INVALID_GENERIC_SELECTION — mapped ID not in snapshot

You used a genericId that wasn't in the snapshot you captured. Re-capture the snapshot after adding the new generic, or use an ID that's actually there.

gaia dev evidence fails — "unknown evidence type"

bashclick to copy
gaia dev evidence --help
# Lists all supported --type values and required flags

gaia dev validate fails after ingest

bashclick to copy
GAIA_OPERATOR_OVERRIDE=1 gaia dev validate --verbose
# Read the first error — usually a missing field or schema mismatch

Cheat sheet — every command in order

bash — full pipeline sequenceclick to copy
# ── Phase 1: Curate ──────────────────────────────────────────
gaia dev list --generic --json > /tmp/generic-snapshot.json
gaia dev prefill contributor/skill-name --name "Skill Name" --description "..." --url "<blob-url>" --stdout > /tmp/prefill-output.json
# ... write packet JSON ...
python3 .agents/skills/gaia-curate/scripts/validate_discovery_packet.py --generic-snapshot /tmp/generic-snapshot.json <packet>.json

# ── Phase 2: L4 ──────────────────────────────────────────────
# Append l4Resolution to packet, re-validate

# ── Phase 3: Push + PR ───────────────────────────────────────
git checkout -b review/meta/handle--skill
gaia push --from-file <packet>.json --dry-run
gaia push --from-file <packet>.json           # auto-labels issue: intake + needs-triage
git add . && git commit -m "feat(intake): ..." && git push -u origin <branch>
gh pr create --draft --title "..." --body-file /tmp/pr-body.md
gh issue edit <ISSUE> --add-label "intake:topology-approved"  # maintainer only
gh issue edit <ISSUE> --add-label "intake:evidence-approved"   # maintainer only, after evidence-ready

# ── Phase 4: ev-pipeline ─────────────────────────────────────
# Phase 0 (skippable, no CLI equivalent — run the ev-discovery agent skill instead)
# /ev-discovery contributor/skill "<repo-url>" arxiv,peer-review,social-signal
# Phase 1 (whole-registry lake rebuild)
python3 evidence/scripts/generate_source_dump.py --output-dir evidence --by-type-dir evidence/by-type
python3 evidence/scripts/compile_data_lake.py --sources evidence/by-type --lake evidence
gh api repos/OWNER/REPO --jq '.stargazers_count'   # phase 2 star check
grep -rn "github.com/.*/tree/" evidence/by-type/      # phase 3 adversarial
python3 evidence/scripts/validate_sources.py          # phase 4 link health

# ── Phase 5: gaia-ingest ─────────────────────────────────────
GAIA_OPERATOR_OVERRIDE=1 gaia dev evidence contributor/skill "<url>" \
  --type repo-own --commits N --contributors N --notes "..." --source-started-at YYYY-MM-DD
# ... repeat for each evidence type ...
GAIA_OPERATOR_OVERRIDE=1 gaia dev build
PYTHONPATH=src python3 scripts/trust_appraise.py --skill contributor/skill
GAIA_OPERATOR_OVERRIDE=1 gaia dev calibrate contributor/skill N★  # after your approval
GAIA_OPERATOR_OVERRIDE=1 gaia dev validate

# ── Phase 6: Close ───────────────────────────────────────────
gh pr ready <PR> && gh pr checks <PR>
gh pr merge <PR> --subject "feat(registry): ... [closes #ISSUE]"
gh pr comment <PR> --body-file /tmp/pr-close-comment.md
gh issue comment <ISSUE> --body-file /tmp/issue-close-comment.md
gh issue close <ISSUE>
GAIA_OPERATOR_OVERRIDE=1 gaia dev docs

Want to automate this? Become a contributor.

Once you've curated a skill manually, you can contribute back to the registry directly using gaia dev commands — the same CLI the pipeline runs under the hood. No intake queue. Direct mutations with your approval.

What you want to doCommand
Add a generic skill nodegaia dev add "Name" --id kebab-id --type basic --description "..."
Add a named implementationgaia dev named --contributor handle --skill slug --generic id --upstream <blob-url>
Add an evidence rowgaia dev evidence contributor/skill "<url>" --type repo-own --commits N ...
Appraise Trust MagnitudePYTHONPATH=src python3 scripts/trust_appraise.py --skill contributor/skill
Calibrate star levelgaia dev calibrate contributor/skill N★
Fuse a suite capstonegaia dev fuse <id> --name "..." --prereqs id1,id2 --named-capstone contributor/slug
Validate registryGAIA_OPERATOR_OVERRIDE=1 gaia dev validate
Regenerate site artifactsGAIA_OPERATOR_OVERRIDE=1 gaia dev docs
✓

All gaia dev mutations require GAIA_OPERATOR_OVERRIDE=1 or maintainer permissions. Read Contributing §1C before making direct registry changes. Or run gaia curate <url> to automate the full pipeline with 2 human gates.