buddy-agent-harness 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/.claude-plugin/plugin.json +12 -0
  2. package/.codex-plugin/plugin.json +16 -0
  3. package/.cursor-plugin/plugin.json +14 -0
  4. package/.plugin/plugin.json +30 -0
  5. package/README.md +37 -0
  6. package/bin/buddy-agent-harness.mjs +7 -0
  7. package/dist/cli.d.mts +5 -0
  8. package/dist/cli.d.mts.map +1 -0
  9. package/dist/cli.mjs +20 -0
  10. package/dist/cli.mjs.map +1 -0
  11. package/dist/index.d.mts +57 -0
  12. package/dist/index.d.mts.map +1 -0
  13. package/dist/index.mjs +2 -0
  14. package/dist/init.command-wxC4cgUc.mjs +203 -0
  15. package/dist/init.command-wxC4cgUc.mjs.map +1 -0
  16. package/package.json +69 -0
  17. package/plugin.json +14 -0
  18. package/skills/init/README.md +29 -0
  19. package/skills/init/SKILL.md +75 -0
  20. package/skills/init/agents/openai.yaml +4 -0
  21. package/skills/init/references/agents-md.md +131 -0
  22. package/skills/init/references/detection.md +34 -0
  23. package/skills/init/references/frontmatter.md +63 -0
  24. package/skills/init/references/harnesses/claude-code.md +51 -0
  25. package/skills/init/references/harnesses/codex.md +13 -0
  26. package/skills/init/references/harnesses/copilot-cli.md +16 -0
  27. package/skills/init/references/harnesses/cursor.md +23 -0
  28. package/skills/init/references/harnesses/devin-desktop.md +19 -0
  29. package/skills/init/references/harnesses/gemini-cli.md +33 -0
  30. package/skills/init/references/standard.md +26 -0
  31. package/src/cli.ts +16 -0
  32. package/src/harness-registry/harness-registry.ts +60 -0
  33. package/src/index.ts +5 -0
  34. package/src/initialize-harnesses/init.command.ts +76 -0
  35. package/src/initialize-harnesses/initialize-harnesses.ts +44 -0
  36. package/src/skill-projection/skill-projection.ts +78 -0
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: init
3
+ description: Use this skill when initializing, adopting, or migrating a repository's agent configuration to the open AGENTS.md and Agent Skills standards, so one canonical source works across Claude Code, Codex, Cursor, Copilot CLI, and other coding-agent harnesses.
4
+ ---
5
+
6
+ # Harness Init
7
+
8
+ Give the repository one canonical agent configuration — a root `AGENTS.md` and an `.agents/` tree — then bridge the harnesses that cannot read it directly.
9
+
10
+ Most of the field already reads `.agents/skills/` natively: Codex, Cursor, GitHub Copilot CLI, and Devin Desktop need no projection at all. Only Claude Code and Gemini CLI read solely their own directory and need a link. Keep that asymmetry in mind — this is a consolidation job, not a copy-everywhere job.
11
+
12
+ `references/standard.md` defines the baseline every repository gets. Read the file below for each harness you are enabling, and only those.
13
+
14
+ | Harness | Skills projection | Instruction bridge | Read |
15
+ | --- | --- | --- | --- |
16
+ | Claude Code | `.claude/skills` | `CLAUDE.md` with `@AGENTS.md` | `references/harnesses/claude-code.md` |
17
+ | Gemini CLI | `.gemini/skills` | `.gemini/settings.json` edit | `references/harnesses/gemini-cli.md` |
18
+ | Codex | none | none | `references/harnesses/codex.md` |
19
+ | Cursor | none | none written; one gap to report | `references/harnesses/cursor.md` |
20
+ | GitHub Copilot CLI | none | none | `references/harnesses/copilot-cli.md` |
21
+ | Devin Desktop | none | none | `references/harnesses/devin-desktop.md` |
22
+
23
+ `init` writes skills projections only. Every instruction bridge above is manual work in Phase 4.
24
+
25
+ Work in five phases. Do not skip Phase 3.
26
+
27
+ ## 1. Survey
28
+
29
+ Locate the Git repository root; the canonical configuration always lives there, including in a monorepo.
30
+
31
+ Inventory both the canonical surface (`AGENTS.md`, `.agents/AGENTS.md`, `.agents/skills/`, and any nested `AGENTS.md` below the root) and every pre-existing harness artifact listed in `references/detection.md`. Read what you find. Write nothing yet.
32
+
33
+ ## 2. Classify
34
+
35
+ Sort each finding into exactly one bucket:
36
+
37
+ - **already canonical** — leave it. Nested `AGENTS.md` files belong here: they are scoped instructions, never content to merge upward.
38
+ - **already linked** — a symlink resolving into `.agents/`; skip it. This is what makes re-runs idempotent.
39
+ - **consolidatable** — harness instruction files whose content belongs in `AGENTS.md`.
40
+ - **portable** — skill and command directories that move into `.agents/skills/`.
41
+ - **canonical-only** — MCP servers, rules, subagents, hooks, output styles. No safe cross-harness mapping exists, so report them and leave them alone.
42
+
43
+ ## 3. Confirm
44
+
45
+ Present the plan before touching anything the user wrote: what will be created, which content moves into `AGENTS.md`, which harness files would become pointers, any frontmatter to be added (show the derived `name` and `description` verbatim), which harnesses will be enabled, and what is being left alone and why.
46
+
47
+ Get explicit approval before any step that deletes, replaces, or rewrites a user-authored file. Creating a missing directory, a missing `AGENTS.md`, or a `CLAUDE.md` bridge stub needs no approval, and neither does the non-material region in `references/agents-md.md` — report these rather than asking.
48
+
49
+ One case does need asking even though it only creates a file: a nested `AGENTS.md` that reverses a root rule, where bridging it hands Claude Code a contradiction it has no rule for resolving. Raise that file, bridge the others, and keep going.
50
+
51
+ ## 4. Apply
52
+
53
+ 1. Scaffold the baseline in `references/standard.md`: `.agents/`, `.agents/skills/`, and a root `AGENTS.md` if absent. Never clobber an existing one. `references/agents-md.md` decides what belongs in that file — a repository with no instruction content still needs one derived and confirmed, not an empty heading.
54
+ 2. Move approved skills and commands to `.agents/skills/<name>/SKILL.md`, preferring `git mv` so history follows. Fix frontmatter per `references/frontmatter.md` — this is where cross-harness portability is won or lost.
55
+ 3. Merge approved instruction content into `AGENTS.md`, preserving the author's wording. Append; do not restructure. Replace a harness file with a pointer only where approved. Content only some tasks need belongs in a skill, not in `AGENTS.md`.
56
+ 4. Run `npx -y buddy-agent-harness init` at the repository root. It links `.agents/skills` into the harnesses that need it and skips those that read it natively. Add harnesses the user names with `--harness codex,gemini-cli`.
57
+ 5. If the command reports a conflict, resolve the named target and retry. Use `--force` only to replace that exact projection; use `--copy` only where links are unavailable — a copy is a snapshot, not a live projection, so say so when you fall back.
58
+ 6. Apply the instruction bridges `init` does not write. Claude Code reads `CLAUDE.md`, not `AGENTS.md` — create a `CLAUDE.md` containing `@AGENTS.md`. Gemini CLI needs `AGENTS.md` added to `context.fileName` in `.gemini/settings.json`. Both are detailed in the matching `references/harnesses/<harness>.md`; apply only the ones you enabled. Where nested `AGENTS.md` files exist, write the same stub in each directory holding one — `references/agents-md.md` covers the one case that stops for approval first.
59
+ 7. If any bridge now exists, write or restore the non-material region in `AGENTS.md` per `references/agents-md.md`, unless the markers are present and empty. Without it, an agent asked to change a skill edits `.claude/skills/<name>/SKILL.md` — which a link resolves back to canonical, but a copy silently forks. Skip this when every enabled harness reads `.agents/skills/` natively; with no bridge there is nothing to warn about.
60
+
61
+ ## 5. Verify and report
62
+
63
+ Confirm each projection resolves into `.agents/skills` and that every migrated `SKILL.md` parses and has valid frontmatter. The command reports the enabled set itself; it records nothing on disk, so there is no file to reconcile against. Report what was created, consolidated, linked, and left canonical-only.
64
+
65
+ `init` is not a formatter. If the repository has one, run it over the written files and say so.
66
+
67
+ ## Rules
68
+
69
+ - Never invent project policy, and never make a material change to a user's `AGENTS.md`. `references/agents-md.md` draws the line: a statement that would stop being true if `init`'s output were removed describes the tool's own artifact and is non-material.
70
+ - Never convert tool settings between formats without a documented mapping. Unmapped settings stay canonical.
71
+ - Symlinks belong in version control. Leave them tracked; do not add them to `.gitignore`.
72
+ - Only `.agents/skills/` is an established convention. Do not invent `.agents/rules/`, `.agents/commands/`, or `.agents/agents/` and present them as standard.
73
+ - Never merge a nested `AGENTS.md` into the root. Merging changes which files it governs.
74
+ - Do not create `AGENTS.local.md`. The standard has no local-override file — two filenames and two meanings are still under discussion upstream. Personal instructions go in `CLAUDE.local.md`, gitignored, and only Claude Code reads them.
75
+ - Local agent configuration only. Do not change workflows, GitHub Actions, repository settings, security scanning, branch rules, or unrelated project files.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Initialize Agent Harnesses"
3
+ short_description: "Link canonical skills across agent harnesses"
4
+ default_prompt: "Use $init to initialize canonical skills in this repository."
@@ -0,0 +1,131 @@
1
+ # Deriving AGENTS.md
2
+
3
+ What to put in `AGENTS.md`, and what to keep out of it.
4
+
5
+ `AGENTS.md` is read on every session, so every line costs context each time. Include a line only when it changes what the agent does.
6
+
7
+ ## What counts as existing
8
+
9
+ Derivation is the greenfield path. Take it only after establishing that no instruction content exists, which is not the same as no instruction file existing.
10
+
11
+ **Existing means authored by a person and carrying content.** A file a previous run wrote is not existing content, and neither is an empty one.
12
+
13
+ | Found | Read it as | Do |
14
+ | --- | --- | --- |
15
+ | root `AGENTS.md` with body content | the canonical file | never rewrite it. Derive nothing. Append only what the user approves, plus the non-material region below |
16
+ | root `AGENTS.md` with nothing but a heading, or empty | a placeholder | treat as absent, derive, and confirm before filling it |
17
+ | `.agents/AGENTS.md` with content | canonical shared instructions, not the root file | leave it alone. Do not derive anything that restates it, and do not merge it upward |
18
+ | a harness instruction file with authored content — `CLAUDE.md`, `.cursorrules`, `.cursor/rules/**`, `.github/copilot-instructions.md`, `.github/instructions/**`, `GEMINI.md`, `.windsurfrules` | existing content | consolidate into `AGENTS.md` preserving the author's wording. Replace the original with a pointer only where approved |
19
+ | `CLAUDE.md` whose whole body is `@AGENTS.md`, or a symlink to `AGENTS.md` | a bridge a previous run created | not content. Skip it — this is what makes re-runs idempotent |
20
+ | a nested `AGENTS.md` — `apps/web/AGENTS.md`, `packages/<name>/AGENTS.md` | canonical instructions scoped to that subtree | leave it alone. Never merge it upward, never derive against it. See below |
21
+ | none of the above | greenfield | derive, then confirm every surviving line |
22
+
23
+ Both can be true at once: a repository can have a `.cursorrules` to consolidate *and* gaps worth deriving. Consolidate first, then derive only what the consolidated content does not already cover.
24
+
25
+ Never make a material change to an existing `AGENTS.md`. Never invent policy in either case.
26
+
27
+ ## Nested AGENTS.md
28
+
29
+ Nested files are part of the format: a subproject may carry its own `AGENTS.md`, and the standard's published rule is that the file closest to the one being edited wins.
30
+
31
+ `init` never consolidates one upward. Merging a nested file into the root would change which files it applies to, turning subtree-scoped instructions into repository-wide ones. Report each nested file, leave it in place.
32
+
33
+ Two things do need doing when Claude Code is enabled.
34
+
35
+ **Bridge every nested file by default.** Claude Code reads `CLAUDE.md`, and the root bridge covers only the root file — instructions in `apps/web/AGENTS.md` reach Codex and Cursor and are invisible to Claude Code until `apps/web/CLAUDE.md` exists. Write one stub per directory holding a nested file, the same way the root stub is written and without asking. A relative `@AGENTS.md` resolves against the file containing the import, so the stub is byte-identical at every level. Report the set; do not enumerate it as a question.
36
+
37
+ **Stop on a file that contradicts the root.** Bridging does not preserve the standard's nearest-wins rule — `references/harnesses/claude-code.md` has the model. A nested file that *adds* facts behaves the same everywhere and is safe to bridge unattended. One that *reverses* a root rule — "this package uses vitest, not jest" — is an override for Codex and a contradiction for Claude Code, so bridging it silently hands Claude two incompatible instructions with no rule for choosing.
38
+
39
+ Read the root file and each nested file before writing stubs. For any nested file that negates, replaces, or narrows a root rule rather than adding to it, ask before bridging that one, and offer the three options: bridge it anyway and accept the ambiguity, reword the nested rule as additive so every harness agrees, or leave it unbridged so Claude Code keeps the root behavior. Bridge the rest without waiting on the answer.
40
+
41
+ Report the comparison, not just the count. Name each nested file and say it was judged additive. This is the only check standing between a missed contradiction and a silently broken bridge, so it has to be reviewable — "wrote 12 stubs" is not.
42
+
43
+ Do not resolve it by rewriting the user's nested file. Which option they want is policy.
44
+
45
+ ## Material and non-material changes
46
+
47
+ The approval rule guards project content. It does not guard `init`'s own bookkeeping, and treating the two the same means the generated-bridge note either never gets written or gets buried in an approval prompt nobody reads.
48
+
49
+ A change is **non-material** when the line describes what `init` created in this repository and asserts nothing about how the project works.
50
+
51
+ The discriminator: **would the statement stop being true if `init`'s output were removed?**
52
+
53
+ | Answer | Reading | Approval |
54
+ | --- | --- | --- |
55
+ | yes — it only holds because `init` ran | describes the tool's own artifact | write it; report it |
56
+ | no — it holds regardless | project content: derived, inferred, or policy | approval, as always |
57
+
58
+ `.claude/skills/ is generated by buddy-agent-harness init` is true only because a bridge exists. `Use pnpm` is true whether or not `init` ever ran. Only the first is non-material.
59
+
60
+ Non-material writes are confined to a managed region so user prose is never touched:
61
+
62
+ ```markdown
63
+ <!-- buddy-agent-harness:begin -->
64
+
65
+ Skills are canonical in `.agents/skills/` — create and edit them there.
66
+ `.claude/skills/` is a generated bridge to it; never write to it directly.
67
+ `CLAUDE.md` is a generated pointer to this file. Shared instructions belong
68
+ here; keep only Claude-specific notes there.
69
+
70
+ <!-- buddy-agent-harness:end -->
71
+ ```
72
+
73
+ Name the bridges this repository actually has, not the example above. Drop the `CLAUDE.md` line where no stub was written, and the skills line where no skills bridge exists — a warning about a path that does not exist teaches an agent to distrust the rest.
74
+
75
+ - **Append-only.** Place the region at the end. Never reorder or remove what the user wrote.
76
+ - **Idempotent.** A re-run rewrites the region in place. Two regions is a bug.
77
+ - **Never silent.** Report the write, the same as any other change.
78
+ - **Self-repairing.** A missing region is restored on the next run. Absence is not consent: the region is far more often lost to a rewrite, a merge resolution, or a pass trimming the file toward the line limit than removed on purpose — and what it protects is exactly what stops a copied bridge from forking.
79
+ - **Emptying it opts out.** Markers with nothing between them are a deliberate choice; leave them empty. Deleting the markers is not, and gets the region back. This keeps the opt-out in the file it governs, where the person who wants it can see it.
80
+
81
+ ```markdown
82
+ <!-- buddy-agent-harness:begin -->
83
+ <!-- buddy-agent-harness:end -->
84
+ ```
85
+
86
+ Nothing else qualifies. A fact read out of the codebase is material even when it feels obvious, and a policy stays material even when `init` is confident about it.
87
+
88
+ ## What earns a line
89
+
90
+ Ask: **would the agent get this wrong, or spend tokens finding it?**
91
+
92
+ | Keep | Cut |
93
+ | --- | --- |
94
+ | a constraint that fails the build in a non-obvious way | anything one cheap read away — `package.json` scripts, `tsconfig.json`, the file tree |
95
+ | an ordered workflow with a step nobody would guess | anything a formatter, linter, or type checker already enforces |
96
+ | a decision table resolving a real ambiguity between two plausible paths | anything the model already defaults to, such as "ask before deleting files" |
97
+ | a short snippet from real code that shows the house pattern | architecture tours, history, and rationale |
98
+
99
+ Pair every "don't" with a "do". A file of unpaired prohibitions makes an agent explore more and finish less.
100
+
101
+ "We use TypeScript" in a repository full of `.ts` files is the shape to avoid. "Every exported binding needs an explicit type annotation or `typecheck` fails" is the shape to keep.
102
+
103
+ ## Derive
104
+
105
+ 1. Read `package.json` (scripts, `engines`), the TypeScript, test, and lint configs, CI workflows, release configuration, and any existing `README.md`.
106
+ 2. List each candidate fact with the file it came from. A fact with no source is invention — drop it.
107
+ 3. Apply the test above. Most candidates fail it. Cut them.
108
+ 4. Show the user every surviving line beside its source, and get approval.
109
+ 5. Write only what was approved.
110
+
111
+ If nothing survives, write the heading and a one-line statement of what the repository is, then stop. Do not pad to look complete.
112
+
113
+ ## Push the rest down
114
+
115
+ | Content | Home |
116
+ | --- | --- |
117
+ | a procedure, or depth about one domain | a skill in `.agents/skills/` — only its `name` and `description` stay in context, and the body loads when the description matches |
118
+ | payload a skill needs only sometimes | `references/` beside that `SKILL.md`, loaded on demand |
119
+ | rationale, background, evidence | the documentation site, not agent context |
120
+
121
+ A section of `AGENTS.md` that only some tasks need is a skill that has not been extracted yet.
122
+
123
+ ## Limits
124
+
125
+ - Target under 150 lines. Past that, added lines cost more than they return.
126
+ - State facts, not instructions, unless the user authored the instruction.
127
+ - Derivable is not the same as worth including — a discoverable fact restated here goes stale the first time someone moves the file.
128
+
129
+ ## CLAUDE.md
130
+
131
+ Claude Code does not read `AGENTS.md`. Create `CLAUDE.md` containing `@AGENTS.md` and nothing else, unless the user adds Claude-specific notes below the import. Never copy `AGENTS.md` content into it — two homes for one fact is how they diverge.
@@ -0,0 +1,34 @@
1
+ # Detection
2
+
3
+ What to look for during the survey, and where each finding belongs.
4
+
5
+ | Class | Look for | Disposition |
6
+ | --- | --- | --- |
7
+ | Instructions | `AGENTS.md`, `.agents/AGENTS.md`, `CLAUDE.md`, `.cursorrules`, `.cursor/rules/**`, `.github/copilot-instructions.md`, `.github/instructions/**`, `GEMINI.md`, `.windsurfrules` | consolidate into `AGENTS.md`; confirm before replacing anything |
8
+ | Nested instructions | `**/AGENTS.md` below the root, and any `**/CLAUDE.md` beside one | canonical and scoped — report, never merge upward. Bridging is per directory and per approval; see `agents-md.md` |
9
+ | Skills | `.claude/skills/`, `.cursor/skills/`, `.codex/skills/`, `.github/skills/`, `.windsurf/skills/`, `.gemini/skills/` | move to `.agents/skills/`, fix frontmatter, then link back |
10
+ | Commands | `.claude/commands/*.md`, `.cursor/commands/*.md` | move to `.agents/skills/<name>/SKILL.md`. Claude Code has merged commands into skills, so this follows the harness rather than fighting it |
11
+ | Subagents | `.claude/agents/` | canonical-only — no cross-harness format exists. Report; leave in place |
12
+ | Rules | `.cursor/rules/**.mdc`, `.claude/rules/`, `.windsurf/rules/` | canonical-only — `.mdc` and `.md` are not interchangeable, and path-scoping syntax differs. Report |
13
+ | MCP servers | `.mcp.json`, `.cursor/mcp.json`, `.vscode/mcp.json`, `.claude/settings.json` | canonical-only. Report; never convert between formats |
14
+ | Hooks, LSP, output styles | hook blocks in settings files, `.claude/output-styles/` | canonical-only. Hook event names differ by case across harnesses, so no safe projection exists. Report |
15
+
16
+ For every entry, record which of three states it is in:
17
+
18
+ - a real file or directory the user authored,
19
+ - a symlink already resolving into `.agents/` — a previous run, skip it,
20
+ - something occupying a projection target that is neither — a conflict to surface in Phase 3.
21
+
22
+ ## Choosing harnesses
23
+
24
+ The enabled set is the union of three sources: Claude Code and Cursor unconditionally, any harness whose detection directory already exists, and any the user names with `--harness`. `init` detects the second group itself — you do not need to pass it.
25
+
26
+ There is no way to disable a harness. Never offer the user a choice that excludes Claude Code or Cursor; `init` enables them whatever the answer, so the question would be a fiction.
27
+
28
+ Enabling a harness is not the same as writing files for it. Most enabled harnesses read `.agents/skills/` natively and receive nothing — see the table in `SKILL.md` for which ones get a projection. Report both facts, because only the projections are a real diff.
29
+
30
+ `init` records nothing on disk about a run. The enabled set is recomputed from detection every time, so a stored copy could only ever go stale or contradict what is actually there. The command's own output is the report — read it, do not look for a file.
31
+
32
+ Antigravity and VS Code are native readers and are not registry entries — never write anything for them. Do not treat a `.vscode/` directory as a signal that any harness needs configuring.
33
+
34
+ Detecting a harness directory means the repository has configuration to reconcile. It does not by itself mean the user wants that harness maintained — say which harnesses you are enabling and why, and let the user correct the part that is actually variable.
@@ -0,0 +1,63 @@
1
+ # Frontmatter for cross-harness skills
2
+
3
+ Linking a skill into every harness is easy. Making it *behave* the same in every harness is not. Each harness parses the frontmatter fields it knows and silently drops the rest.
4
+
5
+ ## Required, everywhere
6
+
7
+ ```yaml
8
+ ---
9
+ name: release-checklist
10
+ description: Runs the release checklist. Use when cutting a release or publishing a package version.
11
+ ---
12
+ ```
13
+
14
+ - `name` — 1–64 characters, lowercase letters, digits, and hyphens. No leading, trailing, or consecutive hyphens. **It must match the parent directory name.**
15
+ - `description` — 1–1024 characters. Say what the skill does *and* when to use it; this is the only text most harnesses see when deciding whether to load it.
16
+
17
+ ## Two rules that decide whether a skill loads at all
18
+
19
+ Harnesses are told to validate leniently, but the leniency is asymmetric:
20
+
21
+ | Problem | Result |
22
+ | --- | --- |
23
+ | `name` does not match the directory | warning, still loads |
24
+ | `name` longer than 64 characters | warning, still loads |
25
+ | `description` missing or empty | **skill is skipped** |
26
+ | YAML fails to parse | **skill is skipped** |
27
+
28
+ So the two failures that actually cost you a skill are a missing description and broken YAML. The most common cause of broken YAML is an unquoted colon:
29
+
30
+ ```yaml
31
+ # Breaks on strict parsers
32
+ description: Use this skill when: the user asks about PDFs
33
+
34
+ # Correct
35
+ description: "Use this skill when: the user asks about PDFs"
36
+ ```
37
+
38
+ **Quote any description containing a colon.** When migrating existing skills, check this first.
39
+
40
+ Enforcing `name` == directory name is also worth doing even though it is only a warning: Claude Code ignores `name` for command resolution and uses the directory name, so matching them removes the discrepancy entirely.
41
+
42
+ ## Which harness understands which field
43
+
44
+ | Field | Recognized by |
45
+ | --- | --- |
46
+ | `name`, `description` | all |
47
+ | `license`, `metadata`, `compatibility` | accepted broadly, largely ignored |
48
+ | `allowed-tools` | most; **not** Kiro CLI or Zencoder |
49
+ | `context: fork`, `agent:` | Claude Code only |
50
+ | `disable-model-invocation` | Claude Code, Cursor |
51
+ | `paths`, legacy `globs` | Cursor only |
52
+ | `model` | Copilot CLI only |
53
+ | hook configuration | Claude Code, Cline, Kiro CLI |
54
+
55
+ Codex additionally reads an `agents/openai.yaml` **sidecar file** beside `SKILL.md` — not frontmatter. See `harnesses/codex.md`; never add one unprompted.
56
+
57
+ ## What follows from that
58
+
59
+ Claude Code has the largest field surface, so a skill authored for it and shared everywhere carries fields the other harnesses parse and discard. That is a small, unavoidable context cost — accept it rather than maintaining divergent copies.
60
+
61
+ The cost that is *not* acceptable is silent behavior loss. **Anything that must hold on every harness has to be stated in the Markdown body, not only in a harness-specific field**, because the body is the one part every harness reads. Treat harness-specific frontmatter as an optimization layered on top of instructions that already work without it.
62
+
63
+ When adding frontmatter to a skill that lacks it, derive `name` from the directory and `description` from the first heading or opening paragraph, then show the user the derived values for approval. If nothing usable can be derived, ask — never write a placeholder description, because a vague description is worse than the warning it silences.
@@ -0,0 +1,51 @@
1
+ # Claude Code
2
+
3
+ Reads neither `.agents/skills/` nor `AGENTS.md`. **Both bridges are required.**
4
+
5
+ ## Bridge 1 — skills
6
+
7
+ `buddy-agent-harness init` creates this:
8
+
9
+ ```
10
+ .claude/skills → ../.agents/skills
11
+ ```
12
+
13
+ If the directory-level link ever fails, fall back to documented per-skill symlinks (`.claude/skills/<name>` → the canonical skill directory).
14
+
15
+ ## Bridge 2 — instructions
16
+
17
+ `init` does **not** do this. Create by hand:
18
+
19
+ ```markdown
20
+ <!-- CLAUDE.md -->
21
+ @AGENTS.md
22
+ ```
23
+
24
+ Claude-specific notes may follow below the import.
25
+
26
+ `ln -s AGENTS.md CLAUDE.md` also works, but **prefer the import** — on Windows a symlink needs Administrator or Developer Mode.
27
+
28
+ ## Nested instruction files
29
+
30
+ Claude Code concatenates every `CLAUDE.md` from the filesystem root down to the working directory; the nearest is read last but does not win. The `AGENTS.md` standard says the nearest file wins. Conflicts are undefined here — the docs say Claude may pick one arbitrarily.
31
+
32
+ So a nested `AGENTS.md` needs its own `CLAUDE.md` stub to be visible at all, and gets additive rather than override semantics once it has one. `references/agents-md.md` has the rule; do not bridge a nested file that reverses a root instruction without saying what will happen.
33
+
34
+ ## Frontmatter
35
+
36
+ Claude Code recognizes the most fields (`context: fork`, `agent:`, `disable-model-invocation`, `once`, `${CLAUDE_SKILL_DIR}`). Other harnesses drop them silently.
37
+
38
+ - Restate anything load-bearing in the Markdown body.
39
+ - **Enforce `name` equal to the directory name.** Claude Code treats `name` as a display label only and resolves the command from the directory name; matching them removes the discrepancy.
40
+
41
+ ## Leave alone — canonical-only
42
+
43
+ Report these and do not convert them:
44
+
45
+ - `.claude/agents/` (subagents), `.claude/rules/`, `.claude/output-styles/`
46
+ - hook blocks in `.claude/settings.json` — event names differ by case across harnesses
47
+ - MCP server definitions
48
+
49
+ ## Commands
50
+
51
+ `.claude/commands/*.md` are **portable** — migrate to `.agents/skills/<name>/SKILL.md`. Claude Code has merged commands into skills, so this follows the harness rather than fighting it.
@@ -0,0 +1,13 @@
1
+ # Codex
2
+
3
+ **Write nothing.** Codex reads `.agents/skills/` and `AGENTS.md` natively, and walks up to the repository root on its own.
4
+
5
+ - Do not create `.codex/skills` — it is redundant.
6
+ - Detection directory is `.codex`. Its presence enables Codex in the config record and changes nothing on disk.
7
+ - Apply `frontmatter.md` as normal. Codex requires `name` and `description`, and rejects unquoted colons like every other harness.
8
+
9
+ ## Optional sidecar
10
+
11
+ Codex alone reads `agents/openai.yaml` inside a skill directory (display name, icons, brand color, `allow_implicit_invocation`, MCP dependencies).
12
+
13
+ Never add one unprompted. If the user asks for it, restate anything load-bearing in the `SKILL.md` body — no other harness reads the sidecar.
@@ -0,0 +1,16 @@
1
+ # GitHub Copilot CLI
2
+
3
+ **Write nothing.** Copilot CLI reads `.agents/skills/` and `AGENTS.md` natively.
4
+
5
+ - Detection directory is `.github/skills` — **not** `.github`. A repository with `.github/` but no `.github/skills/` does not enable Copilot CLI by detection.
6
+ - Copilot also reads `.claude/skills`, `.github/skills`, `CLAUDE.md`, and `GEMINI.md`. Do not create any of them for Copilot's benefit.
7
+
8
+ ## Instruction consolidation
9
+
10
+ `.github/copilot-instructions.md` and `.github/instructions/**` are **consolidatable** — move their content into `AGENTS.md` and leave a pointer, with approval.
11
+
12
+ This is safe here because Copilot has no mode that reads only the harness file. Do not assume the same for Cursor.
13
+
14
+ ## Frontmatter
15
+
16
+ `model` is Copilot-only; `license` and `allowed-tools` are accepted. Keep anything load-bearing in the body — see `frontmatter.md`.
@@ -0,0 +1,23 @@
1
+ # Cursor
2
+
3
+ **Write no skills projection.** Cursor reads `.agents/skills/` natively, plus `.cursor/skills/` and compat reads of `.claude/skills/` and `.codex/skills/`.
4
+
5
+ Cursor is enabled unconditionally alongside Claude Code, so it appears in the config record whether or not `.cursor/` exists. That record changes nothing on disk.
6
+
7
+ ## Report the instruction gap
8
+
9
+ Cursor reads `AGENTS.md` in **Agent mode only**. Chat and Composer read `.cursorrules` and `.cursor/rules/*.mdc` instead.
10
+
11
+ Tell the user: a repository that consolidates into `AGENTS.md` keeps its instructions in Agent mode and loses them in Chat and Composer.
12
+
13
+ **Report this as contested.** It is secondary-sourced, not confirmed from Cursor's own documentation. Do not state it as settled fact.
14
+
15
+ ## Do not
16
+
17
+ - **Do not generate `.cursor/rules/*.mdc` from `AGENTS.md`.** Rules are canonical-only — `.mdc` and `.md` are not interchangeable and path-scoping has no `AGENTS.md` equivalent.
18
+ - **Do not delete or rewrite `.cursorrules` or `.cursor/rules/**` on the assumption that `AGENTS.md` covers them.** In Chat and Composer it does not.
19
+ - Do not assert whether Cursor's `.agents/skills` discovery recurses into nested subdirectories. It is untested.
20
+
21
+ ## Frontmatter
22
+
23
+ `paths`, `disable-model-invocation`, and legacy `globs` are Cursor-recognized. Other harnesses drop them — keep load-bearing behavior in the body, per `frontmatter.md`.
@@ -0,0 +1,19 @@
1
+ # Devin Desktop (formerly Windsurf)
2
+
3
+ **Write nothing.** Devin Desktop reads `.agents/skills/` natively — it is the recommended path of the nine it scans.
4
+
5
+ Windsurf was rebranded to Devin Desktop on 2026-06-02. Use `devin-desktop`; `windsurf` still works as a deprecated alias.
6
+
7
+ ## The alias
8
+
9
+ `--harness windsurf` enables a legacy entry that still creates `.windsurf/skills → ../.agents/skills`. Devin also scans `.windsurf/skills/`, so the projection works — it is redundant, not broken.
10
+
11
+ - For a new repository, use `--harness devin-desktop` and write nothing.
12
+ - If a repository already has a `.windsurf/skills` link, leave it. Report it as legacy compatibility, and mention the rename.
13
+ - `init` reports any enabled deprecated name in its `deprecated` result field. Surface that to the user.
14
+
15
+ ## Instructions
16
+
17
+ Whether Devin Desktop reads `AGENTS.md` is **not established**. Do not assert it either way, and do not write an instruction bridge for it.
18
+
19
+ `.windsurfrules` and `.windsurf/rules/` are **canonical-only**. Report them and leave them in place.
@@ -0,0 +1,33 @@
1
+ # Gemini CLI
2
+
3
+ Reads `.agents/skills` at **user scope only**. At project scope it reads `.gemini/skills/` and nothing else, so **both bridges are required**.
4
+
5
+ Do not enable Gemini CLI speculatively — unlike Cursor, enabling it writes a real directory and symlink. Enable it only via `--harness gemini-cli` or a pre-existing `.gemini/` directory.
6
+
7
+ ## Bridge 1 — skills
8
+
9
+ `buddy-agent-harness init` creates this when `gemini-cli` is enabled:
10
+
11
+ ```
12
+ .gemini/skills → ../.agents/skills
13
+ ```
14
+
15
+ ## Bridge 2 — instructions
16
+
17
+ `init` does **not** do this, and it cannot be a link. Add `AGENTS.md` to `context.fileName` in `.gemini/settings.json`:
18
+
19
+ ```json
20
+ {
21
+ "context": {
22
+ "fileName": ["AGENTS.md", "GEMINI.md"]
23
+ }
24
+ }
25
+ ```
26
+
27
+ `AGENTS.md` is not in the default list. **Without this edit Gemini CLI gets no instructions at all** from a repository that consolidated into `AGENTS.md`.
28
+
29
+ When the file already exists:
30
+
31
+ - Get approval first — it is user-authored.
32
+ - Add to the array; do not replace it. Preserve surrounding settings.
33
+ - Keep `GEMINI.md` in the list if the repository still has one.
@@ -0,0 +1,26 @@
1
+ # The standard baseline
2
+
3
+ What to create in every repository, before any harness-specific work.
4
+
5
+ ## Create
6
+
7
+ | Path | When |
8
+ | --- | --- |
9
+ | `AGENTS.md` at the repository root | if absent — never clobber an existing one; contents per `agents-md.md` |
10
+ | `.agents/` | if absent |
11
+ | `.agents/skills/<name>/SKILL.md` | one directory per skill; frontmatter per `frontmatter.md` |
12
+
13
+ Optional, only when the repository already has content for them: `.agents/AGENTS.md` for shared behavior, and a skill's `scripts/`, `references/`, `assets/` subdirectories.
14
+
15
+ ## Constraints
16
+
17
+ - **Do not create `.agents/rules/`, `.agents/commands/`, or `.agents/agents/`.** Only `.agents/skills/` is read by any harness. Creating the others and calling them standard is invention.
18
+ - **Do not invent policy for `AGENTS.md`.** Write only content the user authored or approved. Deriving facts from the repository is not invention; asserting rules nobody agreed to is. See `agents-md.md`.
19
+ - Call `.agents/` a convention, not a standard, in any user-facing output.
20
+ - `AGENTS.md` has no schema and no required sections. Do not impose one.
21
+
22
+ ## Next
23
+
24
+ Three harnesses need nothing beyond this baseline. `SKILL.md` has the table of which need augmentation; read only the matching `harnesses/<harness>.md`.
25
+
26
+ Background on where these formats come from: [Open Standards](https://repobuddy.github.io/buddy-agent-harness/agent-configuration/open-standards/).
package/src/cli.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { cli } from 'clibuilder'
2
+ import { initCommand } from './initialize-harnesses/init.command.ts'
3
+
4
+ export async function main(): Promise<void> {
5
+ const app = cli({
6
+ name: 'buddy-agent-harness',
7
+ version: '0.1.0',
8
+ description: 'Initialize agent harness skill compatibility in consumer repositories.',
9
+ })
10
+ try {
11
+ await app.command(initCommand).parse(process.argv)
12
+ } catch (error) {
13
+ process.stdout.write(`error: ${error instanceof Error ? error.message : 'Invalid command.'}\n`)
14
+ process.exitCode = 2
15
+ }
16
+ }
@@ -0,0 +1,60 @@
1
+ import { lstatSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+
4
+ export type HarnessName =
5
+ | 'claude-code'
6
+ | 'cursor'
7
+ | 'codex'
8
+ | 'copilot-cli'
9
+ | 'gemini-cli'
10
+ | 'devin-desktop'
11
+ | 'windsurf'
12
+
13
+ /**
14
+ * `skillsDirectory` is the projection target a harness needs to see `.agents/skills`.
15
+ * A harness that reads `.agents/skills` natively has none, and is never projected into.
16
+ */
17
+ export type Harness = {
18
+ name: HarnessName
19
+ detect: string
20
+ skillsDirectory?: string
21
+ /** Set when this name has been superseded; the value is the name that replaces it. */
22
+ deprecated?: HarnessName
23
+ }
24
+
25
+ /**
26
+ * Codex, Cursor, Copilot CLI, and Devin Desktop read `.agents/skills` directly, so they need no
27
+ * projection. Only Claude Code and Gemini CLI read solely their own directory.
28
+ *
29
+ * `windsurf` is the former name of Devin Desktop, rebranded 2026-06-02. It is retained as a
30
+ * deprecated alias: Devin still scans the legacy `.windsurf/skills` path, so its projection keeps
31
+ * working, but new repositories should enable `devin-desktop` and have nothing written for them.
32
+ *
33
+ * See `.research/agentic-configuration-standards/` for the per-harness sources.
34
+ */
35
+ export const harnessRegistry: readonly Harness[] = [
36
+ { name: 'claude-code', detect: '.claude', skillsDirectory: '.claude/skills' },
37
+ { name: 'cursor', detect: '.cursor' },
38
+ { name: 'codex', detect: '.codex' },
39
+ { name: 'copilot-cli', detect: '.github/skills' },
40
+ { name: 'gemini-cli', detect: '.gemini', skillsDirectory: '.gemini/skills' },
41
+ { name: 'devin-desktop', detect: '.devin' },
42
+ { name: 'windsurf', detect: '.windsurf', skillsDirectory: '.windsurf/skills', deprecated: 'devin-desktop' },
43
+ ]
44
+
45
+ /** Enabled whether or not the repository already contains their directories. */
46
+ const defaultHarnesses: readonly HarnessName[] = ['claude-code', 'cursor']
47
+
48
+ function directoryExists(path: string): boolean {
49
+ try {
50
+ return lstatSync(path).isDirectory()
51
+ } catch {
52
+ return false
53
+ }
54
+ }
55
+
56
+ /** The default harnesses, plus the preferred ones, plus every harness whose directory is present. */
57
+ export function selectHarnesses(root: string, preferred: readonly HarnessName[]): Harness[] {
58
+ const enabled = new Set<HarnessName>([...defaultHarnesses, ...preferred])
59
+ return harnessRegistry.filter((harness) => enabled.has(harness.name) || directoryExists(join(root, harness.detect)))
60
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export type { HarnessName } from './harness-registry/harness-registry.ts'
2
+ export { harnessRegistry } from './harness-registry/harness-registry.ts'
3
+ export { activate, harnessCommand, initCommand } from './initialize-harnesses/init.command.ts'
4
+ export type { InitializeOptions, InitializeResult } from './initialize-harnesses/initialize-harnesses.ts'
5
+ export { initializeHarnesses } from './initialize-harnesses/initialize-harnesses.ts'