Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 89 additions & 9 deletions .agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ agent back at one file prevents that structurally.
| ------------------------------------------------------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------- |
| Claude Code | `CLAUDE.md` (first line `@AGENTS.md`) + `.claude/` | `CLAUDE.md`, `.claude/settings.json`, `.claude/{agents,commands,skills}` symlinks |
| OpenCode | `.opencode/opencode.jsonc` `instructions` | `.opencode/opencode.jsonc`, `.opencode/{…}` symlinks |
| GitHub Copilot | native `AGENTS.md` (2026); legacy stub | `.github/copilot-instructions.md` → `AGENTS.md` (opt-in `copilot`) |
| GitHub Copilot | coding agent: native root `AGENTS.md`; code review: `.github/` files only | populated `.github/copilot-instructions.md` + `.github/instructions/` review rules + `.github/skills/code-review/` skill (opt-in `copilot_code_review`; code review does **not** read `AGENTS.md`) |
| OpenAI Codex | native root `AGENTS.md` (32 KiB doc cap) | none needed |
| Google Gemini CLI | `.gemini/settings.json` `context.fileName` | add `.gemini/settings.json` → `AGENTS.md` (see recipe below) |
| Jules, Cursor, Windsurf, Roo Code, Zed, JetBrains Junie, Aider, Amp | native root `AGENTS.md` | none needed |
Expand All @@ -35,26 +35,106 @@ agent back at one file prevents that structurally.
ln -s ../../AGENTS.md .continue/rules/AGENTS.md
```
3. **Needs a config key or a frontmatter'd file?** Add a thin pointer/config stub
that references `AGENTS.md`. Never copy instruction prose into it. Precedents:
that references `AGENTS.md`. Never copy instruction prose into it. Precedent:
```jsonc
// .github/copilot-instructions.md → one line: see ../AGENTS.md
// .gemini/settings.json
{ "context": { "fileName": ["AGENTS.md", "GEMINI.md"] } }
```
4. Put tool-specific guidance (not meant for every agent) in that tool's own file,
not in `AGENTS.md`.

## Layout

Everything here is a single source read by both tools. The symlinks are
created by the post-generation hook; if you copy this layout manually,
recreate them with:

```sh
ln -s ../.agents/subagents .claude/agents && ln -s ../.agents/subagents .opencode/agents
ln -s ../.agents/commands .claude/commands && ln -s ../.agents/commands .opencode/commands
ln -s ../.agents/skills .claude/skills && ln -s ../.agents/skills .opencode/skills
```

### `subagents/`

One Markdown file per role, with YAML frontmatter. Supported keys:

- `name` (required) — invocation name; identity comes from this, not the
filename.
- `description` (required) — used by parent agents to decide when to
delegate; start with "Use proactively when…" for auto-discovery.
- `model` (optional) — `sonnet` / `opus` / `haiku` / `inherit`.
- `tools` (optional) — Claude Code allowlist, comma-separated names
(e.g. `Read, Grep, Glob, Bash`). Claude Code only.
- `permission` (optional) — OpenCode per-action map with keys
`read` / `write` / `edit` / `bash`, each taking `allow` / `ask` / `deny`;
`bash` can also be a per-pattern map (e.g. `"rg *": allow`, `"*": deny`).
OpenCode only — Claude Code ignores this field.
- `mode` (optional, **strongly recommended for subagents**) — OpenCode-only.
Set `mode: subagent` to keep the agent delegation-only; the default
(`all`) would also expose it as a top-level primary OpenCode agent.

A subagent runs in its own context window — use them to keep heavy
exploration or repetitive review out of the main session's context. Claude
Code subagents **cannot spawn other subagents**: when a role needs something
run outside itself (an `explorer` pass, a spike experiment, a user's
answer), it stops and hands back to the main agent, carrying the request
and the resume instruction in its own reply — the role subagents' Handoff
sections define these protocols. The reply must be self-contained because a
subagent can be reached by description match as well as by its slash
command, and in the former case the command's instructions were never
loaded.

### `commands/`

One Markdown file per slash command, with YAML frontmatter (`description`,
optional `argument-hint`). Keep each command short and imperative — the
description is what surfaces in the slash-command picker, and the body is
the prompt the agent will follow.

### `skills/`

One directory per skill, containing a `SKILL.md` (required, with YAML
frontmatter `name` and `description`) and optionally `scripts/`
(deterministic executables), `references/` (docs loaded on demand), and
`assets/`. `design-principles/` is the skill that ships — the shared design
ground rules and red-flag checklist the role subagents read. Write skill
descriptions slightly "pushy" — agents tend to under-trigger skills —
and include synonyms.

## Caveats

- **Copier-managed.** This harness is generated from a Copier template
(`gh:grAItools/harness-copier-template`; see `.copier-answers.yml`). Edits to
template-owned files (`.claude/settings.json`, `.opencode/opencode.jsonc`,
`AGENTS.md`, the managed `.gitignore` block) can be reverted by `copier update`;
port durable changes upstream behind a per-agent toggle. Net-new files (this
README, `.agents/hooks/*`, `.gemini/settings.json`) are safe.
(`gh:grAItools/harness-copier-template`; see `.copier-answers.yml`).
Everything under `.agents/` is template-owned — this README, `hooks/*`,
`subagents/*`, `commands/*`, `skills/*` — as are `.claude/settings.json`,
`.opencode/opencode.jsonc`, `AGENTS.md`, and the managed `.gitignore` block.
Edits to any of them can be reverted by `copier update`; port durable changes
upstream behind a per-agent toggle. Safe to edit: files you add yourself
(e.g. `.gemini/settings.json` from the recipe above) and the files the
template hands over on first generation and never rewrites — the root
`README.md`, the task-runner file, `scripts/*.sh`,
`.github/PULL_REQUEST_TEMPLATE.md`, and the `development/` documents
(`architecture.md`, `style.md`, `testing.md`, `glossary.md`,
`tool-bootstrap.md`, `harness-usage.md`, `adr/README.md`). Note that
`development/README.md` is *not* in that set — it is template-owned.
Comment thread
egparedes marked this conversation as resolved.
- **Symlinks need `core.symlinks=true`.** On Windows checkouts without it, Git
materializes a symlink as a text file containing the target path; prefer a stub
there. The repo already relies on symlinks for `.claude/` / `.opencode/`.
- **Destructive-command deny-list** is canonical in
[`hooks/block-destructive.sh`](hooks/block-destructive.sh); OpenCode's deny globs
are a hand-kept mirror (it cannot call a script).
are a hand-kept mirror (it cannot call a script). The script denies an
*operation* only where it is not inside quotes, so a read-only mention of one
(a search pattern, a fixture, a commit message) is allowed; SQL patterns still
match anywhere, quoted or not, since they have no unquoted form. OpenCode's
globs cannot express either distinction and deny every mention. The patterns
themselves are kept in sync by hand in both places.
- **Hook payload parsing** is canonical in
[`hooks/hook-input.sh`](hooks/hook-input.sh): the Claude Code hooks in
`.claude/settings.json` read their JSON input through it (`jq`, with a
`python3` fallback; each backend is probed by *running* it, so a `jq` that
resolves but cannot run falls through instead of failing the read). With
neither parser working, the PreToolUse guard fails closed with an
explanatory message, SessionStart warns, and the Stop gate still runs but
can only report a red result. Read scalar string or boolean fields: the
backends agree on those, not on number spelling (see the script header).
20 changes: 0 additions & 20 deletions .agents/commands/README.md

This file was deleted.

30 changes: 22 additions & 8 deletions .agents/commands/build.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
description: Implement the current feature one phase at a time, ticking tasks.md and running the verification gate at each phase boundary
argument-hint: <spec-dir-name> (optional; defaults to the most recent work/* directory)
argument-hint: <spec-dir-name> (optional; defaults to the most recent development/work/* directory)
---

You are carrying out the implementation phase of a feature.

1. Identify the target spec directory.
- If `$ARGUMENTS` is provided, use `work/$ARGUMENTS/`.
- If `$ARGUMENTS` is provided, use `development/work/$ARGUMENTS/`.
- Otherwise, use the most recently modified directory under
`work/`.
`development/work/`.
2. Read `spec.md`, `plan.md`, and `tasks.md` in full. If `plan.md` is
missing or empty, stop and tell the user to run `/plan` first.
3. If the plan touches an unfamiliar area of the codebase, run an
Expand All @@ -25,13 +25,27 @@ You are carrying out the implementation phase of a feature.
- Work one phase at a time, writing tests first where the plan
calls for behaviour change.
- Tick `tasks.md` checkboxes in the same commit as the code change.
- Keep `report.md` current: deviations, abandoned approaches, and
`DECISION-PENDING:` escalations are recorded when they happen.
- Run `make verify` at every phase boundary.
- Stop at the end of each phase and hand off to `/verify`
(Reviewer) before starting the next.
5. When the developer reports a phase complete, **stop** and ask the
user to run `/verify` before proceeding. Do not auto-start the
next phase.
5. If the developer stops mid-phase, that is not a phase boundary. Its
reply names the stop and the servicing instruction; follow it:
- `HANDBACK(explore):` in `scratch.md` — run the `explorer`, append
its answer as a `RESULT(explore):` line (keep the `path:LINE`
citations), then re-invoke the developer. After three explore
hand-backs on the same phase, the phase is scoped too wide — stop
and put it to the user.
- `DECISION-PENDING:` in `report.md` — put the question to the user,
add the register row (`development/adr/README.md`), re-invoke the

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CONFIRMED] correctness — ✅ Fixed in 17232e3

Ownership of the decision-register row is assigned to two different actors: /build step 5 tells the main agent to add it, while developer.md:83-90 and development/adr/README.md:75 say the row is the Developer's alone to append.

Failure scenario

Developer hits a decision beyond its authority, writes DECISION-PENDING: in report.md plus its register row in development/adr/README.md, and stops. The main agent, following build.md:40-42, appends a second row for the same decision before re-invoking. The register now carries two rows with different IDs for one escalation, so the documented "scan the table for pending rows" procedure double-counts open decisions. In the mirror case each side assumes the other owns the row, no row is written, and the Reviewer's rule (reviewer.md:180-181) makes the missing row an automatic MAJOR -> NEEDS-WORK on a build that was actually correct.

developer with the answer.
- `HANDBACK(replan):` in `scratch.md` — hand back to `/plan`
(Architect), then re-run `/build`. After three replan hand-backs
on the same feature, the plan and reality are not converging —
stop and put the mismatch to the user instead of re-planning.
6. When the developer reports a phase complete, **stop** and ask the
user to run `/verify`. Do not auto-start the next phase.

Never silently skip a failing test, edit anything under `*/generated/`,
or run destructive Git. If the plan turns out to be wrong, hand back
to `/plan` (Architect) rather than silently re-planning.
or run destructive Git.
17 changes: 14 additions & 3 deletions .agents/commands/plan.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
---
description: Expand spec.md into a numbered, testable plan.md for the current feature
argument-hint: <spec-dir-name> (optional; defaults to the most recent work/* directory)
argument-hint: <spec-dir-name> (optional; defaults to the most recent development/work/* directory)
---

You are expanding a feature spec into an implementation plan.

1. Identify the target spec directory.
- If `$ARGUMENTS` is provided, use `work/$ARGUMENTS/`.
- If `$ARGUMENTS` is provided, use `development/work/$ARGUMENTS/`.
- Otherwise, use the most recently modified directory under
`work/`.
`development/work/`.
2. Confirm `spec.md` exists and has been reviewed. If it's missing or
empty, stop and tell the user to run `/spec` first.
3. Delegate the planning to the **architect** subagent
(`.agents/subagents/architect.md`). It owns the phased-plan format,
the architecture-decisions block, the "each phase has tests"
contract, and the "stop and ask before coding" boundary.
4. If the architect hands back a **spike request** — a
`HANDBACK(spike):` line in `scratch.md` naming one question (it
cannot run code itself) — run the smallest throwaway experiment that
answers it, in a temp dir or scratch space, never left in the source
tree. Append the result to `scratch.md` on a `RESULT(spike):` line
(question → method → answer → evidence), then re-invoke the
architect; it starts with fresh context and reads `scratch.md` to
pick the answer up. Spike code is disposable; only the findings
survive, in the plan's **Spike findings** section.
After **three spike hand-backs on the same plan**, the uncertainty
is not a design experiment — stop and put the question to the user.

The architect subagent will write `plan.md` and mirror it into
`tasks.md`, then stop for user review. Once the user confirms the
Expand Down
29 changes: 23 additions & 6 deletions .agents/commands/spec.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Create a new feature spec directory under work/<YYYY-MM>-<slug>/
description: Create a new feature spec directory under development/work/<YYYY-MM>-<slug>/
argument-hint: <kebab-case-slug>
---

Expand All @@ -8,17 +8,34 @@ You are creating a new feature spec.
1. If `$ARGUMENTS` is empty, ask the user for a slug before creating
anything.
2. Compute today's date as `YYYY-MM`. The directory is
`work/<YYYY-MM>-$ARGUMENTS/`.
`development/work/<YYYY-MM>-$ARGUMENTS/`.
3. Create the directory if it doesn't exist. **Do not** pre-create
`plan.md`, `tasks.md`, or `scratch.md` — each role creates the
artifacts it owns (Architect: `plan.md`/`tasks.md`; Developer:
`scratch.md`), and pre-creating them would force those roles to
`edit` files they should be able to `write` from scratch.
`plan.md`, `tasks.md`, `report.md`, or `scratch.md` — each role
creates the deliverables it owns (Architect: `plan.md`/`tasks.md`;
Developer: `report.md`), and pre-creating them would force those
roles to `edit` files they should be able to `write` from scratch.
`scratch.md` is not a deliverable but the feature's shared channel:
whoever needs it first creates it, and everyone after that appends.
4. Delegate the actual spec authoring to the **product-owner** subagent
(`.agents/subagents/product-owner.md`). It owns the spec format,
the testable-criteria rule, the non-goals requirement, and the
"stop and ask before planning" boundary.
5. If the product-owner hands back a **clarifying question** instead of
`spec.md`, put it to the user, then re-invoke the product-owner
subagent with the question, the user's answer, **and the prior Q&A**
included in the prompt — it starts each invocation with fresh
context and cannot see the exchange otherwise (the carried Q&A is
also how it knows the round count). Repeat until it produces the
spec. Cap this at **five rounds**: if the questions have not
converged by then, stop and ask the user to settle the scope
directly.

The product-owner subagent will write `spec.md` and then stop for user
review. Once the user confirms the spec, the next step is `/plan`
(Architect role). Do not start implementing yet.

If the reviewed spec's **Glossary** section pins down new domain terms,
promote them verbatim to `development/glossary.md` as part of the
review wrap-up (the product-owner subagent cannot write outside the
feature directory; the promotion rule lives in
`development/glossary.md`).
25 changes: 17 additions & 8 deletions .agents/commands/verify.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,27 @@ You are running the review phase for the current feature.
Delegate the work to the **reviewer** subagent
(`.agents/subagents/reviewer.md`). It will:

- Read `spec.md`, `plan.md`, `tasks.md`, and the current diff.
- Run `make verify`.
- Check spec conformance, plan conformance, and implementation
quality.
- Read `spec.md`, `plan.md` (including its **Review checklist**
section, if present — *additional* checks only; the checklist never
narrows the review or relaxes a verdict rule), `tasks.md`, `report.md`
(if the Developer has started it — expected by the final phase), and
the current diff.
- Run `make verify` itself — it never takes the Developer's
word for the gate.
- Check spec conformance, plan conformance, implementation quality,
and report honesty (undeclared deviations are defects).
- Produce a `GO` or `NEEDS-WORK` verdict with a citation-rich defect
list (`path/to/file.ext:LINE`) when work remains.
list (`path/to/file.ext:LINE`), ranked MAJOR / MINOR / INFO. Any
MAJOR means NEEDS-WORK.

Hand the reviewer's verdict back to the user verbatim. If
`NEEDS-WORK`, the next step is `/build` (Developer role) to address
the defects. If `GO`, summarise what changed since the last verify
(use `git diff --stat` and `git log -1`) and stop.
the defects. If `GO` on the feature's final phase, confirm `report.md`
is complete (what was built, deviations, negative results, follow-ups,
gate result) before the feature is declared mergeable — it freezes at
merge. Then summarise what changed since the last verify (use
`git diff --stat` and `git log -1`) and stop.

Never silently skip, disable, or `@ignore` a failing test. If a test
must be skipped, draft an ADR under `docs/adr/` and ask for
must be skipped, draft an ADR under `development/adr/` and ask for
confirmation.
Loading
Loading