-
Notifications
You must be signed in to change notification settings - Fork 0
feat: multi-agent support — harness selection, instructions, skills & hooks (v0.16.0) #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f5c2ed5
646921b
7c23221
3208d8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| # ADR-016: Multi-Agent Harness via Adapter Registry | ||
|
|
||
| **Status:** Accepted | ||
| **Date:** 2026-06-02 | ||
| **Version:** 1.0 | ||
| **Deciders:** Nicholas (Gocase) | ||
|
|
||
| ## Context | ||
|
|
||
| dotcontext was built Claude-Code-first (ADR-004): a project-root `CLAUDE.md` plus `.claude/` | ||
| commands, agents, and skills. ADR-004 explicitly accepted "tightly coupled to Claude Code | ||
| (won't work with other AI tools)" as a tradeoff. | ||
|
|
||
| The toolkit's value — the curated project instructions, decisions, and skills — is agent-agnostic. | ||
| Coding agents have converged on a near-common convention: the **AGENTS.md** open standard | ||
| (Linux-Foundation-stewarded, plain Markdown, nearest-file-wins). GitHub's spec-kit ships per-agent | ||
| integrations; we want the same reach without abandoning the Claude-first ergonomics. | ||
|
|
||
| Research (2026) on where each agent reads its project instruction/memory file: | ||
|
|
||
| | Agent | Instructions file | Reads `AGENTS.md` natively? | | ||
| |-------|-------------------|-----------------------------| | ||
| | Claude Code | `CLAUDE.md` | No (but supports `@import`) | | ||
| | OpenAI Codex | `AGENTS.md` | Yes (originator) | | ||
| | opencode | `AGENTS.md` (also reads `CLAUDE.md`) | Yes | | ||
| | GitHub Copilot | `AGENTS.md` / `.github/copilot-instructions.md` | Yes (since Aug 2025) | | ||
| | Cursor (IDE + `cursor-agent` CLI) | `AGENTS.md` / `.cursor/rules/*.mdc` | Yes | | ||
| | Gemini CLI | `GEMINI.md` | No (but supports `@import`; configurable) | | ||
|
|
||
| ## Decision | ||
|
|
||
| ### 1. Extensible adapter registry | ||
|
|
||
| A registry (`src/setup/agents.sh`) declares each supported agent as a small record: `id`, | ||
| display name, detection command (`command -v`), instructions filename, and emit mode. Adding an | ||
| agent is one entry — nothing else in the toolkit hard-codes an agent. Initial set: | ||
| `claude, codex, opencode, gemini, copilot, cursor` (the Cursor entry covers both the IDE and the | ||
| `cursor-agent` CLI). | ||
|
|
||
| ### 2. `AGENTS.md` is the single canonical source of project instructions | ||
|
|
||
| The real instruction content lives in **`AGENTS.md` at the repo root**. This natively covers | ||
| **codex, opencode, copilot, and cursor** with zero extra files. The two agents that don't read | ||
| `AGENTS.md` get thin **import stubs** pointing at it (both support `@import`): | ||
|
|
||
| - `CLAUDE.md` → `@AGENTS.md` (for Claude Code) | ||
| - `GEMINI.md` → `@AGENTS.md` (for Gemini CLI) | ||
|
|
||
| Single source, no duplication, no drift; each editor edits `AGENTS.md`. | ||
|
|
||
| ### 3. Interactive agent detection (no new CLI flags) | ||
|
|
||
| `dotcontext init` detects which agent CLIs are installed and emits the matching instruction files; | ||
| in interactive mode it confirms the selection. `--yes` sets up all detected agents (falling back | ||
| to Claude when none are detected). This honors the minimal-CLI constraint (ADR-007) — no | ||
| `--agent` flag, the flow lives inside `init`. | ||
|
|
||
| ### 4. Safe migration for existing projects | ||
|
|
||
| `dotcontext update` migrates legacy single-file projects: when a content-bearing `CLAUDE.md` | ||
| exists and `AGENTS.md` does not, it offers to make `AGENTS.md` canonical (move the content) and | ||
| leave `CLAUDE.md` as an `@AGENTS.md` stub. This is content-preserving and behavior-preserving for | ||
| Claude (it still reads the same content via the import). | ||
|
|
||
| ### 5. Scope of this decision (phase 2a) | ||
|
|
||
| This ADR covers the **instructions file** only. Skills and hooks portability is addressed in | ||
| **ADR-017**; porting slash commands to each agent's native format is deferred to a later phase. | ||
|
|
||
| > **Correction (2026-06-03):** an earlier draft of this ADR claimed "Codex/Gemini/etc. have no | ||
| > structured-question API," used to justify a degraded `{{ASK}}` fallback. That premise is **false**. | ||
| > Current research (see ADR-017) confirms **all six agents ship a model-callable structured-question | ||
| > tool** (Claude `AskUserQuestion`, Codex `request_user_input`, opencode `question`, Gemini | ||
| > `ask_user`, Copilot `ask_user`, Cursor `cursor/ask_question`) **and** lifecycle hooks. So command | ||
| > portability (ADR-018) renders `{{ASK}}` to each agent's **native** question tool — it | ||
| > does not degrade to free text. The `--version --json` handshake (ADR-015) flips `multiagent: true` | ||
| > and lists supported `agents` as adapters land. | ||
|
|
||
| ## Consequences | ||
|
|
||
| ### Positive | ||
| - The toolkit works across Claude, Codex, opencode, Copilot, Cursor, and Gemini from one source. | ||
| - Adding a new agent is a single registry entry. | ||
| - Existing Claude-only projects keep working and migrate safely. | ||
|
|
||
| ### Negative | ||
| - A root `AGENTS.md` plus possible `CLAUDE.md`/`GEMINI.md` stubs is slightly more surface than a | ||
| lone `CLAUDE.md`. | ||
| - Import resolution depends on each agent honoring `@import`; agents that don't are covered by | ||
| reading `AGENTS.md` directly, but a future agent that does neither would need a real copy. | ||
| - Command/skill portability is **not** solved here (phase 2b). | ||
|
|
||
| ## Alternatives Considered | ||
|
|
||
| 1. **Keep `CLAUDE.md` canonical, point `AGENTS.md` at it via `@import`** — rejected: Codex/Copilot/ | ||
| Cursor don't resolve `@import`, so they'd see a literal pointer instead of content. | ||
| 2. **Symlinks (`AGENTS.md` → `CLAUDE.md`)** — rejected: fragile on Windows/WSL (ADR cross-platform rule) and in git. | ||
| 3. **Full content copies per agent** — rejected: guarantees drift across files. | ||
| 4. **Per-agent zip artifacts (old spec-kit model)** — rejected: doesn't fit the single-bash-executable + curl distribution (ADR-001/002). | ||
|
|
||
| ## History | ||
|
|
||
| | Version | Date | Changes | | ||
| |---------|------|---------| | ||
| | 1.0 | 2026-06-02 | Initial decision (phase 2a: instructions file across agents) | | ||
|
|
||
| ## Related | ||
| - ADR-004: Claude Code integration (this extends it beyond Claude) | ||
| - ADR-005: Mandatory AskUserQuestion (will get a v2.0 for command portability in phase 2b) | ||
| - ADR-007: CLI simplification (interactive detection, no new flags) | ||
| - ADR-015: Capability discovery & update awareness (the handshake this populates) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| # ADR-017: Harness Selection, Skills & Hooks Portability | ||
|
|
||
| **Status:** Accepted | ||
| **Date:** 2026-06-03 | ||
| **Version:** 1.0 | ||
| **Deciders:** Nicholas (Gocase) | ||
|
|
||
| ## Context | ||
|
|
||
| ADR-016 made the project-instructions file (`AGENTS.md`) multi-agent. Two follow-ups remained: | ||
| **skills** and **hooks**. Research (June 2026) overturned an earlier assumption: **all six target | ||
| agents now implement the open Agent Skills (`SKILL.md`) standard, ship lifecycle hooks, and expose a | ||
| model-callable structured-question tool** (so the `AskUserQuestion` premise in ADR-016's first draft | ||
| was wrong — corrected there). | ||
|
|
||
| Skills directory coverage: | ||
|
|
||
| | Reads `.agents/skills/` | Reads `.claude/skills/` | | ||
| |-------------------------|--------------------------| | ||
| | Codex, opencode, Gemini, Copilot, Cursor | Claude, opencode, Copilot, Cursor | | ||
|
|
||
| No single directory covers all six: **Claude only reads `.claude/skills/`**, and **Codex/Gemini do | ||
| not read `.claude/skills/`**. | ||
|
|
||
| A separate problem surfaced: the old `init` emitted **all** of `.claude/` (commands, agents, | ||
| statusline, settings) plus `CLAUDE.md` unconditionally — junk for a user who only runs Codex or | ||
| Gemini. | ||
|
|
||
| ## Decision | ||
|
|
||
| ### 1. Harness selection — only emit what the chosen agents use | ||
|
|
||
| `dotcontext init` resolves a set of harnesses and emits files **only** for them: | ||
| - **Interactive** (default): confirm each detected agent (default = detected set). | ||
| - **`--agents claude,codex`** flag: non-interactive/scripted selection (a deliberate, scoped | ||
| exception to the minimal-CLI rule of ADR-007, for spec-kit `--integration` parity). | ||
| - **`--yes`**: all detected agents (fallback to `claude` if none). | ||
|
|
||
| Emission gating: | ||
| - `AGENTS.md` (canonical instructions) + `.context/` skeleton + MCP → **always** (harness-agnostic). | ||
| - `CLAUDE.md` stub + **all of `.claude/`** (commands, agents, statusline, `.claudeignore`) → **only if | ||
| Claude is selected**. | ||
| - `GEMINI.md` stub → only if Gemini selected. | ||
| - A Codex-only project therefore gets just `AGENTS.md` + `.agents/skills/` + a Codex hook — no `.claude/`. | ||
|
|
||
| ### 2. Skills — `.agents/skills/` canonical, mirrored to `.claude/skills/` | ||
|
|
||
| The shared `SKILL.md` files are emitted to the physical directory matching the selection: | ||
| - Claude selected → physical `.claude/skills/`; if an `AGENTS.md`-reading agent is also selected, | ||
| `.agents/skills/` is a symlink to it (copy fallback for filesystems without symlinks). | ||
| - Claude not selected → physical `.agents/skills/`. | ||
|
|
||
| dotcontext owns these files, so a single physical copy + symlink avoids drift (no `@import` exists for | ||
| skills, unlike instructions). | ||
|
|
||
| ### 3. Hooks — a notification hook per selected harness | ||
|
|
||
| Each selected harness gets a "task finished / needs attention" notification wired in its native config: | ||
| - Claude → `.claude/settings.json` (existing: notify + tool-failure-guard). | ||
| - Codex → `.codex/hooks.json`; Gemini → `.gemini/settings.json`; Copilot → `.github/hooks/dotcontext-notify.json`; | ||
| Cursor → `.cursor/hooks.json`; opencode → `.opencode/plugins/dotcontext-notify.js` (opencode has no | ||
| declarative hooks — only JS/TS plugins). | ||
| - All point at a shared, **arg-driven** `notify.sh` (it takes title/message/sound as args and ignores | ||
| stdin, so the same script works regardless of each agent's hook JSON contract). Create-only — never | ||
| clobbers an existing agent config. | ||
|
|
||
| **Scope limits (intentional):** only the **notification** hook ports. The richer | ||
| `tool-failure-guard` stays **Claude-only** (it depends on Claude's `PostToolUseFailure` semantics, which | ||
| don't map uniformly). Non-Claude hook configs are validated as well-formed (JSON/TOML/JS) but are | ||
| **best-effort** — they are not end-to-end tested against each agent runtime. | ||
|
|
||
| ## Consequences | ||
|
|
||
| ### Positive | ||
| - No junk: a project only carries files for the harnesses it actually uses. | ||
| - Skills and notification hooks work across all six agents from shared sources. | ||
| - Confirms command portability (ADR-018) is viable — every agent has a native | ||
| structured-question tool. | ||
|
|
||
| ### Negative | ||
| - Per-agent hook configs are best-effort (not runtime-tested per agent); event-name/semantics differ | ||
| (e.g. Gemini uses `AfterAgent`, not `Stop`). | ||
| - `tool-failure-guard` remains Claude-only. | ||
| - A `--agents` flag widens the CLI surface (scoped exception, justified above). | ||
|
|
||
| ## Alternatives Considered | ||
|
|
||
| 1. **Emit everything for all agents always** — rejected: dumps junk (the problem this fixes). | ||
| 2. **One skills dir for all** — impossible: Claude and Codex/Gemini read disjoint directories. | ||
| 3. **Duplicate skill copies per ecosystem** — rejected: drift; symlink keeps one source. | ||
| 4. **Port `tool-failure-guard` everywhere** — rejected for now: no uniform failure-event semantics. | ||
|
|
||
| ## History | ||
|
|
||
| | Version | Date | Changes | | ||
| |---------|------|---------| | ||
| | 1.0 | 2026-06-03 | Initial decision (harness selection, skills, notification hooks) | | ||
|
|
||
| ## Related | ||
| - ADR-016: Multi-agent harness (instructions file) — this builds on it | ||
| - ADR-005: Mandatory AskUserQuestion — ADR-018 renders `{{ASK}}` to each agent's native question tool to satisfy it cross-agent | ||
| - ADR-007: CLI simplification — `--agents` is a scoped exception | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # ADR-018: Command Portability & Invocation Modes (phase 2b plan) | ||
|
|
||
| **Status:** Proposed | ||
| **Date:** 2026-06-03 | ||
| **Deciders:** Nicholas (Gocase) | ||
|
|
||
| ## Context | ||
|
|
||
| ADR-016/017 made instructions, skills, and hooks multi-agent. The remaining piece (phase 2b) is | ||
| porting the 12 slash commands. Two facts shape the design: | ||
|
|
||
| 1. **Commands and skills have converged** (Claude Code): a `/x` command is effectively a skill with | ||
| `disable-model-invocation: true`. Skills (`SKILL.md`) port cleanly to all six agents (ADR-017); | ||
| classic per-repo commands do not (Codex prompts are global, Cursor has no file-based slash command). | ||
| 2. **Every agent ships a structured-question tool** (ADR-016 correction): Claude `AskUserQuestion`, | ||
| Codex `request_user_input`, opencode `question`, Gemini `ask_user`, Copilot `ask_user`, Cursor | ||
| `cursor/ask_question`. So requirement-gathering (ADR-005) is satisfiable on every agent. | ||
|
|
||
| The tempting shortcut — "make everything a skill" — is **unsafe**: skills are model-auto-invocable, | ||
| and `disable-model-invocation` (explicit-only) is honored only by Claude and Cursor. Auto-firing a | ||
| side-effecting command (`/commit`, `/create-pr`) on the other agents would be a foot-gun. | ||
|
|
||
| ## Decision | ||
|
|
||
| ### 1. Each artifact declares an invocation mode | ||
|
|
||
| - **`skill`** — auto-discoverable (model invokes by `description`) **and** explicitly invocable. For | ||
| read-mostly knowledge/analysis with no dangerous side effects. | ||
| - **`command`** — explicit-only. For deliberate, side-effecting, or outward-facing actions. | ||
|
|
||
| Classification (skills for knowledge, commands for action): | ||
|
|
||
| | Mode `skill` | Mode `command` (explicit-only) | | ||
| |---|---| | ||
| | `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` | | ||
| | **`code-review`**, **`deep-context`** (read-mostly analysis — promoted from command) | `fix-bug` (makes changes; leans on the `bug-reproduction` skill) | | ||
|
|
||
| Rationale for the promotions: `code-review` and `deep-context` are read-mostly, and "review my changes" | ||
| / "help me understand X" are natural auto-triggers — discovery adds value with no side-effect risk, and | ||
| the explicit `/name` still works. | ||
|
|
||
| ### 2. Emit per agent by mode | ||
|
|
||
| - `skill` mode → `SKILL.md` (already ports to all six — ADR-017). | ||
| - `command` mode → each agent's **explicit** primitive: Claude command, opencode command, Copilot | ||
| prompt file, Gemini custom command (TOML), Cursor skill + `disable-model-invocation`, Codex prompt | ||
| (global `~/.codex/prompts/`, namespaced). Where an agent only offers auto-skills, use its explicit | ||
| flag if honored, otherwise fall back to documenting the workflow in `AGENTS.md`. | ||
|
|
||
| ### 3. Portable `{{ASK}}` directive | ||
|
|
||
| Command/skill bodies express requirement-gathering with a portable `{{ASK: question | optA | optB }}` | ||
| directive. At emit time it renders to each agent's **native** structured-question tool — it does **not** | ||
| degrade to free text. This satisfies ADR-005's clarity-assessed questioning on every agent. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - **Positive:** preserves the safe boundary (knowledge = skill, action = command); no side-effecting | ||
| auto-invocation; `{{ASK}}` keeps the ADR-005 contract everywhere. | ||
| - **Negative:** the emitter must implement per-agent command formats + the `{{ASK}}` renderer; Codex | ||
| commands remain global; Cursor commands ride on the skill+flag path. | ||
|
|
||
| ## Alternatives Considered | ||
|
|
||
| 1. **All artifacts as auto-skills** — rejected: unsafe (auto-firing side effects; `disable-model-invocation` | ||
| not universal). | ||
| 2. **All as classic commands** — rejected: don't port (Codex global, Cursor none). | ||
| 3. **Free-text fallback for `{{ASK}}`** — rejected: unnecessary, every agent has a native question tool. | ||
|
|
||
| ## History | ||
|
|
||
| | Version | Date | Changes | | ||
| |---------|------|---------| | ||
| | 1.0 (proposed) | 2026-06-03 | Initial plan for phase 2b | | ||
|
|
||
| ## Related | ||
| - ADR-005: Mandatory AskUserQuestion (clarity assessment) — `{{ASK}}` is how it's satisfied cross-agent | ||
| - ADR-016: Multi-agent harness (instructions) | ||
| - ADR-017: Harness selection, skills & hooks portability |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,22 @@ | ||
| # Changelog | ||
|
|
||
| ## [0.16.0](https://github.com/goca-se/dotcontext/compare/v0.15.0...v0.16.0) (2026-06-03) | ||
|
|
||
| ### Features | ||
|
|
||
| * **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): | ||
| * **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 | ||
| * **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 | ||
| * **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 | ||
| * **skills** — shared `SKILL.md` content emitted to `.agents/skills/` (Codex/opencode/Gemini/Copilot/Cursor) mirrored to `.claude/skills/` (Claude) via symlink (copy fallback) | ||
| * **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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use official “GitHub” capitalization in this bullet. Tiny wording fix, but it avoids inconsistency in release notes. 🧰 Tools🪛 LanguageTool[uncategorized] ~12-~12: The official name of this software platform is spelled with a capital “H”. (GITHUB) 🤖 Prompt for AI Agents |
||
| * **`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 | ||
| * **`--version --json`** reports `multiagent: true`, `skills: true`, `hooks: true` and the supported `agents` list; **`doctor`** is `AGENTS.md`-aware and reports detected agents | ||
|
|
||
| ### Notes | ||
|
|
||
| * 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. | ||
|
|
||
| ## [0.15.0](https://github.com/goca-se/dotcontext/compare/v0.14.2...v0.15.0) (2026-06-02) | ||
|
|
||
| ### Features | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Capitalize “GitHub” consistently in hook path examples.
Use “GitHub Copilot” capitalization in this sentence for consistency with the rest of the docs.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~60-~60: The official name of this software platform is spelled with a capital “H”.
Context: ...ni →
.gemini/settings.json; Copilot →.github/hooks/dotcontext-notify.json; Cursor...(GITHUB)
🤖 Prompt for AI Agents