Every provider is seeded the same skills bundle; a provider without native skill discovery gets a frontmatter-derived skills index appended to its context file, whose name must be lab-owned and never repo-tracked¶
The embedded skills bundle (assets/skills, a single go:embed all:skills source) is seeded into each provider's declared SeedMeta.SkillsDir on every spawn, but the agent only ever discovers it through Claude Code's .claude/skills convention. The bundle content is agent-agnostic markdown: each SKILL.md carries YAML frontmatter whose description already embeds the "use when…" triggers that tell an agent when to reach for the playbook. A provider whose CLI reads only AGENTS-style context files — the Codex provider, #2 — receives the bundle on disk but has no way to learn it exists. The generated context file (issue #51 decision 8) describes the tracker binding, the labctl vocabulary, and the triage-label table, and never mentions the seeded skills. Such an agent gets the labctl vocabulary but none of the workflow playbooks (triage, land-pr, to-issues, to-prd, …) that carry AFK quality. A second, quieter hazard rides the same surface: SeedMeta.ContextFileName is free-form, and the natural name for a Codex provider is its CLI's native AGENTS.md — a file repositories legitimately track, which lab must never write.
ADR-0026 made the provider seam provider-neutral by construction and promised a second provider is "one new implementation and zero refactor of the generic core." Issue #51 decision 8 carried that into workspace seeding: it lifted every claude-specific shape the seeder used to hardcode — the .claude/skills dir, the CLAUDE.local.md name, the exclude entries, the incogni scrub/path patterns — into provider.SeedMeta, so ONE generic seeder serves any agent CLI. The split kept the content lab's (the skills bytes and the context-file template are internal/seeder's) and made only the destination name/dir provider-declared. ADR-0012 first vendored the skills bundle, seeded it on every spawn, and pinned the .git/info/exclude (never .gitignore) mechanism that hides lab-seeded files from git status (D15 §9 measure 6). ADR-0033 and ADR-0034 continued ADR-0026's provider-neutral-by-construction carry across the attribution-marker and host-config surfaces. This ADR carries the same promise into the skills/context-file seeding surface: it routes the bundle to a skills-less agent through the one channel every provider reads — its context file — without forking the bundle, and it pins the context-file name to a lab-owned convention so the seam can never be satisfied by writing a file the repo tracks.
The pins, decided:
- The SAME embedded bundle seeds every provider with a non-empty
SkillsDir— no content fork, no per-provider curation list. The bundle stays a singlego:embed all:skillssource copied verbatim into<worktree>/<SkillsDir>/; the bytes are identical for claude-code, for Codex, and for provider N+1. Only discovery differs between providers, never content — a curation or subsetting mechanism would fork the one asset the seeder is careful to keep single, and pick winners about which agent deserves which playbook. SeedMeta.NativeSkillDiscovery boolgates a generated skills-index section on the context file. claude-code declarestrue(the.claude/skillsconvention finds the bundle on its own). When a provider declaresfalseand itsSkillsDiris non-empty,renderContextFileappends a skills-index section to the rendered context file: one line per bundled skill, rendered from that skill's frontmatter (name+description— the description already carries the "use when…" trigger, so the line needs no hand-written copy), pointing at the skill's seeded path<SkillsDir>/<name>/SKILL.md. The paths reflect THAT provider's declaredSkillsDir, not a constant. An agent that follows file pointers pulls the full playbook on demand; the context file grows about one line per skill, not pages. A provider with an emptySkillsDirgets no index section regardless of the flag — there is nothing seeded to point at.- The index is parsed once at seeder package initialization and fails loudly and early. The index entries come from each bundled skill's YAML frontmatter, parsed exactly once at
internal/seederpackage init straight from the embedded bundle — not lazily at seed time, per worktree. A bundled skill with malformed or missing frontmatter panics at init, which any test run and the binary's own boot catch, so a broken bundle is a build/test-time failure that stops the release — never a silently broken or partial index materialized into a live worktree at seed time, where no one is watching. SeedMeta.ContextFileNameMUST be a lab-owned, never-repo-tracked name — the.local-suffixed convention (CLAUDE.local.md,AGENTS.local.md). This is a hard rule on the field, documented onSeedMeta.ContextFileNameininternal/provider/provider.go. Lab must never write a file repositories legitimately track (e.g. Codex's nativeAGENTS.md): a tracked file cannot be hidden by.git/info/exclude(excludes touch only untracked files), would be clobbered on every re-seed, would dirty every diff, and would break incogni (D15 §9 measure 6). Making the agent CLI actually read the lab-owned name is the adapter's OWN job in itsSeedWorkspace— e.g. a Codex project-config file pointing the CLI atAGENTS.local.md— a live-verified coupling held to the ADR-0008 bar, never solved by declaring a tracked name here and letting the CLI find it for free. The conformance suite (#80) will assert the naming convention across every registered provider.- Claude-code seeding stays byte-identical, pinned by goldens. Native discovery means no index section, so claude-code's rendered
CLAUDE.local.md— and its whole seeded worktree — is unchanged from today. The pre-change renders are captured as golden fixtures (internal/seeder/testdata/contextfile-claude-*.golden), so any accidental drift in the generic render path fails a test rather than silently reshaping every claude worktree.
Out of scope: the Codex AgentProvider itself (#2, ready-for-human), including the SeedWorkspace wiring that points the Codex CLI at AGENTS.local.md — this ADR only makes that a pure downstream add. Conformance-suite enforcement of the naming convention is #80. Any curation or subsetting of which skills a provider receives is explicitly rejected below, not deferred. Changes to skill content or to the frontmatter schema are not in scope — the index reads the existing name/description fields and writes nothing back.
Status¶
Accepted. Extends provider.SeedMeta (issue #51 decision 8) with NativeSkillDiscovery, hardens the ContextFileName contract with the lab-owned-name rule, and adds the conditional skills-index render to internal/seeder's context-file path; the single go:embed skills bundle (ADR-0012) is unchanged and the .git/info/exclude seeding-hide mechanism (D15 §9 measure 6) is why the tracked-name rule exists. Carries ADR-0026's provider-neutral-by-construction promise into the skills/context-file seeding surface, mirroring ADR-0033's and ADR-0034's carry of the same promise into the attribution-marker and host-config surfaces. The adapter-owned "make the CLI read the lab-owned file" coupling is held to the ADR-0008 live-verification bar. Relates to #2 (Codex): it seeds the shared bundle and gets the generated index for free, and lands its AGENTS.local.md-reading SeedWorkspace with no change to the generic seeder; the naming convention is enforced by the conformance suite in #80. Resolves #79.
Considered options¶
- Curate a per-provider skill subset, or fork the bundle per provider. Rejected: the bundle content is agent-agnostic markdown; every skill's "use when…" trigger applies to any agent that follows file pointers, so there is no principled per-provider subset to curate — only an arbitrary one. Curation or a fork would split the single
go:embedasset the seeder deliberately keeps unified, add a per-provider list to maintain in lockstep with the bundle, and pick winners about which agent deserves which playbook. The same bundle for everyone plus per-provider discovery gives every agent the full set at zero content-maintenance cost. - Teach each skills-less CLI native discovery in its adapter, instead of indexing from the context file. Rejected: a CLI that reads only AGENTS-style context files has no
.claude/skills-equivalent discovery mechanism to teach — there is nothing to point at. This option couples lab to N per-provider discovery mechanisms that do not exist and would have to be invented and live-verified one by one, exactly the accretion ADR-0026 rules out. Indexing rides the one channel every context-file-reading agent already has, so a new skills-less provider needs onlyNativeSkillDiscovery: falseand inherits the index with no new discovery code. - Inline the full skill bodies into the context file instead of one pointer line each. Rejected: the playbooks run to pages; inlining them all would bloat the context file into an unreadable wall the agent must load in full on every turn, defeating the "grows about one line per skill" property. A frontmatter-derived pointer line carries the "use when…" trigger the agent needs to decide to read a skill, and the agent pulls the full body on demand by following the path — the whole point of file pointers.
- Seed the provider's native tracked context-file name (e.g. Codex's
AGENTS.md) so the CLI reads it with no adapter work. Rejected by the hard rule:AGENTS.mdis a file repositories legitimately track, and a tracked file cannot be hidden by.git/info/exclude, is clobbered on every re-seed, dirties every diff, and breaks incogni (D15 §9 measure 6). The one-time convenience of the CLI finding the file for free is bought at the cost of corrupting the repo's tracked state on every spawn. The lab-owned.localname plus an adapter that points its CLI at that name (a live-verified coupling, the ADR-0008 bar) keeps the seeded file invisible to git and costs the adapter a few lines it already owns. - Parse each skill's frontmatter lazily at seed time and skip a skill whose frontmatter won't parse. Rejected: skip-on-error produces a silently broken or partial index in a live worktree, where no one is watching — an agent would just never learn about the dropped skill, with no signal that anything failed. Parsing once at package init turns a malformed bundle into a panic that every test run and the binary's own boot catch, so the failure is loud, early, and blocks the release rather than degrading a real spawn.