Skills for skills-less providers: seeded bundle indexed from the context file; lab-owned context-file name rule #79

Closed
opened 2026-07-09 21:46:16 +02:00 by dominik.polakovics · 2 comments

Context

The embedded skills bundle (assets/skills, seeded into SeedMeta.SkillsDir) is only discovered via Claude's .claude/skills convention — the content itself is agent-agnostic markdown with frontmatter descriptions that already carry 'use when…' triggers. A provider without native skill discovery (#2 Codex reads AGENTS-style context files only) would get the labctl vocabulary from the context file but none of the workflow playbooks (triage, land-pr, to-issues, to-prd) that carry AFK quality.

Decided in provider-seam grill (2026-07-09):

  1. Seed the SAME bundle for every provider into its declared SkillsDir; no content fork, no curation list.
  2. For providers without native discovery, the generated context file gains an index section: one line per skill rendered from its frontmatter (name + description), pointing at the seeded path ('when doing X, read /triage/SKILL.md'). Agents that follow file pointers get the full playbooks on demand; the context file grows ~one line per skill, not pages.
  3. Hard rule: ContextFileName must be a lab-owned, never-tracked name (CLAUDE.local.md, AGENTS.local.md.local-suffixed convention). Lab must never write a file repos legitimately track (Codex's native AGENTS.md): a tracked file can't be hidden by .git/info/exclude, would be clobbered on re-seed, would show in every diff, and would break incogni measure 6. Making the CLI actually READ the lab-owned file is the ADAPTER's job in SeedWorkspace (e.g. Codex project config pointing at AGENTS.local.md) — a live-verified coupling like every other (ADR-0008 bar).

Design

  • SeedMeta gains NativeSkillDiscovery bool (claude-code: true). When false and SkillsDir is non-empty, renderContextFile appends the generated skills index section.
  • Index entries come from each bundled skill's frontmatter; parse once (embed-time or seeder init). A skill with unparseable frontmatter fails loudly at build/test time, not silently at seed time.
  • Document the lab-owned-name hard rule on SeedMeta.ContextFileName (internal/provider/provider.go) and in the ADR. The conformance suite (follow-up issue) will assert the naming convention.
  • Claude-code seeding stays byte-identical (native discovery → no index section) — pin with the existing golden pattern.

Sequencing

Touches the same SeedMeta/internal/seeder surface as #75 (in progress). Blocked until #75 merges to avoid churn conflicts — re-triage to ready-for-agent then.

Acceptance

  • Fake provider with NativeSkillDiscovery: false seeds the bundle and gets a context file listing every bundled skill with correct paths.
  • Claude-code worktree seeding byte-identical to today (golden).
  • Hard rule documented; ADR recorded.
  • No content fork of the bundle; single go:embed source remains.
## Context The embedded skills bundle (`assets/skills`, seeded into `SeedMeta.SkillsDir`) is only *discovered* via Claude's `.claude/skills` convention — the content itself is agent-agnostic markdown with frontmatter descriptions that already carry 'use when…' triggers. A provider without native skill discovery (#2 Codex reads AGENTS-style context files only) would get the labctl vocabulary from the context file but none of the workflow playbooks (triage, land-pr, to-issues, to-prd) that carry AFK quality. Decided in provider-seam grill (2026-07-09): 1. **Seed the SAME bundle for every provider** into its declared `SkillsDir`; no content fork, no curation list. 2. **For providers without native discovery, the generated context file gains an index section**: one line per skill rendered from its frontmatter (`name` + `description`), pointing at the seeded path ('when doing X, read <SkillsDir>/triage/SKILL.md'). Agents that follow file pointers get the full playbooks on demand; the context file grows ~one line per skill, not pages. 3. **Hard rule: `ContextFileName` must be a lab-owned, never-tracked name** (`CLAUDE.local.md`, `AGENTS.local.md` — `.local`-suffixed convention). Lab must never write a file repos legitimately track (Codex's native `AGENTS.md`): a tracked file can't be hidden by `.git/info/exclude`, would be clobbered on re-seed, would show in every diff, and would break incogni measure 6. Making the CLI actually READ the lab-owned file is the ADAPTER's job in `SeedWorkspace` (e.g. Codex project config pointing at `AGENTS.local.md`) — a live-verified coupling like every other (ADR-0008 bar). ## Design - `SeedMeta` gains `NativeSkillDiscovery bool` (claude-code: true). When false and `SkillsDir` is non-empty, `renderContextFile` appends the generated skills index section. - Index entries come from each bundled skill's frontmatter; parse once (embed-time or seeder init). A skill with unparseable frontmatter fails loudly at build/test time, not silently at seed time. - Document the lab-owned-name hard rule on `SeedMeta.ContextFileName` (`internal/provider/provider.go`) and in the ADR. The conformance suite (follow-up issue) will assert the naming convention. - Claude-code seeding stays byte-identical (native discovery → no index section) — pin with the existing golden pattern. ## Sequencing Touches the same `SeedMeta`/`internal/seeder` surface as #75 (in progress). **Blocked until #75 merges** to avoid churn conflicts — re-triage to `ready-for-agent` then. ## Acceptance - Fake provider with `NativeSkillDiscovery: false` seeds the bundle and gets a context file listing every bundled skill with correct paths. - Claude-code worktree seeding byte-identical to today (golden). - Hard rule documented; ADR recorded. - No content fork of the bundle; single `go:embed` source remains.
Author
Owner

This was generated by AI during triage.

Agent Brief

Category: enhancement
Summary: Seed the same skills bundle for every provider; for providers without native skill discovery, append a generated skills index to the context file; enforce the lab-owned context-file-name rule.

Sequencing note: the "blocked until #75 merges" condition in the issue body is satisfied — #75 landed via PR #81 (ADR-0033). SeedMeta.ScrubPatterns was widened there; this issue touches the same struct but a disjoint surface (context file + skills), so no churn conflict remains.

Current behavior:
The embedded skills bundle (single go:embed source) is seeded into each provider's declared SeedMeta.SkillsDir, but discovery relies entirely on Claude's .claude/skills convention. A provider whose CLI reads only AGENTS-style context files (e.g. the Codex provider, #2) receives the bundle on disk but has no way to learn it exists: the generated context file describes the tracker binding, labctl vocabulary, and triage labels, and never mentions the seeded skills. Such an agent gets none of the workflow playbooks (triage, land-pr, to-issues, to-prd, …) that carry AFK quality.

Desired behavior:

  1. Same bundle for every provider. Every provider with a non-empty SkillsDir gets the identical embedded bundle — no content fork, no per-provider curation list.
  2. SeedMeta gains NativeSkillDiscovery bool (claude-code declares true). When a provider declares false AND has a non-empty SkillsDir, the rendered context file gains an appended skills-index section: one line per bundled skill, rendered from that skill's frontmatter (name + description), pointing at its seeded path — the shape is "when doing X, read <SkillsDir>/<name>/SKILL.md". Agents that follow file pointers pull the full playbook on demand; the context file grows about one line per skill, not pages.
  3. Frontmatter parsing fails loudly and early. Index entries come from each skill's frontmatter, parsed once (embed-time or seeder init). A bundled skill with unparseable frontmatter must fail at build/test time — never silently produce a broken or partial index at seed time.
  4. Hard rule, documented: SeedMeta.ContextFileName must be a lab-owned, never-tracked name — the .local-suffixed convention (CLAUDE.local.md, AGENTS.local.md). Lab must never write a file repositories legitimately track (e.g. Codex's native AGENTS.md): a tracked file can't be hidden by .git/info/exclude, would be clobbered on re-seed, would show in every diff, and would break incogni. Document this on the SeedMeta.ContextFileName field and in an ADR. Making the CLI actually read the lab-owned file is the adapter's job in its SeedWorkspace (e.g. Codex project config pointing at AGENTS.local.md) — a live-verified coupling per the ADR-0008 bar; not this issue's job to build for Codex.
  5. Claude-code seeding stays byte-identical. Native discovery → no index section → the rendered CLAUDE.local.md is unchanged. Pin with the existing golden pattern.

Key interfaces:

  • SeedMeta (provider package) — new NativeSkillDiscovery bool field, with doc comment; claude-code's declaration sets it true and its seedmeta pin test covers it.
  • The context-file rendering path in the seeder — currently renders a generic lab-owned body from an embedded template; gains the conditional index section driven by the provider's SeedMeta.
  • The embedded skills bundle — each SKILL.md carries YAML frontmatter with name and description; the description already embeds "use when…" triggers, so index lines need no extra copy.
  • SeedMeta.ContextFileName doc comment + a new ADR recording the lab-owned-name hard rule and the index design.

Acceptance criteria:

  • A fake provider with NativeSkillDiscovery: false and a non-empty SkillsDir seeds the full bundle and gets a context file whose index section lists every bundled skill with a correct seeded path (paths reflect THAT provider's declared SkillsDir).
  • A provider with NativeSkillDiscovery: true (claude-code) gets no index section; its seeded worktree — context file included — is byte-identical to today, pinned by golden.
  • A provider with an empty SkillsDir gets no index section regardless of the flag.
  • A bundled skill with malformed/missing frontmatter fails a build-time or test-time check, not seed time.
  • The lab-owned-name hard rule is documented on the ContextFileName field and in an ADR.
  • The bundle remains a single go:embed source — no fork, no curation list.

Out of scope:

  • The Codex provider itself (#2), including its SeedWorkspace wiring that points the CLI at AGENTS.local.md.
  • Conformance-suite enforcement of the naming convention — that's #80.
  • Any curation/subsetting of which skills a provider receives.
  • Changes to skill content or frontmatter schema.
> *This was generated by AI during triage.* ## Agent Brief **Category:** enhancement **Summary:** Seed the same skills bundle for every provider; for providers without native skill discovery, append a generated skills index to the context file; enforce the lab-owned context-file-name rule. **Sequencing note:** the "blocked until #75 merges" condition in the issue body is satisfied — #75 landed via PR #81 (ADR-0033). `SeedMeta.ScrubPatterns` was widened there; this issue touches the same struct but a disjoint surface (context file + skills), so no churn conflict remains. **Current behavior:** The embedded skills bundle (single `go:embed` source) is seeded into each provider's declared `SeedMeta.SkillsDir`, but discovery relies entirely on Claude's `.claude/skills` convention. A provider whose CLI reads only AGENTS-style context files (e.g. the Codex provider, #2) receives the bundle on disk but has no way to learn it exists: the generated context file describes the tracker binding, labctl vocabulary, and triage labels, and never mentions the seeded skills. Such an agent gets none of the workflow playbooks (triage, land-pr, to-issues, to-prd, …) that carry AFK quality. **Desired behavior:** 1. **Same bundle for every provider.** Every provider with a non-empty `SkillsDir` gets the identical embedded bundle — no content fork, no per-provider curation list. 2. **`SeedMeta` gains `NativeSkillDiscovery bool`** (claude-code declares `true`). When a provider declares `false` AND has a non-empty `SkillsDir`, the rendered context file gains an appended skills-index section: one line per bundled skill, rendered from that skill's frontmatter (`name` + `description`), pointing at its seeded path — the shape is "when doing X, read `<SkillsDir>/<name>/SKILL.md`". Agents that follow file pointers pull the full playbook on demand; the context file grows about one line per skill, not pages. 3. **Frontmatter parsing fails loudly and early.** Index entries come from each skill's frontmatter, parsed once (embed-time or seeder init). A bundled skill with unparseable frontmatter must fail at build/test time — never silently produce a broken or partial index at seed time. 4. **Hard rule, documented:** `SeedMeta.ContextFileName` must be a lab-owned, never-tracked name — the `.local`-suffixed convention (`CLAUDE.local.md`, `AGENTS.local.md`). Lab must never write a file repositories legitimately track (e.g. Codex's native `AGENTS.md`): a tracked file can't be hidden by `.git/info/exclude`, would be clobbered on re-seed, would show in every diff, and would break incogni. Document this on the `SeedMeta.ContextFileName` field and in an ADR. Making the CLI actually *read* the lab-owned file is the adapter's job in its `SeedWorkspace` (e.g. Codex project config pointing at `AGENTS.local.md`) — a live-verified coupling per the ADR-0008 bar; not this issue's job to build for Codex. 5. **Claude-code seeding stays byte-identical.** Native discovery → no index section → the rendered `CLAUDE.local.md` is unchanged. Pin with the existing golden pattern. **Key interfaces:** - `SeedMeta` (provider package) — new `NativeSkillDiscovery bool` field, with doc comment; claude-code's declaration sets it `true` and its seedmeta pin test covers it. - The context-file rendering path in the seeder — currently renders a generic lab-owned body from an embedded template; gains the conditional index section driven by the provider's `SeedMeta`. - The embedded skills bundle — each `SKILL.md` carries YAML frontmatter with `name` and `description`; the description already embeds "use when…" triggers, so index lines need no extra copy. - `SeedMeta.ContextFileName` doc comment + a new ADR recording the lab-owned-name hard rule and the index design. **Acceptance criteria:** - [ ] A fake provider with `NativeSkillDiscovery: false` and a non-empty `SkillsDir` seeds the full bundle and gets a context file whose index section lists every bundled skill with a correct seeded path (paths reflect THAT provider's declared `SkillsDir`). - [ ] A provider with `NativeSkillDiscovery: true` (claude-code) gets no index section; its seeded worktree — context file included — is byte-identical to today, pinned by golden. - [ ] A provider with an empty `SkillsDir` gets no index section regardless of the flag. - [ ] A bundled skill with malformed/missing frontmatter fails a build-time or test-time check, not seed time. - [ ] The lab-owned-name hard rule is documented on the `ContextFileName` field and in an ADR. - [ ] The bundle remains a single `go:embed` source — no fork, no curation list. **Out of scope:** - The Codex provider itself (#2), including its `SeedWorkspace` wiring that points the CLI at `AGENTS.local.md`. - Conformance-suite enforcement of the naming convention — that's #80. - Any curation/subsetting of which skills a provider receives. - Changes to skill content or frontmatter schema.
Author
Owner

This was generated by AI while landing a PR.

Landing audit — PR #86 (afk/79)

Verdict: PASS. Recommending merge.

Verification signal. No readable CI status via the labctl surface (no forge token here), so nothing external vouches — I ran the repo's Go gate myself against origin/afk/79 (which, since main is an ancestor of afk/79, is the post-merge tree):

  • gofmt -l internal/ — clean
  • go vet ./internal/seeder/... ./internal/provider/... — clean
  • go test on every changed package — all pass (internal/seeder, internal/provider, internal/provider/claudecode), including the byte-identity goldens and the init-panic frontmatter guard cases
  • Full go test ./... — green except internal/tmuxx integration tests, which fail only because the sandbox has no usable tmux server ("session exited immediately"); untouched by this diff and failing identically at pristine HEAD, exactly as the PR body states.

Conventions. Title feat(seeder): … is Conventional Commits ✓. Body carries a valid Closes #79 ✓ (AFK contract satisfied: afk/79#79).

Merge state. main is an ancestor of afk/79 — no divergence, clean merge, no conflict.

Correctness vs. issue #79. Implements every decision: same bundle for every provider (single go:embed, no content fork); SeedMeta.NativeSkillDiscovery bool (claude-code true); index appended in Go only when !NativeSkillDiscovery && SkillsDir != "", so claude-code stays byte-identical (goldens pin it); frontmatter parsed once at package init and fails loudly (panic mirroring the template.Must idiom); lab-owned context-file-name hard rule documented on ContextFileName + ADR-0035. go.mod correctly promotes yaml/v2 indirect→direct. Sequencing ("blocked until #75") is satisfied — #75 landed via #81.

Awaiting explicit free-text merge go-ahead before merging.

> *This was generated by AI while landing a PR.* ## Landing audit — PR #86 (`afk/79`) **Verdict: PASS.** Recommending merge. **Verification signal.** No readable CI status via the labctl surface (no forge token here), so nothing external vouches — I ran the repo's Go gate myself against `origin/afk/79` (which, since `main` is an ancestor of `afk/79`, *is* the post-merge tree): - `gofmt -l internal/` — clean - `go vet ./internal/seeder/... ./internal/provider/...` — clean - `go test` on every changed package — **all pass** (`internal/seeder`, `internal/provider`, `internal/provider/claudecode`), including the byte-identity goldens and the init-panic frontmatter guard cases - Full `go test ./...` — green **except `internal/tmuxx`** integration tests, which fail only because the sandbox has no usable tmux server ("session exited immediately"); untouched by this diff and failing identically at pristine HEAD, exactly as the PR body states. **Conventions.** Title `feat(seeder): …` is Conventional Commits ✓. Body carries a valid `Closes #79` ✓ (AFK contract satisfied: `afk/79` → #79). **Merge state.** `main` is an ancestor of `afk/79` — no divergence, clean merge, no conflict. **Correctness vs. issue #79.** Implements every decision: same bundle for every provider (single `go:embed`, no content fork); `SeedMeta.NativeSkillDiscovery bool` (claude-code `true`); index appended in Go only when `!NativeSkillDiscovery && SkillsDir != ""`, so claude-code stays byte-identical (goldens pin it); frontmatter parsed once at package init and fails loudly (panic mirroring the `template.Must` idiom); lab-owned context-file-name hard rule documented on `ContextFileName` + ADR-0035. `go.mod` correctly promotes `yaml/v2` indirect→direct. Sequencing ("blocked until #75") is satisfied — #75 landed via #81. Awaiting explicit free-text merge go-ahead before merging.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/coding-lab#79
No description provided.