Skip to content

Commit 3b533c3

Browse files
authored
feat: multi-agent support — harness selection, instructions, skills & hooks (v0.16.0) (#9)
* feat: multi-agent instructions via AGENTS.md canonical source (phase 2a) Lifts the Claude-only coupling (ADR-004): project instructions are written once to a canonical AGENTS.md and shared across agents via an extensible adapter registry. (ADR-016) - src/setup/agents.sh: registry (claude, codex, opencode, gemini, copilot, cursor). Codex/opencode/Copilot/Cursor read AGENTS.md natively; Claude (CLAUDE.md) and Gemini (GEMINI.md) get thin @AGENTS.md import stubs. - templates: AGENTS.md now canonical; CLAUDE.md/GEMINI.md are import stubs. - init: detect installed agents and emit matching files; report detection. - update: content-preserving migration of legacy CLAUDE.md -> AGENTS.md, plus GEMINI.md stub when Gemini CLI is present. - --version --json/--features: multiagent:true + agents list from registry. - doctor: AGENTS.md-aware instructions check + detected-agents line. - docs: README multi-agent section + structure tree. Commands/skills stay Claude-native; per-agent ports + ADR-005 v2.0 ({{ASK}}) are a later phase. * fix: unambiguous seed-mapping separator + doc/wording fixes (CodeRabbit) - init.sh/agents.sh: the "url:target" mapping was split on the FIRST colon, which broke on the URL scheme (https:) — url became "https", breaking every init download. Switched the separator to " |" (cannot appear in a URL or filename) and split with ${mapping%|*} / ${mapping##*|}. Unambiguous by construction, no reliance on "targets never contain a colon". - README: CLAUDE.md is always added (not only when Claude is detected). - ADR-016: capitalize "GitHub/spec-kit". * feat: harness selection + multi-agent skills & hooks (ADR-017) Only emit files for the chosen harness(es) — no .claude/ junk for a Codex-only user. init resolves agents interactively (default = detected), via --agents claude,codex, or --yes (all detected); gates all .claude/ + CLAUDE.md on Claude being selected. - skills: shared SKILL.md emitted to .agents/skills (Codex/opencode/Gemini/ Copilot/Cursor) mirrored to .claude/skills (Claude) via symlink+copy fallback. - hooks: notification wired per selected harness in native format (.codex, .gemini, .github/hooks, .cursor, opencode JS plugin) pointing at a shared arg-driven notify.sh; Claude keeps the tool-failure guard. - registry: resolve_selected_agents, link_or_copy_dir, setup_agent_hooks. - update: mirror skills to .agents/skills when a non-Claude agent is present. - --version --json: + skills:true; help/completion document --agents. - ADR-016 corrected (all 6 agents have structured-question tools + hooks); new ADR-017 (harness selection, skills, hooks, scope limits). Commands stay Claude-native (next phase). Non-Claude hook configs are artifact-validated (JSON/TOML/JS) but best-effort, not runtime-tested per agent. * docs(adr): ADR-018 — command portability & invocation modes (phase 2b plan) Records the skill-vs-command classification (knowledge=skill, action=command): code-review + deep-context promoted to skill mode; the 9 side-effecting/ deliberate commands stay explicit-only; fix-bug stays command. Documents the portable {{ASK}} that renders to each agent's native structured-question tool (satisfies ADR-005 cross-agent, no free-text degrade). Status: Proposed. Fixes stale "ADR-005 v2.0" references in ADR-016/017 and CHANGELOG — ADR-005 is already v2.0 (clarity assessment); the {{ASK}} work is ADR-018.
1 parent c805568 commit 3b533c3

17 files changed

Lines changed: 1360 additions & 323 deletions
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# ADR-016: Multi-Agent Harness via Adapter Registry
2+
3+
**Status:** Accepted
4+
**Date:** 2026-06-02
5+
**Version:** 1.0
6+
**Deciders:** Nicholas (Gocase)
7+
8+
## Context
9+
10+
dotcontext was built Claude-Code-first (ADR-004): a project-root `CLAUDE.md` plus `.claude/`
11+
commands, agents, and skills. ADR-004 explicitly accepted "tightly coupled to Claude Code
12+
(won't work with other AI tools)" as a tradeoff.
13+
14+
The toolkit's value — the curated project instructions, decisions, and skills — is agent-agnostic.
15+
Coding agents have converged on a near-common convention: the **AGENTS.md** open standard
16+
(Linux-Foundation-stewarded, plain Markdown, nearest-file-wins). GitHub's spec-kit ships per-agent
17+
integrations; we want the same reach without abandoning the Claude-first ergonomics.
18+
19+
Research (2026) on where each agent reads its project instruction/memory file:
20+
21+
| Agent | Instructions file | Reads `AGENTS.md` natively? |
22+
|-------|-------------------|-----------------------------|
23+
| Claude Code | `CLAUDE.md` | No (but supports `@import`) |
24+
| OpenAI Codex | `AGENTS.md` | Yes (originator) |
25+
| opencode | `AGENTS.md` (also reads `CLAUDE.md`) | Yes |
26+
| GitHub Copilot | `AGENTS.md` / `.github/copilot-instructions.md` | Yes (since Aug 2025) |
27+
| Cursor (IDE + `cursor-agent` CLI) | `AGENTS.md` / `.cursor/rules/*.mdc` | Yes |
28+
| Gemini CLI | `GEMINI.md` | No (but supports `@import`; configurable) |
29+
30+
## Decision
31+
32+
### 1. Extensible adapter registry
33+
34+
A registry (`src/setup/agents.sh`) declares each supported agent as a small record: `id`,
35+
display name, detection command (`command -v`), instructions filename, and emit mode. Adding an
36+
agent is one entry — nothing else in the toolkit hard-codes an agent. Initial set:
37+
`claude, codex, opencode, gemini, copilot, cursor` (the Cursor entry covers both the IDE and the
38+
`cursor-agent` CLI).
39+
40+
### 2. `AGENTS.md` is the single canonical source of project instructions
41+
42+
The real instruction content lives in **`AGENTS.md` at the repo root**. This natively covers
43+
**codex, opencode, copilot, and cursor** with zero extra files. The two agents that don't read
44+
`AGENTS.md` get thin **import stubs** pointing at it (both support `@import`):
45+
46+
- `CLAUDE.md``@AGENTS.md` (for Claude Code)
47+
- `GEMINI.md``@AGENTS.md` (for Gemini CLI)
48+
49+
Single source, no duplication, no drift; each editor edits `AGENTS.md`.
50+
51+
### 3. Interactive agent detection (no new CLI flags)
52+
53+
`dotcontext init` detects which agent CLIs are installed and emits the matching instruction files;
54+
in interactive mode it confirms the selection. `--yes` sets up all detected agents (falling back
55+
to Claude when none are detected). This honors the minimal-CLI constraint (ADR-007) — no
56+
`--agent` flag, the flow lives inside `init`.
57+
58+
### 4. Safe migration for existing projects
59+
60+
`dotcontext update` migrates legacy single-file projects: when a content-bearing `CLAUDE.md`
61+
exists and `AGENTS.md` does not, it offers to make `AGENTS.md` canonical (move the content) and
62+
leave `CLAUDE.md` as an `@AGENTS.md` stub. This is content-preserving and behavior-preserving for
63+
Claude (it still reads the same content via the import).
64+
65+
### 5. Scope of this decision (phase 2a)
66+
67+
This ADR covers the **instructions file** only. Skills and hooks portability is addressed in
68+
**ADR-017**; porting slash commands to each agent's native format is deferred to a later phase.
69+
70+
> **Correction (2026-06-03):** an earlier draft of this ADR claimed "Codex/Gemini/etc. have no
71+
> structured-question API," used to justify a degraded `{{ASK}}` fallback. That premise is **false**.
72+
> Current research (see ADR-017) confirms **all six agents ship a model-callable structured-question
73+
> tool** (Claude `AskUserQuestion`, Codex `request_user_input`, opencode `question`, Gemini
74+
> `ask_user`, Copilot `ask_user`, Cursor `cursor/ask_question`) **and** lifecycle hooks. So command
75+
> portability (ADR-018) renders `{{ASK}}` to each agent's **native** question tool — it
76+
> does not degrade to free text. The `--version --json` handshake (ADR-015) flips `multiagent: true`
77+
> and lists supported `agents` as adapters land.
78+
79+
## Consequences
80+
81+
### Positive
82+
- The toolkit works across Claude, Codex, opencode, Copilot, Cursor, and Gemini from one source.
83+
- Adding a new agent is a single registry entry.
84+
- Existing Claude-only projects keep working and migrate safely.
85+
86+
### Negative
87+
- A root `AGENTS.md` plus possible `CLAUDE.md`/`GEMINI.md` stubs is slightly more surface than a
88+
lone `CLAUDE.md`.
89+
- Import resolution depends on each agent honoring `@import`; agents that don't are covered by
90+
reading `AGENTS.md` directly, but a future agent that does neither would need a real copy.
91+
- Command/skill portability is **not** solved here (phase 2b).
92+
93+
## Alternatives Considered
94+
95+
1. **Keep `CLAUDE.md` canonical, point `AGENTS.md` at it via `@import`** — rejected: Codex/Copilot/
96+
Cursor don't resolve `@import`, so they'd see a literal pointer instead of content.
97+
2. **Symlinks (`AGENTS.md``CLAUDE.md`)** — rejected: fragile on Windows/WSL (ADR cross-platform rule) and in git.
98+
3. **Full content copies per agent** — rejected: guarantees drift across files.
99+
4. **Per-agent zip artifacts (old spec-kit model)** — rejected: doesn't fit the single-bash-executable + curl distribution (ADR-001/002).
100+
101+
## History
102+
103+
| Version | Date | Changes |
104+
|---------|------|---------|
105+
| 1.0 | 2026-06-02 | Initial decision (phase 2a: instructions file across agents) |
106+
107+
## Related
108+
- ADR-004: Claude Code integration (this extends it beyond Claude)
109+
- ADR-005: Mandatory AskUserQuestion (will get a v2.0 for command portability in phase 2b)
110+
- ADR-007: CLI simplification (interactive detection, no new flags)
111+
- ADR-015: Capability discovery & update awareness (the handshake this populates)
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# ADR-017: Harness Selection, Skills & Hooks Portability
2+
3+
**Status:** Accepted
4+
**Date:** 2026-06-03
5+
**Version:** 1.0
6+
**Deciders:** Nicholas (Gocase)
7+
8+
## Context
9+
10+
ADR-016 made the project-instructions file (`AGENTS.md`) multi-agent. Two follow-ups remained:
11+
**skills** and **hooks**. Research (June 2026) overturned an earlier assumption: **all six target
12+
agents now implement the open Agent Skills (`SKILL.md`) standard, ship lifecycle hooks, and expose a
13+
model-callable structured-question tool** (so the `AskUserQuestion` premise in ADR-016's first draft
14+
was wrong — corrected there).
15+
16+
Skills directory coverage:
17+
18+
| Reads `.agents/skills/` | Reads `.claude/skills/` |
19+
|-------------------------|--------------------------|
20+
| Codex, opencode, Gemini, Copilot, Cursor | Claude, opencode, Copilot, Cursor |
21+
22+
No single directory covers all six: **Claude only reads `.claude/skills/`**, and **Codex/Gemini do
23+
not read `.claude/skills/`**.
24+
25+
A separate problem surfaced: the old `init` emitted **all** of `.claude/` (commands, agents,
26+
statusline, settings) plus `CLAUDE.md` unconditionally — junk for a user who only runs Codex or
27+
Gemini.
28+
29+
## Decision
30+
31+
### 1. Harness selection — only emit what the chosen agents use
32+
33+
`dotcontext init` resolves a set of harnesses and emits files **only** for them:
34+
- **Interactive** (default): confirm each detected agent (default = detected set).
35+
- **`--agents claude,codex`** flag: non-interactive/scripted selection (a deliberate, scoped
36+
exception to the minimal-CLI rule of ADR-007, for spec-kit `--integration` parity).
37+
- **`--yes`**: all detected agents (fallback to `claude` if none).
38+
39+
Emission gating:
40+
- `AGENTS.md` (canonical instructions) + `.context/` skeleton + MCP → **always** (harness-agnostic).
41+
- `CLAUDE.md` stub + **all of `.claude/`** (commands, agents, statusline, `.claudeignore`) → **only if
42+
Claude is selected**.
43+
- `GEMINI.md` stub → only if Gemini selected.
44+
- A Codex-only project therefore gets just `AGENTS.md` + `.agents/skills/` + a Codex hook — no `.claude/`.
45+
46+
### 2. Skills — `.agents/skills/` canonical, mirrored to `.claude/skills/`
47+
48+
The shared `SKILL.md` files are emitted to the physical directory matching the selection:
49+
- Claude selected → physical `.claude/skills/`; if an `AGENTS.md`-reading agent is also selected,
50+
`.agents/skills/` is a symlink to it (copy fallback for filesystems without symlinks).
51+
- Claude not selected → physical `.agents/skills/`.
52+
53+
dotcontext owns these files, so a single physical copy + symlink avoids drift (no `@import` exists for
54+
skills, unlike instructions).
55+
56+
### 3. Hooks — a notification hook per selected harness
57+
58+
Each selected harness gets a "task finished / needs attention" notification wired in its native config:
59+
- Claude → `.claude/settings.json` (existing: notify + tool-failure-guard).
60+
- Codex → `.codex/hooks.json`; Gemini → `.gemini/settings.json`; Copilot → `.github/hooks/dotcontext-notify.json`;
61+
Cursor → `.cursor/hooks.json`; opencode → `.opencode/plugins/dotcontext-notify.js` (opencode has no
62+
declarative hooks — only JS/TS plugins).
63+
- All point at a shared, **arg-driven** `notify.sh` (it takes title/message/sound as args and ignores
64+
stdin, so the same script works regardless of each agent's hook JSON contract). Create-only — never
65+
clobbers an existing agent config.
66+
67+
**Scope limits (intentional):** only the **notification** hook ports. The richer
68+
`tool-failure-guard` stays **Claude-only** (it depends on Claude's `PostToolUseFailure` semantics, which
69+
don't map uniformly). Non-Claude hook configs are validated as well-formed (JSON/TOML/JS) but are
70+
**best-effort** — they are not end-to-end tested against each agent runtime.
71+
72+
## Consequences
73+
74+
### Positive
75+
- No junk: a project only carries files for the harnesses it actually uses.
76+
- Skills and notification hooks work across all six agents from shared sources.
77+
- Confirms command portability (ADR-018) is viable — every agent has a native
78+
structured-question tool.
79+
80+
### Negative
81+
- Per-agent hook configs are best-effort (not runtime-tested per agent); event-name/semantics differ
82+
(e.g. Gemini uses `AfterAgent`, not `Stop`).
83+
- `tool-failure-guard` remains Claude-only.
84+
- A `--agents` flag widens the CLI surface (scoped exception, justified above).
85+
86+
## Alternatives Considered
87+
88+
1. **Emit everything for all agents always** — rejected: dumps junk (the problem this fixes).
89+
2. **One skills dir for all** — impossible: Claude and Codex/Gemini read disjoint directories.
90+
3. **Duplicate skill copies per ecosystem** — rejected: drift; symlink keeps one source.
91+
4. **Port `tool-failure-guard` everywhere** — rejected for now: no uniform failure-event semantics.
92+
93+
## History
94+
95+
| Version | Date | Changes |
96+
|---------|------|---------|
97+
| 1.0 | 2026-06-03 | Initial decision (harness selection, skills, notification hooks) |
98+
99+
## Related
100+
- ADR-016: Multi-agent harness (instructions file) — this builds on it
101+
- ADR-005: Mandatory AskUserQuestion — ADR-018 renders `{{ASK}}` to each agent's native question tool to satisfy it cross-agent
102+
- ADR-007: CLI simplification — `--agents` is a scoped exception
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# ADR-018: Command Portability & Invocation Modes (phase 2b plan)
2+
3+
**Status:** Proposed
4+
**Date:** 2026-06-03
5+
**Deciders:** Nicholas (Gocase)
6+
7+
## Context
8+
9+
ADR-016/017 made instructions, skills, and hooks multi-agent. The remaining piece (phase 2b) is
10+
porting the 12 slash commands. Two facts shape the design:
11+
12+
1. **Commands and skills have converged** (Claude Code): a `/x` command is effectively a skill with
13+
`disable-model-invocation: true`. Skills (`SKILL.md`) port cleanly to all six agents (ADR-017);
14+
classic per-repo commands do not (Codex prompts are global, Cursor has no file-based slash command).
15+
2. **Every agent ships a structured-question tool** (ADR-016 correction): Claude `AskUserQuestion`,
16+
Codex `request_user_input`, opencode `question`, Gemini `ask_user`, Copilot `ask_user`, Cursor
17+
`cursor/ask_question`. So requirement-gathering (ADR-005) is satisfiable on every agent.
18+
19+
The tempting shortcut — "make everything a skill" — is **unsafe**: skills are model-auto-invocable,
20+
and `disable-model-invocation` (explicit-only) is honored only by Claude and Cursor. Auto-firing a
21+
side-effecting command (`/commit`, `/create-pr`) on the other agents would be a foot-gun.
22+
23+
## Decision
24+
25+
### 1. Each artifact declares an invocation mode
26+
27+
- **`skill`** — auto-discoverable (model invokes by `description`) **and** explicitly invocable. For
28+
read-mostly knowledge/analysis with no dangerous side effects.
29+
- **`command`** — explicit-only. For deliberate, side-effecting, or outward-facing actions.
30+
31+
Classification (skills for knowledge, commands for action):
32+
33+
| Mode `skill` | Mode `command` (explicit-only) |
34+
|---|---|
35+
| `bug-reproduction`, `batch-operations`, `git-platform` (existing guides) | `setup-context`, `generate-prp`, `execute-prp`, `commit`, `create-pr`, `pr-comment`, `add-decision`, `add-skill`, `add-command` |
36+
| **`code-review`**, **`deep-context`** (read-mostly analysis — promoted from command) | `fix-bug` (makes changes; leans on the `bug-reproduction` skill) |
37+
38+
Rationale for the promotions: `code-review` and `deep-context` are read-mostly, and "review my changes"
39+
/ "help me understand X" are natural auto-triggers — discovery adds value with no side-effect risk, and
40+
the explicit `/name` still works.
41+
42+
### 2. Emit per agent by mode
43+
44+
- `skill` mode → `SKILL.md` (already ports to all six — ADR-017).
45+
- `command` mode → each agent's **explicit** primitive: Claude command, opencode command, Copilot
46+
prompt file, Gemini custom command (TOML), Cursor skill + `disable-model-invocation`, Codex prompt
47+
(global `~/.codex/prompts/`, namespaced). Where an agent only offers auto-skills, use its explicit
48+
flag if honored, otherwise fall back to documenting the workflow in `AGENTS.md`.
49+
50+
### 3. Portable `{{ASK}}` directive
51+
52+
Command/skill bodies express requirement-gathering with a portable `{{ASK: question | optA | optB }}`
53+
directive. At emit time it renders to each agent's **native** structured-question tool — it does **not**
54+
degrade to free text. This satisfies ADR-005's clarity-assessed questioning on every agent.
55+
56+
## Consequences
57+
58+
- **Positive:** preserves the safe boundary (knowledge = skill, action = command); no side-effecting
59+
auto-invocation; `{{ASK}}` keeps the ADR-005 contract everywhere.
60+
- **Negative:** the emitter must implement per-agent command formats + the `{{ASK}}` renderer; Codex
61+
commands remain global; Cursor commands ride on the skill+flag path.
62+
63+
## Alternatives Considered
64+
65+
1. **All artifacts as auto-skills** — rejected: unsafe (auto-firing side effects; `disable-model-invocation`
66+
not universal).
67+
2. **All as classic commands** — rejected: don't port (Codex global, Cursor none).
68+
3. **Free-text fallback for `{{ASK}}`** — rejected: unnecessary, every agent has a native question tool.
69+
70+
## History
71+
72+
| Version | Date | Changes |
73+
|---------|------|---------|
74+
| 1.0 (proposed) | 2026-06-03 | Initial plan for phase 2b |
75+
76+
## Related
77+
- ADR-005: Mandatory AskUserQuestion (clarity assessment) — `{{ASK}}` is how it's satisfied cross-agent
78+
- ADR-016: Multi-agent harness (instructions)
79+
- ADR-017: Harness selection, skills & hooks portability

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Changelog
22

3+
## [0.16.0](https://github.com/goca-se/dotcontext/compare/v0.15.0...v0.16.0) (2026-06-03)
4+
5+
### Features
6+
7+
* **multi-agent support** — dotcontext now targets six harnesses (Claude Code, OpenAI Codex, opencode, Gemini CLI, GitHub Copilot, Cursor incl. `cursor-agent`) instead of Claude only (ADR-016, ADR-017):
8+
* **extensible adapter registry** (`src/setup/agents.sh`) — each agent is one entry (`id`, name, detection, instructions file, emit mode). Adding an agent is a single case arm
9+
* **harness selection — only emit what you choose**`init` confirms each detected agent interactively, or takes `--agents claude,codex` (non-interactive), or `--yes` (all detected). A Codex-only project gets **no `.claude/`** — no junk
10+
* **instructions** — canonical **`AGENTS.md`** read natively by Codex/opencode/Copilot/Cursor; **Claude** (`CLAUDE.md`) and **Gemini** (`GEMINI.md`) via thin `@AGENTS.md` import stubs. Single source, no duplication
11+
* **skills** — shared `SKILL.md` content emitted to `.agents/skills/` (Codex/opencode/Gemini/Copilot/Cursor) mirrored to `.claude/skills/` (Claude) via symlink (copy fallback)
12+
* **hooks** — a "task finished / needs attention" notification wired per selected harness in its native config (`.codex/hooks.json`, `.gemini/settings.json`, `.github/hooks/`, `.cursor/hooks.json`, opencode JS plugin); Claude also keeps the tool-failure guard
13+
* **`update` migrates legacy projects** — a content-bearing `CLAUDE.md` with no `AGENTS.md` is offered migration into the shared `AGENTS.md` (content- and behavior-preserving), plus a `GEMINI.md` stub when the Gemini CLI is present
14+
* **`--version --json`** reports `multiagent: true`, `skills: true`, `hooks: true` and the supported `agents` list; **`doctor`** is `AGENTS.md`-aware and reports detected agents
15+
16+
### Notes
17+
18+
* Slash **commands** remain Claude-native; per-agent command ports (ADR-018 — invocation-mode classification + a portable `{{ASK}}` rendered to each agent's native structured-question tool) are the next phase. Non-Claude hook configs are validated as well-formed but are best-effort (not runtime-tested per agent); the tool-failure guard stays Claude-only.
19+
320
## [0.15.0](https://github.com/goca-se/dotcontext/compare/v0.14.2...v0.15.0) (2026-06-02)
421

522
### Features

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ SOURCES = \
1010
src/core/utils.sh \
1111
src/setup/notifications.sh \
1212
src/setup/mcp.sh \
13+
src/setup/agents.sh \
1314
src/commands/init.sh \
1415
src/commands/update.sh \
1516
src/commands/doctor.sh \

0 commit comments

Comments
 (0)