Skip to content

About

Custom OpenCode settings

Resources

Stars

170 stars

Watchers

1 watching

Forks

Latest commit

 

History

310 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

English | Français

CodeMemory MCP License: MIT OpenCode Claude Code mirror Cursor plugin

harness-manifesto

One harness for Claude Code, OpenCode, and Cursor. Formerly settings-opencode; that URL redirects here. You install one variant. Monolith is the default. Conductor is opt-in. Skills are one shared tree either way.

MIT licensed. Fork it. The tree moves with the workflow, so treat it as a living reference.

Un harness pour Claude Code, OpenCode et Cursor. Anciennement settings-opencode. Monolith est le défaut, Conductor est opt-in. Les schémas sont en anglais et partagés. Choisir une variante et Comment une demande avance reprennent le même choix en français. L'installation est dans Public install.

One harness, two variants, three hosts

One harness, two variants, three hosts. Monolith is the default install. Conductor is opt-in.

Open the comparison (one HTML file, no network). La même page en français, plus bas.

Three hosts, one install tree:

Host Where it lands
OpenCode ~/.config/opencode/. Hub file: opencode.jsonc. Entry: install.sh or bootstrap.sh.
Claude Code Optional ~/.claude/ mirror: settings, hooks, rules, agents, synced skills. Same variant as OpenCode when you install both.
Cursor Plugin fmflurry-harness via install-cursor.sh. Version 0.4.36 in scripts/cursor-plugin/config.json. Agents are marked readonly or not. This host has no per-agent write allowlist.

Monolith is variants/monolith/. These install it when you omit the variant: ./install.sh --yes, ./install.sh --local, bootstrap.ps1, settings-sync, and ./install-cursor.sh. install.sh copies the Conductor tree, then scripts/variants/apply-monolith.mjs overlays the lean roster onto that copy. The source checkout stays as it is.

The primary agent writes, plans, and implements in the same session. Nothing has to run before the first edit. /orchestrate loads the conductor skill and stays optional.

Nine agents are installed, for review and noisy output: code-reviewer, security-reviewer, database-reviewer, ecosystem-auditor, e2e-runner, why-investigator, build-error-resolver, cop, comment-judge. Folded roles are skills (planner, coder, tdd, git-workflow, writer, and the rest named in variants/monolith/AGENTS.md). Live Postgres goes to database-reviewer or the main agent. The installed roster leaves out postgres-dba.

Conductor is the repository root: .claude/, opencode.jsonc, prompts/agents/, instructions/. variants/conductor/manifest.json sets "default": true because that root is the Conductor source. Installers still select Monolith when the variant is omitted. Choose Conductor with ./install.sh conductor, ./install-cursor.sh --variant conductor, or the alias orchestration.

A read-only conductor routes every change. In opencode.jsonc its write and edit tools are off, and the Task allowlist names every legal specialist. instructions/subagent-routing.md is the first-tool gate: when a specialist matches, the first tool call is that Task. Before coder, writer, or tdd-guide, the conductor emits the 6-field brief (brief-contract). The roster is 1 conductor plus 25 specialists: 26 files in prompts/agents/ and 26 in .claude/agents/.

planner → (tdd-guide → coder) or coder → code-reviewer → verify → git-specialist

On Cursor, the same conductor agent is marked readonly (scripts/cursor-plugin/lib.mjs). Delegation on that host is the readonly mark plus the prompt.

Switching variants removes the other variant's agents, commands, and rules. Returning to Conductor runs scripts/variants/prune-foreign.mjs.

Monolith Conductor
Who writes application code The primary agent, through skills such as coder and tdd Writable specialists (coder, writer, tdd-guide, and the other writable names in instructions/subagent-routing.md)
Who coordinates The primary agent. /orchestrate is optional The conductor agent
Installed agents 9 26 (conductor + 25)
Skills Shared skills/ tree Shared skills/ tree
Source in this repo Overlay variants/monolith/ on the install copy Repository root. "default": true marks that source
Install ./install.sh --yes, ./install.sh --local, ./install-cursor.sh ./install.sh conductor, ./install-cursor.sh --variant conductor. orchestration is an alias
./install.sh                         # interactive; default Monolith
./install.sh --yes                   # Monolith on OpenCode + Claude Code
./install.sh conductor               # Conductor on OpenCode + Claude Code
./install.sh monolith
./install.sh --local                 # project files; default Monolith
./install.sh --variant orchestration # alias of Conductor
./install-cursor.sh                  # Cursor plugin, default Monolith
./install-cursor.sh --variant conductor

Windows: bootstrap.ps1 with no variant is Monolith. bootstrap.ps1 conductor selects Conductor. orchestration is the same alias.

Choisir une variante

Monolith est le défaut : ./install.sh --yes, ./install.sh --local, bootstrap.ps1, settings-sync, ./install-cursor.sh. L'agent principal écrit, planifie et implémente. Neuf agents restent pour la revue et la sortie bruyante. Les rôles repliés sont des skills, listés dans variants/monolith/AGENTS.md. /orchestrate charge le skill conductor et reste optionnel. Postgres en direct va à database-reviewer ou à l'agent principal.

Conductor se choisit avec ./install.sh conductor ou ./install-cursor.sh --variant conductor. orchestration est un alias. Le conducteur route chaque changement. Le roster fait 1 conducteur + 25 spécialistes. variants/conductor/manifest.json porte "default": true parce que la racine du dépôt est l'arbre source Conductor. Les installeurs choisissent Monolith quand la variante est omise.

Le schéma au-dessus et la page HTML montrent les trois hôtes et le tableau des différences. Changer de variante retire les agents, commandes et règles de l'autre.

How a request moves

How a request moves: Conductor routes and Monolith writes, then verification, review, a pull request, or an escalation.

Open the statechart. Visual vocabulary adapted from @poteto's /statechart in backnotprop/pstack (MIT · Lauren Tan).

The rails are the same on OpenCode, Claude Code, and Cursor. The fork is the variant. Conductor routes, and a writable specialist edits. Monolith writes in the main session and spawns a specialist for review, parallel fan-out, or noisy output. After a source edit, the verification gate wants the project build, lint, and the tests that cover the change, with the real output pasted. Two failed fix passes on the same error stop. Independent review is code-reviewer and security-reviewer, plus cop or the stack reviewer when it applies. A confirmed Important finding blocks. Nit and Pre-existing do not. An interactive run stops when the PR is open. /ship continues through CI and merges only with agent-harness ship-merge.

The chart leaves out hook internals and the full /ship retry loop. Those are shared once review has passed. The contract is Autonomous mode and Mode autonome.

Shared on both variants and all three hosts:

  • Verification gate. "Done" waits on fresh command output.
  • Tool budget. Verification commands are uncapped. Exploratory shell is budgeted.
  • Secret-file guard, autonomy and /ship, worktree destruction safety, and a PR visual report under docs/pr-reports/.
  • KPI journal at ~/.agent-harness/kpi/events.jsonl.
  • CodeMemory when it is on. Cloud and remote sessions skip it unless FMFLURRY_CODEMEMORY=on.

Comment une demande avance

Mêmes rails sur OpenCode, Claude Code et Cursor. Conductor délègue. Monolith écrit dans la session principale. Le schéma et la page HTML suivent la demande : routage ou écriture, porte de vérification, revue, PR, ou escalade vers vous. Le vocabulaire visuel est adapté de /statechart de @poteto dans backnotprop/pstack (MIT, Lauren Tan).

The harness as a state machine

The harness as a state machine: one session, two runtimes reading the same state files, with gates that block, steer, or loop.

Open the statechart. Visual vocabulary adapted from @poteto's /statechart in backnotprop/pstack (MIT · Lauren Tan).

The chart follows a Monolith install. Control flow lives in the gates, not in the prompt. On OpenCode the secret guard, the git guard, and the tool budget are plugins. On Claude Code the git guard and the tool budget are hooks, and the secret guard is the permissions.deny list in .claude/settings.json, which covers Write and Edit only. The subagent allow-list is the permission.task block in opencode.jsonc. Autonomy state lives in .claude/state/. A hard gate denies and the model reroutes. A soft gate only steers. Autonomous mode adds the goal lifecycle: one worktree, one branch, one goal file, and a stop gate that blocks until the PR merges or the run escalates. The last panel lists three places where the config holds together in theory and slips in practice.

Le harness comme machine à états

Le schéma suit une installation Monolith. Avec la page HTML, il suit une session entière : démarrage, appel d'outil, arrêt, puis le cycle d'un objectif en mode autonome. Les gardes décident. Un garde dur refuse et le modèle change de route. Un garde souple ne fait qu'aiguiller. Le vocabulaire visuel est adapté de /statechart de @poteto dans backnotprop/pstack (MIT, Lauren Tan).

On this page

Public install

The repo is designed to merge into ~/.config/opencode/, plus an optional ~/.claude/ mirror. There are three paths: a one-line install (recommended — nothing to clone by hand), a one-shot script if you already have the repo, and a manual walk-through if you want to see every step.

One-line install

You don't need to clone anything first. The command below downloads harness-manifesto. bootstrap.sh still clones https://github.com/fmflurry/settings-opencode.git (that URL redirects here) into ~/.local/share/settings-opencode (override with SETTINGS_OPENCODE_SRC), then runs the installer. That directory name, and the shell-rc fence # >>> settings-opencode >>>, are still what bootstrap.sh and install.sh write. Re-running the exact same command is also how you update — it pulls the latest and re-applies it.

macOS / Linux / WSL (bash):

curl -fsSL https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.sh | bash

On WSL it installs to the Windows side (/mnt/c/Users/<you>/.config/opencode), matching install.sh's WSL behaviour. Pass installer flags through after -s --:

curl -fsSL https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.sh | bash -s -- --local
curl -fsSL https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.sh | bash -s -- --no-claude
curl -fsSL https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.sh | bash -s -- --uninstall

Native Windows (PowerShell — no WSL):

irm https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.ps1 | iex

Merges into %USERPROFILE%\.config\opencode and \.claude, runs npm install (or bun install), and writes the OPENCODE_* defaults as persistent User environment variables. Open a new terminal afterwards so they take effect. Variants:

# project-scoped install
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.ps1))) -Local
# skip the Claude mirror
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.ps1))) -NoClaude
# skip OpenCode (install Claude only)
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.ps1))) -NoOpencode
# uninstall (removes the OPENCODE_* env vars; leaves copied config in place)
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.ps1))) -Uninstall

Prerequisites

  • macOS, Linux, WSL, or native Windows.
  • OpenCode CLI installed and on your PATH (unless installing Claude Code only via --no-opencode).
  • Claude Code installed if you want the .claude/ mirror (unless skipped via --no-claude).
  • Either Bun (recommended — bun.lock is what's checked in) or Node.js >=22.6 with npm.
  • git.

Secrets

This repo stores no API keys. If you use the myMistral provider in opencode.jsonc, set MISTRAL_API_KEY by:

  • Copying .env.example → .env and filling in your key, OR
  • Exporting MISTRAL_API_KEY in your shell rc.

Other providers (Anthropic, OpenAI, GitHub Copilot, OpenCode Go) need their own keys set the same way if you select their profiles. All local .env* files are git-ignored; only .env.example is tracked.

Quick install (script)

Already have the repo cloned? Run the installer directly:

git clone https://github.com/fmflurry/harness-manifesto.git ~/Workspace/harness-manifesto
cd ~/Workspace/harness-manifesto
./install.sh

install.sh is interactive by default. It asks which harness to install (Claude Code, OpenCode, or both), which variant (Conductor or Monolith), and whether the scope is global or local. The variant question comes first. Monolith is the default. conductor selects Conductor:

  1. Verify your prerequisites (git, bun/npm).
  2. OpenCode (if selected): merge repo files into ~/.config/opencode (or ./.opencode if --local) without removing existing user config.
  3. Run bun install (or npm ci if Bun isn't available).
  4. Sync skills from the canonical set into both harnesses via scripts/sync-skills.sh.
  5. Seed personal config files (settings.json, settings.local.json, policy-limits.json) only on first install; preserve user edits on reinstall.
  6. Write a marker-fenced shell block that records SETTINGS_OPENCODE_REPO (OpenCode only, skipped if --local). A re-run replaces the block and drops retired OPENCODE_MODEL_* and OPENCODE_REASONING_* exports. The block does not set a model.
  7. Claude Code (if selected): merge .claude/ into ~/.claude (or ./.claude if --local).
  8. Print a smoke-test command and the locations to tweak afterwards.

Useful flags:

Flag Behaviour
(none) Interactive walk-through: prompt [Y/n] for OpenCode (default Y) and Claude Code (default Y).
--yes, -y Non-interactive — accept all defaults: OpenCode ✓, Claude Code ✓. Monolith is the default, including a global install. Existing normal directories are merged, not removed or backed up.
--variant monolith (default) or conductor. orchestration is an alias of conductor. Same as HARNESS_VARIANT. The flag wins over the env. With neither set, Monolith is the default, including global --yes. conductor selects Conductor.
--status Print the installed variant for OpenCode and Claude Code, then exit. --local also prints ./.cursor, ./.agents, the .harness-local overlay, exclude entries, and domain-rules state. A marker of orchestration is reported as Conductor.
--local Project-scoped install into the current directory (./.opencode, ./.claude as independent siblings) and vendors ./AGENTS.md, ./.cursor/rules, and ./.agents. Applies .harness-local/ on top and prunes .harness-local/exclude. Skips the global shell-rc env block and prints the repo-path block instead. That block does not set a model. Default variant is Monolith.
--opencode Allow-list: install OpenCode only (if combined with other flags, only those are installed).
--claude Allow-list: install Claude Code only.
--no-opencode Deny: skip OpenCode entirely (repo copy, deps, and env block). Can be combined with other targets.
--no-claude Deny: skip the Claude Code mirror. Can be combined with other targets.
--uninstall Remove the env-var block and optionally remove copied local/global dirs after confirmation. Never deletes the cloned repo or your data without confirmation.
--help, -h Print usage.

Conductor is the conductor-led tree at the repo root. Monolith (variants/monolith/) is a lean overlay applied to the install copy: the primary agent writes, /orchestrate is optional, and OpenCode and Claude Code get the same roster. Skills stay one shared tree. ./install.sh --yes with no variant installs Monolith. install-cursor.sh builds that Monolith plugin unless --variant conductor or HARNESS_VARIANT=conductor is set. ./install.sh --local vendors the same variant into the project. ./install.sh conductor and ./install.sh monolith switch without the menu and remove the other variant's leftovers.

Project overlay (.harness-local/)

./install.sh --local (Conductor or Monolith) reads a project-owned directory and never creates, edits, or deletes it. A symlink such as macOS /tmp still applies that overlay, and a skipped root prints why. Local settings record ./.claude/mods/autonomy-status. Monolith records .opencode/instructions/monolith.md. Layout, exclude format, and the off-by-default domain-rules hook are in docs/harness-local.md.

.harness-local/exclude                         # skill ids and harness paths to prune
.harness-local/domain-rules.json               # {"enabled": false, "script": "scripts/check-domain-rules.sh"}
.harness-local/AGENTS.md                       # wins over the vendored AGENTS.md
.harness-local/.claude/                        # copied onto ./.claude
.harness-local/.opencode/                      # copied onto ./.opencode
.harness-local/.cursor/                        # copied onto ./.cursor
.harness-local/.agents/                        # copied onto ./.agents

A line in exclude that is a skill id (angular-ddd or skills/angular-ddd) is removed from .claude/skills/, .opencode/skills/, and .agents/skills/ on every run. ./install.sh --local --status prints the overlay and the exclude list. The domain-rules hook does nothing until domain-rules.json sets "enabled": true.

./install.sh conductor
./install.sh monolith
./install.sh --status
./install.sh --variant orchestration
HARNESS_VARIANT=monolith ./install.sh --yes

The script writes a fenced block to your shell rc (~/.zshrc, ~/.bashrc, or ~/.config/fish/config.fish) that looks like this:

# >>> settings-opencode >>>
# Added by settings-opencode installer.
# To remove this block, run: settings-sync --uninstall
# OpenCode agents inherit the session model. This block does not set one.
export SETTINGS_OPENCODE_REPO="/path/to/harness-manifesto"
# <<< settings-opencode <<<

Re-running ./install.sh rewrites the block. ./install.sh --uninstall removes it. OpenCode does not read a model from it.

If your shell isn't bash/zsh/fish, the script prints the env block for you to paste manually and continues with the rest of the install.

Manual install

Click to expand the step-by-step manual walk-through (same outcome as the script).

1. Clone the repo, then merge it into the OpenCode config dir

OpenCode loads ~/.config/opencode/opencode.jsonc at startup. Keep the repo wherever you like, then copy it additively into the config dir.

# Clone
git clone https://github.com/fmflurry/harness-manifesto.git ~/Workspace/harness-manifesto
mkdir -p ~/.config/opencode
rsync -a --exclude node_modules --exclude .git ~/Workspace/harness-manifesto/ ~/.config/opencode/
cd ~/.config/opencode

2. Install plugin/tool dependencies

bun install        # uses bun.lock
# or
npm ci

3. Leave the model unset

The harness does not set an OpenCode model. A primary agent with no model uses the model selected for the session, or your OpenCode default. A subagent with no model uses the model of the agent that invoked it. See OpenCode agents.

To pin one agent, set model on that agent in your own OpenCode config. Do not expect OPENCODE_MODEL_* or OPENCODE_REASONING_*. The installer no longer writes them, and opencode.jsonc never interpolated the reasoning variables. The myMistral block remains a provider definition. Nothing selects it unless you do.

4. Install MCP server prerequisites

opencode.jsonc declares six MCP servers: one enabled by default (code-memory) and five disabled (context7, blender, wallaby, Figma, smartbear-swagger). CodeMemory is strongly recommended — the codebase-exploration skill routes repo orientation through it before falling back to grep/read. The others are optional but documented here so you know what you're opting into.

Server Install Status
code-memory uvx --from flurryx-code-memory@latest code-memory-mcp (auto-installed on first use) Recommended. Enabled. Semantic repo orientation; code-memory_* tools are pre-allowlisted for every subagent. Pairs with the codebase-exploration skill.
context7 nothing — npx -y @upstash/context7-mcp@latest Disabled by default. Live docs lookup.
blender uv --directory $HOME/dev/blender_mcp/mcp run blender-mcp Disabled by default. Blender scene tooling; drives the gaudi agent when enabled.
wallaby install Wallaby.js and run wallaby update-mcp Disabled by default. Runtime-test introspection.
Figma remote — https://mcp.figma.com/mcp Disabled by default. Flip enabled: true and set up Figma MCP for design-system tools.
smartbear-swagger remote — https://swagger.mcp.smartbear.com/mcp Disabled by default. OpenAPI/Swagger tooling for api-spec-architect.

5. (Optional) Install the Claude Code mirror

The repo ships a .claude/ subtree. OpenCode and Claude Code can be installed separately and never nest inside one another.

Claude Code:

mkdir -p ~/.claude
rsync -a ~/.config/opencode/.claude/ ~/.claude/

What this installs:

  • .claude/CLAUDE.md — global user instructions Claude Code reads on every session.
  • .claude/settings.json — permissions, hooks, env vars (API_TIMEOUT_MS, autocompact threshold, etc.), and "model": "opus" for the Claude Code main agent (Conductor and Monolith). Seeded on first install. A model value already in the file is left as written.
  • .claude/hooks/*.sh — pre-tool-use security warnings + stop hook.
  • .claude/rules/{common,typescript}/*.md — coding-style/testing/security rule packs.
  • .claude/commands/*.md — extra slash commands (/create-pull-request, /update-codemaps, and the Claude-only arena commands).
  • .claude/skills/** — the skill mirror, synced from the canonical set by scripts/sync-skills.sh on install.

Smoke test

opencode

You should see:

  • The panda banner shows up.

Then drop a slash command:

/plan add a TODO list to my homepage

On Conductor it dispatches the planner subagent and returns a plan. On Monolith, the install default, the same command loads the planner skill in the main session.

Changing models

OpenCode uses the session model for every agent. Select it in OpenCode, or set your default in your own OpenCode config. To pin one agent, add model to that agent in your own config. This harness does not set one, and a reinstall does not put one back. See OpenCode agents. Claude Code reads .claude/settings.json. Cursor reads its tier files.

Claude Code: the main agent (the session default) is "model": "opus" in .claude/settings.json, for Conductor and Monolith. Subagent tiers stay as they are. A fresh global ~/.claude install and a fresh project .claude install both receive that alias. If model is already set, the installer leaves that value alone when it merges hooks.

Cursor: tier files stay Cursor models. This change does not edit ~/.cursor/rules/fmflurry-harness-models.mdc or ~/.agents/fmflurry-harness-models.md.

Updating

If you installed via the one-liner, re-run the exact same command — it pulls the latest and re-applies it:

# macOS / Linux / WSL
curl -fsSL https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.sh | bash
# native Windows
irm https://raw.githubusercontent.com/fmflurry/harness-manifesto/master/bootstrap.ps1 | iex

If you cloned the repo by hand instead:

cd ~/.config/opencode
git pull
./install.sh --yes        # refreshes deps + env block; idempotent
# or, if you want to do it by hand:
# bun install   (or: npm ci)

If a new plugin shows up, OpenCode picks it up on the next restart. If an env var is added to opencode.jsonc, this README will mention it.


Measure the variants

Conductor and Monolith share one local journal. OpenCode, Claude Code, and Cursor write the same events.

Session, stop, and subagent hooks, PreToolUse guards, PostToolUse, ship-stop-gate, and the review verdict append one JSON line to ~/.agent-harness/kpi/events.jsonl. AGENT_HARNESS_KPI_LOG changes the path. AGENT_HARNESS_KPI=0 turns writing off. Each line carries the variant from .harness-variant (orchestration counts as Conductor), the harness version, the host (opencode, claude, or cursor), the repo, the branch, the session, and the time. A Skill tool adds skill. A Task or Agent tool, and a subagent stop, add agent. tool_result carries tool_name, duration_ms, and ok. Tokens come from message.updated (OpenCode) or the stop transcript (Claude). Cursor leaves them null. The field list is docs/kpi-events.md. The journal has no prompt, no secret, and no absolute path.

agent-harness kpi report --since 30d --by variant
agent-harness kpi report --json
agent-harness kpi report --html > /tmp/kpi.html
agent-harness kpi feature
agent-harness kpi feature --pr 53 --json

agent-harness kpi feature summarizes one branch (repo, branch, and the PR number once an event carries it): wall time, active time with gaps over 5 minutes removed, sessions per host, tools and skills, calls per agent (main and each subagent), failures and durations, guard blocks, review and fix rounds, and tokens when the host sent them (n/a otherwise). It writes docs/pr-reports/<slug>.metrics.json with no prompt, argument, or absolute path. Both variants run this before the PR report HTML. pr-report inserts a Metrics panel. pr-report-check warns when the metrics are missing or partial, and the visual check still passes.

The comparison table puts Conductor next to Monolith: tasks, tokens per task when known, duration, tool calls, review rounds per PR, first-pass CI, Important findings per PR, guard blocks, 7-day revert rate, time to merge. Counts are shown. Under 5 tasks or under 3 PRs the report says the sample is too small to conclude. PR columns come from read-only git and gh. If gh does not answer, those columns stay empty (--no-live skips the call).

agent-harness eval
agent-harness eval --run-model

agent-harness eval replays evals/tasks/*.yaml (bugfix, feature, refactor, test add, CI, docs, and the fix-ci skill trigger) in an isolated worktree and HOME, once per variant. The default mode calls no model: it checks the checkers and skill routing. --run-model requires AGENT_HARNESS_EVAL_CMD and runs one Cursor agent per task per variant (grok-4.7-medium, or AGENT_HARNESS_EVAL_MODEL). The shipped suite is 10 tasks × 2 variants, 20 sessions. Results join the same journal.

Mesurer les variantes

Conductor et Monolith s'observent avec le même journal. Le détail des champs est ci-dessus et dans docs/kpi-events.md. Les commandes sont les mêmes : agent-harness kpi report, agent-harness kpi feature, agent-harness eval.

What's inside

Counts below were recounted from this tree on 2026-11-06. The agent, command, and skill catalogs further down are the Conductor source. Monolith installs 9 agents and the same skills/ tree.

Powered by CodeMemory

CodeMemory indexes the repo into files, symbols, and episodes. One code-memory_codememory_retrieve call surfaces paths, symbols, and prior decisions. grep and read run afterwards for the exact lines.

Episodes persist across sessions. The codebase-exploration skill is the rule. code-memory_* tools are pre-allowlisted for the conductor and the specialist subagents in the Conductor tree. On Monolith the main agent and the installed reviewers use the same tools when CodeMemory is on. Cloud and remote agents skip it (docs/codememory-cloud.md). FMFLURRY_CODEMEMORY=on keeps it on.

Thing Count Notes
Agents (Conductor source) 26 1 conductor + 25 specialists. build and plan overrides ship with "disable": true
Agents (Monolith install) 9 Review and noisy output. See Variants
Skills 80 skills/*/SKILL.md. skill-creator/ is git-ignored and outside this count
Command templates 53 commands/*.md. 37 pinned in the opencode.jsonc command block
Instructions loaded 6 The instructions array in opencode.jsonc. 13 files sit in instructions/. caveman-ultra.md is not in the array
.claude rule files 17 6 pathless under rules/common/, 6 path-scoped under rules/common/, 5 under rules/typescript/
Hook scripts 21 .claude/hooks/*.sh
MCP servers 6 1 enabled (code-memory), 5 disabled by default
Custom tool files 4 run-tests, check-coverage, security-audit, plus the index.ts barrel
TUI plugins 2 Enabled in tui.json: panda-banner, autonomy-status. caveman.tsx.disabled is not loaded

Highlighted subagents. Full Conductor roster in Agents. On Monolith, names other than the nine installed agents are skills.

Name What it does Why it's good
conductor Primary orchestrator. write and edit denied on OpenCode Routing is in the permission block, and on Cursor the agent is readonly
planner Turns requests into phased plans Surfaces dependencies and risks before code is written
coder Writes and edits source code Application code stays inside a brief
tdd-guide Drives test-first cycles RED-GREEN-REFACTOR. Implementation goes to coder
code-reviewer Reviews diffs before merge Catches regressions and convention drift
security-reviewer Audits auth, secrets, and input Read-only findings. Fixes go to coder on Conductor, or to the main agent on Monolith
git-specialist Sequences atomic commits and PRs Cohesion-first splits, Conventional Commits
scout Maps the repo before a dispatch File manifests so briefs stay precise
comment-judge Judges added comments by rubric Flags false, stale, and noisy comments
postgres-dba Live PostgreSQL diagnostics Read-only advisory. Conductor only. Monolith uses database-reviewer or the main agent

Highlighted skills. Full catalog in Skills.

Name What it does Why it's good
socratic-design Spikes a short question, otherwise asks one Gates a decision before a plan
caveman Ultra-terse replies Keeps the technical content and spends fewer tokens
verify-this Falsifiable verification of a claim Green means fresh evidence
blast-radius Traces what a change can break Proves safety with real code
why Cites design rationale from history Searches source control and evidence MCPs in parallel
chimera Runs parallel candidates, grafts the best Avoids locking in the wrong shape early
humanizer Strips AI tells from prose Keeps writing sounding like a person wrote it
test-behavior-not-implementation Detects tests that cannot fail Catches mock-only and self-referential assertions
show-your-work Keeps a per-decision log Gives reviewers a trail for unattended runs
fix-ci Finds failing checks and fixes them Routes by failure type: build, test, or security
config-sync Propagates harness config changes Keeps the repo and the live directories in step
openspec OpenSpec workflow, one skill Propose, apply, archive, and the rest live under references/

Highlighted commands. Full list in Slash commands. On Monolith a folded agent name in a command is remapped: postgres-dba becomes database-reviewer, and every other folded name becomes main, which loads the matching skill (scripts/variants/dangling-agents.mjs).

Name What it does Why it's good
/plan Plan before code On Conductor this dispatches planner. On Monolith it loads the planner skill
/tdd Test-first cycle, or /tdd refactor to pin behavior Characterization tests pass immediately and stay frozen
/cop-review Pre-merge review of the branch Stack checklists, then lint
/security Security audit of the change Read-only findings
/git Branch and commit operations Keeps git work on the git rules
/build-fix Resolves build and type errors Loop until the build is green
/orchestrate Multi-agent coordination On Monolith this loads the conductor skill. It is optional
/verify Verification loop Checks the goal against concrete criteria
/db-health Read-only PostgreSQL health check Vacuum, wraparound, and connections. Conductor routes it to postgres-dba
/api-spec Generates OpenAPI 3.1 specs One spec per bounded context, Zalando-style

English

These catalogs describe the Conductor source tree at the repo root, unless a line says Monolith. The install default is Monolith. The cross-host picture is One harness, two variants, three hosts and How a request moves. Conductor ships a read-only conductor and 25 specialists. Monolith keeps 9 review agents and folds the other roles into skills.

Recent changes

Shipped on master through fa50d8e (2026-10-18). The plugin number is version in scripts/cursor-plugin/config.json. History is scripts/cursor-plugin/CHANGELOG.md.

PR Plugin What landed
#25 0.2.0 Semver guard in scripts/cursor-plugin/check.mjs. A plugin-source change must carry a version strictly above the base.
#27 0.3.0 CodeMemory stays off in cloud and remote sessions unless overridden. Ship review/fix rounds stop at 3.
#28 0.4.0 Review findings are Important, Nit, or Pre-existing. Only Important blocks. The verdict is Approve or Block.
#29 0.4.1 Enforcement ladder: code, then lint, tests, or static analysis, then a prose rule, then human review.
#30 0.4.2 A project's REVIEW.md is the tag reference when it exists. The PR template adds Risk, How to revert, and Tier.
#32 0.4.3 Always-applied Cursor rules drop from 21 files (1438 lines) to 7 files (502 lines). The rest load by path glob or by skill.
#33 0.4.4 create-verification-skill writes a project verify-this override from the repository's build, test, and e2e commands.
#35 0.4.6 socratic-design spikes a question a prototype under 30 minutes can settle, and presents that result. An L-sized task is restated in the agent's own words before planning.

Semver (#25, policy note in #29). scripts/cursor-plugin/check.mjs diffs plugin sources against the merge-base with the base branch (origin/master, origin/$GITHUB_BASE_REF in GitHub Actions, or CURSOR_PLUGIN_BASE). The version must be MAJOR.MINOR.PATCH and strictly greater, and the changelog needs a heading for it. The build copies scripts/cursor-plugin/config.json into plugins/fmflurry-harness/.cursor-plugin/plugin.json. A root README.md edit is not a plugin source. #25 shipped that guard at 0.2.0, with patch, minor, and major as the suggested bumps. From 0.4.1, scripts/cursor-plugin/CHANGELOG.md says later plugin changes bump the patch only. The guard does not enforce that: it still accepts a minor or major bump, and it still prints those suggestions.

CodeMemory (#27). FMFLURRY_CODEMEMORY=on|off|auto wins. Unset, auto, or any other value detects. Detection order is in docs/codememory-cloud.md, implemented in plugins/code-memory-lib/mode.ts and .claude/hooks/codememory-mode.sh:

  • CLAUDE_CODE_REMOTE truthy (true, 1, or yes), or CLAUDE_CODE_REMOTE_SESSION_ID non-empty: off.
  • Cursor metadata agent/runtime equal to managed, read with GET /v1/meta-data/agent/runtime on CURSOR_AGENT_SOCKET (default /run/cursor/api.sock): off.
  • CI: truthy GITHUB_ACTIONS, GITLAB_CI, CIRCLECI, or BUILDKITE, or a set TF_BUILD or JENKINS_URL: off. CI=true alone is ignored, because .claude/settings.json sets CI for every Claude Code session.
  • macOS (uname Darwin), and none of the signals above: on, even when the local services are down.
  • Otherwise both FalkorDB 127.0.0.1:6379 and Qdrant 127.0.0.1:6333 must accept a TCP connection, or CodeMemory stays off. A failed probe is "down", not an error.

Hooks and the OpenCode code-memory plugins no-op when the decision is off. FMFLURRY_CODEMEMORY=on keeps it on in the cloud. off keeps it off on a laptop.

Project memory. On by default. /memory-init (skill project-memory) scaffolds a short root AGENTS.md (about 80 lines at most) and docs/memory/: INDEX.md, contexts/<bounded-context>.md, immutable ADRs in decisions/NNNN-<slug>.md, and glossary.md. Each doc carries owner, reviewed, and refs frontmatter. A context file is read only when the task touches that bounded context (instructions/project-memory.md). agent-harness memory-lint (.claude/hooks/memory-lint.sh) fails on a missing owner or reviewed, a reviewed date older than 90 days, or a dead ref path or symbol. The ship stop gate adds its findings to the block reason. pr-report-check and the gh pr create hook run it, and require mémoire : màj or mémoire : aucun changement in the PR body when docs/memory exists. FMFLURRY_MEMORY=off turns it off.

Review tags (#28, #30). The default mapping is Finding tags in .claude/agents/code-reviewer.md. Important blocks the merge. Nit does not. Pre-existing does not, at any gravity. Approve means no Important finding is open (lint passes, and no forbidden comments). Block means at least one Important finding is open. There is no Warning verdict. scripts/cursor-plugin/check.mjs rejects the old uppercase review-severity words in harness sources. The allowlist for non-review uses (GDPR, database health, plan risk lines, npm audit, CVE) is scripts/cursor-plugin/review-tags.mjs. When the repository under review has a root REVIEW.md, that file is the only tag mapping. The reviewer cites it and does not apply the default table as a second mapping. This repo ships REVIEW.md.

Enforcement ladder (#29). .claude/rules/common/enforcement-ladder.md (Cursor copy plugins/fmflurry-harness/rules/enforcement-ladder.mdc) and instructions/enforcement-ladder.md (loaded from opencode.jsonc). Put the fix at the first level that can hold it: code, then lint, tests, or static analysis, then a prose rule, then human review. A prose rule carries why-not-tooled:. Adding always-on prose means deleting or shortening other always-on prose in the same change.

PR template (#30). .github/pull_request_template.md has Summary, Risk, How to revert, and Tier. Tier is T1, T2, or T3, from blast radius, protected paths, and diff size. It is not a finding tag. /setup-harness writes that template when .github/pull_request_template.md is missing and leaves an existing file alone (scripts/cursor-plugin/templates/setup-harness.md, built to plugins/fmflurry-harness/skills/setup-harness/SKILL.md). commands/pr.md and commands/create-pull-request.md fill the template when it exists. From 0.4.18 the template also has ## Visual report. The harness commits a show-me HTML file and a PNG at docs/pr-reports/<branch-slug>.html and .png, embeds the PNG, and links the HTML. .claude/hooks/pr-visual-report.sh blocks a gh or az body that omits the section. A docs typo or a version bump only may check Skip and state the reason. Conductor and Monolith share the pr-visual-report skill. agent-harness pr-report writes the files, agent-harness pr-report-links prints the section with absolute links pinned to the report commit (a relative link opens a compare page and is rejected from 0.4.33), and agent-harness pr-report-check checks a body.

Rules diet (#32). Plugin 0.4.3 (fa50d8e). plugins/fmflurry-harness/rules/ has 7 files with alwaysApply: true, 502 lines, down from 21 files and 1438 lines at 62aa030. At 0.4.3 they were autonomy.mdc, conductor.mdc, enforcement-ladder.mdc, orchestration.mdc, question-handling.mdc, tool-budget.mdc, and verification-gate.mdc. scripts/cursor-plugin/config.json rules.always lists the six common/ rules. The Conductor build adds rules/conductor.mdc. Plugin 0.4.19's default Monolith build replaces that file with rules/monolith.mdc and stubs the first-tool gate. There is no rules/always__harness.mdc in this build. The always-on count stays 7. File-bound rules stay in that directory with alwaysApply: false and globs: code-comments, coding-style, security, testing, and the five typescript-* packs. These left the always-on set and are skills: agent-roster, brief-contract, codebase-exploration, git-workflow, harness-parity, hooks, open-pr-check, patterns, performance, worktree-destruction-safety. skills/ai-ecosystem-audit/SKILL.md (Always-on budget) counts session-global rules. More than 8 alwaysApply: true Cursor rules is a confirmed finding.

Goals

  • Reproducibility: same agent behavior across machines/sessions.
  • Quality: on-demand TDD, frequent verification, centralized conventions.
  • Security: security-review skill available on demand + pre-tool-use hooks.

Repository layout

  • Configs: opencode.jsonc, dcp.jsonc (dynamic context pruning), tui.json (TUI theme).
  • Profiles: profiles/<name>/ (per-profile overrides + AGENTS.md).
  • Skills: skills/*/SKILL.md (plus auxiliary docs) — canonical set, shared with Claude Code via sync-skills.sh.
  • Agent prompts: prompts/agents/*.txt (26 files).
  • Slash commands: commands/*.md (53 templates; 37 pinned in opencode.jsonc, recounted 2026-11-06).
  • OpenCode plugins: plugins/<name>/index.ts + plugins/code-memory-lib/ + plugins/lib/ (with plugins/lib/kdco-primitives/).
  • TUI plugins: tui-plugins/*.tsx (registered in tui.json; autonomy-status.tsx is the autonomy sidebar panel).
  • Custom tools: tools/*.ts.
  • Mode notes: contexts/*.md.
  • Global instructions: instructions/*.md (6 loaded at session start; file-bound and situational docs are skills or unloaded instruction files).
  • Scripts: scripts/setup-package-manager.js, scripts/codemaps/generate.ts, scripts/settings-sync.sh, scripts/sync-skills.sh (sync canonical skill set to both harnesses), scripts/skill-drift-check.sh (read-only drift detector).
  • Install entry points: bootstrap.sh, bootstrap.ps1, install.sh, install-cursor.sh. ./install.sh --yes, settings-sync, and bootstrap.ps1 install Monolith when no variant is set. ./install.sh --local and ./install-cursor.sh default to Monolith. conductor selects Conductor. --variant and HARNESS_VARIANT override the default. orchestration is an alias of Conductor. A remote Claude Code session runs .claude/hooks/cloud-session-bootstrap.sh on SessionStart when CLAUDE_CODE_REMOTE=true and the project does not vendor the harness.
  • Claude mirror: .claude/CLAUDE.md, .claude/settings.json, .claude/hooks/, .claude/rules/, .claude/agents/, .claude/skills/ (synced from the canonical set on install), .claude/commands/.
  • Intentional exclusions (.gitignore): node_modules/, antigravity-*, .DS_Store, local .env* files except .env.example, runtime dir skills/skill-creator/ (not synced).

Configuration: opencode.jsonc

Six concerns wired in one file:

  1. instructions: always-on docs loaded at session start. Currently 6:
    • instructions/subagent-routing.md — Task-first subagent delegation gate.
    • instructions/question-handling.md — blocking vs non-blocking question protocol.
    • instructions/verification-gate.md — independent build/test verification before "done".
    • instructions/autonomy.md — destructive-action and autonomous-mode limits.
    • instructions/tool-budget.md — verification-vs-exploration budget.
    • instructions/enforcement-ladder.md — code, then lint or tests, then a prose rule, then review. File-bound guidance stays on disk and off this array: instructions/code-comments.md, instructions/coding-style.md, instructions/testing.md, instructions/security.md (the coder or tdd-guide prompt points at them). Situational guidance is a skill: open-pr-check, codebase-exploration, harness-parity, brief-contract, git-workflow, worktree-destruction-safety, performance, patterns, hooks, agent-roster.

    instructions/caveman-ultra.md sits in the repo but is not in the instructions array, so it isn't loaded at session start.

  2. default_agent: conductor (orchestrator-only — cannot write/edit).
  3. agent: 26 definitions (prompt + tool allowlist). No agent sets model, and the file sets no top-level model. Each agent uses the session model — see Changing models.
  4. command: maps /<name> -> template + sub-agent + subtask; 21 entries are pinned here.
  5. mcp: six servers — code-memory enabled; context7, blender, wallaby, Figma, smartbear-swagger disabled by default. code-memory_* perms are pre-allowlisted for every subagent.
  6. plugins: the npm plugin opencode-skill-creator. OpenCode 2 loads the local plugin folders under plugins/ on its own.

dcp.jsonc is the config stub for the optional external Dynamic Context Pruning plugin.

How the harness works today

This section describes Conductor. On Monolith the primary agent may write on the first edit, and /orchestrate loads the conductor skill. The picture for all three hosts is How a request moves. The interesting part of Conductor is the machinery that keeps a literal model on rails. Each rule lives in an instructions/ file loaded at startup.

1. The conductor cannot write

conductor has tools.write: false, tools.edit: false, and permission.edit/write: deny in opencode.jsonc. Its Task allowlist enumerates every legal specialist; *: deny blocks the rest. The orchestrator has no file-mutation tool — it must dispatch a task to coder, writer, tdd-guide, or git-specialist. instructions/subagent-routing.md adds a first-tool gate: if the request matches a specialist, the very first tool call must be that dispatch.

2. Agent selection at a glance

You want… Route to
A plan, risk list, or phased breakdown planner
Architecture / scalability / module boundaries architect
Non-test implementation coder
Docs, README, markdown, HTML, release notes writer
Diff / PR / current-change review code-reviewer
Tests and coverage tdd-guide (delegates impl to coder)
Build, typecheck, lint, or TS errors build-error-resolver
Git, commits, branches, pushes, PRs git-specialist
Security / auth / secrets / user input security-reviewer
GDPR / privacy / cookies / PII gdpr-specialist
Angular or .NET pre-merge review angular-cop / dotnet-cop
SQL / schema / migrations / RLS database-reviewer
Live PostgreSQL instance diagnostics postgres-dba
OpenAPI specs api-spec-architect
Unknown file scope for a brief scout
Dead code / duplication cleanup refactor-cleaner
Generated docs / codemaps doc-updater
E2E browser journeys e2e-runner
Harness / skill / agent parity audit ecosystem-auditor
Comment judging / purge comment-judge (purge via haruspex-commentorum)
Blender / 3D art gaudi (triggered-only)

3. Canonical flows

Most non-trivial work follows a fixed order, so planning, implementation, and review never collapse into one agent:

planner → (tdd-guide → coder) or coder → code-reviewer → verify → git-specialist

A feature goes planner → /tdd (RED) → coder (GREEN) → /verify → /pr → /cop-review → ship-merge.

A behavior-preserving refactor goes planner → /tdd refactor (characterization tests that pass immediately, then freeze) → coder (the restructure does not edit those tests) → /blast-radius → /verify (baseline against treatment on the same pin) → /pr → /cop-review → ship-merge.

A test-first variant routes tdd-guide first (RED), then tdd-guide delegates the GREEN implementation to coder, then code-reviewer, then the verification gate, then git-specialist. Docs-only work short-circuits to writer. A refactor routes tdd-guide in /tdd refactor mode first, so the characterization pin is green before any restructure.

4. The brief contract

Before dispatching coder, writer, or tdd-guide, the conductor emits a 6-field brief (the brief-contract skill): TASK (one imperative outcome), FILES (authoritative path + line ranges), CHANGE (named target state), DONE-WHEN (an executable command that must exit 0), OUT OF SCOPE, and CONTEXT ALREADY RESOLVED — plus a BUDGET. Precise briefs cost roughly 4× fewer tokens than open-ended ones, so this is enforced, not advice.

5. Question handling

Subagents that hit an ambiguity must tag their question [BLOCKING] or [NON-BLOCKING] (instructions/question-handling.md). Blocking questions stop the agent; the conductor tries to answer from the repo first, then asks the human. Non-blocking questions let work continue with a stated default and are batched and reported at the end of the job.

6. The verification gate

Nobody says "done" without fresh evidence (instructions/verification-gate.md). After any source edit, the agent detects the project type from manifests, runs the matching build/typecheck/lint command itself (subagent self-reports are not proof), runs the tests if behavior changed, and pastes the tail of the real output. Two failed fix passes on the same error → stop and escalate.

7. Tool budget

instructions/tool-budget.md separates verification commands (build, test, git state — uncapped) from exploratory shell (listing, grepping, file inspection — default 3 per dispatch). It nudges the model toward CodeMemory and targeted read ranges instead of full-file reads, and requires a one-line justification when the exploratory ratio runs high.

8. Worktree destruction safety

Removing a worktree is treated like rm -rf, not bookkeeping (the worktree-destruction-safety skill). The only removal path is agent-harness worktree-rm <path> --confirmed; without --confirmed it is a dry run that exits 3. It runs the pre-removal checks: git status --porcelain, commits not on the base branch, activity (fails closed when unknown; with the Orca app closed, lsof must show that no process has its working directory in the worktree, then removal goes through git), and every other checkout of the repo (main and sibling worktrees) clean or snapshotted. It lists the target's ignored files before removing. Snapshots are recoverable refs under refs/harness/snapshots/<ts>-<n> that capture tracked content, file modes, index state, and untracked files. In Orca-managed repos the removal goes through Orca, never with --force. The command then waits for the removal to finish, settles, and re-scans every other checkout; a change is reported as changed during removal. A changed checkout is restored only if its HEAD is unchanged and it is clean. Otherwise exit 4 with inspect and restore commands, refs kept. On success each snapshot sha is printed before its ref is released. Not covered: ignored files, untracked nested git repositories (reported as a note), and submodule contents. Any failed check is a hard stop reported to the human. The guard denies raw orca worktree rm, git worktree remove|prune|move (including global options and aliases), and recursive rm/mv/trash/rsync --delete/find -delete on a worktree or its parent, in every mode. It is text matching and cannot catch commands assembled at run time; the script's checks are the real boundary. git worktree prune -n stays allowed. In autonomous mode, agent-harness worktree-rm <path> --confirmed removes a worktree that is clean and whose branch is merged into the default branch (tip reachable, trees equal, or gh pr view --json state is MERGED). It refuses a dirty worktree, unmerged work, the main checkout, and a path that is not a worktree of the repo, and the message names the reason. Raw git worktree remove stays denied. With autonomy off, a squash-merged branch that is still ahead of origin/<base> is still refused. agent-harness teardown-merged-worktree <pr> removes the registered goal worktree of a MERGED PR in autonomous mode and also deletes that goal's branches and registry. It re-runs the checks against the PR head (not an origin/<base>..HEAD count, because squash merges rewrite history), never uses --force, and keeps the registry when a step is partial. Goal worktrees are created by agent-harness ship-init and registered in <git-common-dir>/agent-harness/goals/<slug>.json.

9. Codememory-first

When the code-memory MCP server is connected and CodeMemory is on, its tools are the mandatory first choice for search, callers, definitions, importers, and dependencies (the codebase-exploration skill). grep/glob/bash are fallbacks only — raw listing, filename globs, or a known path region. Cloud and remote agents skip CodeMemory (docs/codememory-cloud.md). This is the rule that makes orientation cheap for every other agent.

Hardened sub-agent orchestration

Delegation is enforced at two layers, so the same behavior holds whether the primary model is Claude, GPT, DeepSeek, or any open-weight runner that ignores prose hints:

  1. Permissions — conductor has tools.write: false, tools.edit: false, and permission.edit/write: deny in opencode.jsonc. The Task allowlist enumerates every legal specialist; *: deny blocks anything else. The orchestrator literally has no file-mutation tool.
  2. Guard plugins + front-loaded prompt — plugins/secret-file-guard/index.ts aborts any read/bash access to a secret-bearing .env file; plugins/tool-budget/index.ts nudges verification over exploration (it never blocks a call). prompts/agents/conductor.txt puts hard rules in the first lines, the routing table second, and six worked few-shot examples showing User → task calls with explicit wrong-way contrasts; instructions/subagent-routing.md enforces a Task-first gate before direct inspection.

Use these paths depending on how much control you want:

  • Plain request: conductor consults the routing table and dispatches the matching specialist via Task.
  • @agent mention: manually invokes a specific subagent in the conversation.
  • Slash command: forces a subtask with a configured template, e.g. /plan, /tdd, /security.

Why this exists: GPT/Claude often infer delegation from short descriptions, but open-source/open-weight models are more literal and tend to inspect or edit first. Permissions + the front-loaded gate make delegation mechanically enforced rather than instruction-dependent.

Agents

This table is the Conductor roster, defined in opencode.jsonc under agent — 26 entries: the primary plus 25 subagents. build and plan are built-in overrides and ship disabled.

Monolith does not install this roster. It keeps 9 agents. The main agent coordinates and may write. /orchestrate loads the conductor skill.

Agent Access Role Trigger notes
conductor read-only Primary orchestrator. write/edit denied; every change routed via Task. Default agent — always on
planner read-only Plan + risks + phased order before large changes. No edit. Complex features, unclear order
architect read-only System design, scalability, cross-module boundaries. High-impact design decisions
coder writable Pure non-test implementation. Build+lint+standards self-check before reporting. Socratic ambiguity gate. Any source-code change
writer writable Docs/markdown/HTML/text artifacts. Refuses source files. Prose, README, ADRs, reports
code-reviewer read-only General diff/PR review. Findings only; fixes go to coder. Owns /cop-review. Review requests
comment-judge read-only Rubric verdict on added/changed comments; REVIEW (diff) or PURGE (directory). Emits JSON. Comment review / purge
haruspex-commentorum writable Comment-deleting purge agent. Applies agreed verdicts. Triggered-only by purge flow
ecosystem-auditor read-only Evidence-first audit of OpenCode/Claude parity and harness coherence. /ecosystem-audit, parity checks
angular-cop read-only Angular + TypeScript pre-merge review (signals, RxJS, flurryx, TS strict). Runs tsc + lint. Angular PR review
dotnet-cop read-only .NET 10 Minimal API review (ports/adapters, modular isolation, EF Core). Runs build + dotnet format. .NET PR review
gdpr-specialist read-only GDPR/CNIL compliance review (consent, cookies, PII, retention, transfers, 72h breach). Privacy-sensitive features
security-reviewer read-only OWASP/secrets/deps review. Reports vulnerabilities; fixes routed to coder. Auth, input, endpoints, secrets
tdd-guide writable (tests) RED → GREEN → REFACTOR + 80% coverage. /tdd refactor pins current behavior with characterization tests that already pass. Delegates impl to coder. New features, bug fixes, refactors
build-error-resolver writable Fixes build/typecheck/lint/TS errors with minimal diffs. Red build or lint
e2e-runner writable E2E tests from the project override or a discovered runner. Browser journeys
doc-updater writable Generated docs + codemaps. /update-docs, /update-codemaps
refactor-cleaner writable Dead-code removal + consolidation, behavior preserved. Cleanup requests
database-reviewer read-only PostgreSQL/Supabase schema, query perf, RLS, migrations. SQL/migration/schema review
postgres-dba read-only Live instance ops: health, vacuum/bloat, WAL, backups/PITR, pooling, upgrades. Emits human-confirmed commands. /db-health, /db-backup-check
api-spec-architect writable Zalando-compliant OpenAPI 3.1 specs; optional SwaggerHub publish. /api-spec
git-specialist writable (git) Branches, staged commits, pushes, PRs. Git/commit/PR tasks
scout read-only Emits a file manifest for an unknown scope before a brief. Triggered-only by conductor
why-investigator read-only Investigates one evidence category for design rationale. Triggered-only by why skill
why-synthesizer read-only Merges investigator findings into one evidence-weighted answer. Triggered-only by why skill
gaudi writable Blender / 3D art: modeling, materials, lighting, render, glTF export. Drives the Blender MCP. Triggered-only (3D work)

Session model. No agent in opencode.jsonc sets model, and the file sets no top-level model. A primary agent uses the model selected for the session. A subagent uses the model of the agent that invoked it (OpenCode agents). A Monolith install is the same: the generator does not write model.

OPENCODE_REASONING_* is not written either. Those variables were only exported to the shell. opencode.jsonc never interpolated them. Reasoning fields on a myMistral model entry describe that provider. They do not select a model for the session.

To pin one agent, set model on that agent in your own OpenCode config. A reinstall of this harness does not add a pin.

Slash commands

53 templates live in commands/ (recounted 2026-11-06). 37 are pinned in the opencode.jsonc command block. That block is the Conductor set. Monolith remaps a folded agent: postgres-dba becomes database-reviewer, and every other folded name becomes main, which loads the matching skill (scripts/variants/dangling-agents.mjs). Many pinned commands set subtask: true. OpenCode reads the pinned block; whether it additionally auto-discovers commands/ is something this repo cannot prove, so treat unpinned entries as Claude-side or discovery-dependent.

Pinned (37):

Command Sub-agent Purpose
/git git-specialist Bounded git ops (branches, commits).
/push-changes git-specialist Commit + push with upstream guard.
/plan planner Implementation plan.
/tdd tdd-guide TDD cycle. /tdd refactor pins current behavior.
/api-spec api-spec-architect OpenAPI 3.1 spec generation.
/cop-review code-reviewer Direct pre-merge review; selects stack guidance.
/security security-reviewer Security audit.
/gdpr-review gdpr-specialist GDPR/CNIL compliance audit.
/build-fix build-error-resolver Build/TS error resolution.
/e2e e2e-runner E2E tests from the project override or discovered runner.
/refactor-clean refactor-cleaner Dead-code cleanup.
/orchestrate planner Multi-agent orchestration.
/verify (conductor) Verification loop.
/eval (conductor) Evaluate against criteria.
/update-docs doc-updater Doc updates.
/update-codemaps doc-updater Generates docs/CODEMAPS/.
/test-coverage tdd-guide Coverage analysis.
/skill-create no agent key Generate a skill from git history. Runs as the default agent.
/db-health postgres-dba Read-only PostgreSQL health battery.
/dependabot-friday git-specialist Dependabot PR triage (report-only).
/db-backup-check postgres-dba Backup/PITR posture audit.
/ship conductor One goal from clarify through merge.
/autonomous conductor Turn autonomous mode on, off, or show status.
/pr git-specialist Open a pull request from the repo template.
/memory-init writer Scaffold split project memory.
/show-me writer Offline HTML diagram and PNG screenshots.
/show-your-work conductor TSV decision trail.
/comment-judge comment-judge Rubric verdict on comments.
/interfectio-commentarum conductor Haruspex comment-purge flow.
/for-real conductor Restate the last message in plain language.
/why conductor Cited design rationale.
/blast-radius conductor What a change can break, from running code.
/chimera conductor Parallel candidates, then graft.
/fix-ci conductor Fix failing pull-request checks.
/loop-on-ci conductor Watch checks and iterate fixes.
/get-pr-comments git-specialist Summarize review comments on the active PR.
/fix-merge-conflicts git-specialist Rebase through conflicts.

Unpinned templates (16) — available in commands/, plus Claude-side/OpenSpec helpers:

/checkpoint, /pm2, /setup-pm, /ecosystem-audit, /create-pull-request, and the OpenSpec family /opsx-{new,ff,continue,apply,verify,archive,bulk-archive,sync,explore,propose,onboard}.

Claude-only: .claude/commands/ adds arena.md and arena-new-prompt.md (the arena/chimera flow) plus the OpenSpec command dir — those are not pinned for OpenCode.

Skills

Recounted 2026-11-06: skills/*/SKILL.md is 80 skills. The groups below name that set. Twelve of them sit in the last bullet, outside the older groups. skill-creator/ is git-ignored and outside the 80. scripts/sync-skills.sh computes the canonical union (root skills/ ∪ .claude/skills/, root wins on conflicts), excludes the runtime dir skills/skill-creator/, and copies into both harness targets. Attribution for vendored skills lives in skills/THIRD_PARTY_NOTICES.md. Attack-class references in skills/security-review/references/ are verbatim copies from cloudflare/security-audit-skill at c1c8a8c1471069fb0e188eeaff69b8e8db6564a8 (MIT, Copyright (c) 2025-2026 Cloudflare, Inc.). The license text is LICENSE-cloudflare-security-audit.

  • Planning & design (5): socratic-design, chimera, api-spec-openapi, why, blast-radius.
  • Review & quality (6): comment-judge, interfectio-commentarum, verify-this, create-verification-skill, test-behavior-not-implementation, ai-ecosystem-audit.
  • TDD & testing (3): tdd-workflow, tdd, e2e.
  • CI & git (5): fix-ci, fix-merge-conflicts, get-pr-comments, loop-on-ci, git-workflow.
  • Angular (4): angular-clean-architecture, angular-ddd, angular-cop, angular-accessibility.
  • .NET (3): dotnet-clean-architecture, dotnet-ddd, dotnet-cop.
  • Three.js / 3D (1): threejs, with the ten topics under references/.
  • PostgreSQL playbooks (4): postgres-health-check, postgres-performance-tuning, postgres-backup-restore, postgres-container-ops.
  • Playwright E2E (2): playwright-e2e-authoring, playwright-e2e-review.
  • OpenSpec workflow (1): openspec, with the eleven workflows under references/.
  • Writing & communication (7): humanizer, for-real, caveman, caveman-commit, caveman-review, show-me, show-your-work.
  • Harness & config (5): config-sync, harness-parity, skill-authoring, treetopia, strategic-compact.
  • Security (1): security-review.
  • Compliance (1): gdpr-compliance.
  • Domain (2): flurryx, transloco.
  • Universal standards (1): coding-standards.
  • On-demand role skills: planner, coder, writer, doc-updater, architect, refactor-cleaner, scout, gaudi, testing, security, coding-style, code-comments, autonomy, question-handling, enforcement-ladder, tool-budget, verification-gate. Monolith loads these in the main loop. Conductor still has the matching agents.
  • Also in the tree (12): agent-roster, autonomous, brief-contract, codebase-exploration, hooks, open-pr-check, patterns, performance, project-memory, pr-visual-report, ship, worktree-destruction-safety.

The PostgreSQL and Playwright sets are gc.platform-specific project playbooks, not general-purpose skills — read them alongside the postgres-dba agent. /e2e and e2e-runner do not assume that stack. They read e2e.json or discover the start command, ports, and runner (skills/e2e). Load playwright-e2e-authoring and playwright-e2e-review only when that override names them. A project sets "enabled": false to opt out. Consumers that do not want the playbooks omit those two skills when vendoring.

skill-creator is a runtime-only skill: it is git-ignored (skills/skill-creator/) and never synced. opencode-skill-creator (npm) provides the same capability at runtime.

Instructions & rules

6 session-start instructions (listed in Configuration) are the operating rules every agent loads: subagent routing, question handling, the verification gate, autonomy, the tool budget, and the enforcement ladder.

The Claude Code side keeps the same six as pathless rules under .claude/rules/common/, plus path-scoped rules for code comments, coding style, security, and testing, and five rules/typescript/ packs. Domain text that is not file-bound lives in skills (codebase-exploration, brief-contract, git-workflow, worktree-destruction-safety, performance, patterns, hooks, agent-roster, open-pr-check, harness-parity).

Two top-level instruction files, distinct jobs:

  • Root CLAUDE.md — behavioral guidelines for Claude Code agents (think before coding, simplicity, surgical changes, goal-driven execution, verification gate, delegation, destructive-action safety, tool hygiene). Project rule packs feed into it via @rules/... imports.
  • .claude/CLAUDE.md — the global user instructions installed into ~/.claude, carrying the cross-project essentials (no any, facade-not-UseCase).

Plugins & hooks

The plugins are OpenCode 2 folder plugins built with @opencode/plugin@2.2.7 (plugins/<name>/index.ts, Plugin.define). OpenCode loads every folder in plugins/; plugins in opencode.jsonc names only the npm plugin opencode-skill-creator.

  • plugins/secret-file-guard/index.ts — hard-blocks read/bash access to secret-bearing .env files; .env.example/.sample/.template stay readable.
  • plugins/mistral-affinity/index.ts — attaches a stable x-affinity header to Mistral / Mistral-compatible provider calls for cache affinity.
  • plugins/tool-budget/index.ts — nudges the model toward verification over exploration via the system prompt (never blocks a tool call).
  • plugins/code-memory/index.ts + plugins/code-memory-lib/ — CodeMemory auto-retrieve / auto-learn nudges (no-op when the code-memory CLI is absent).
  • plugins/lib/ (with plugins/lib/kdco-primitives/) — shared utilities (mutex, shell, terminal-detect, project-id resolver, types).
  • opencode-skill-creator (external npm, declared in opencode.jsonc › plugin) — skill scaffolding and benchmarking.
  • plugins/kpi/index.ts — OpenCode side of the KPI journal. Records session boundaries, skill names, subagent types, and tool results.
  • plugins/autonomy/index.ts — OpenCode side of autonomous mode. See Autonomous mode.
  • plugins/domain-rules/index.ts — off unless .harness-local/domain-rules.json opts in. Runs before write, edit, patch, and multiedit.
  • Not loaded: plugins/ecc-hooks.ts.disabled, plugins/worktree.disabled, plugins/figma-rag.md, and tui-plugins/caveman.tsx.disabled ship disabled and are skipped by the loader.

Claude-side hooks (.claude/hooks/, 21 scripts, recounted 2026-11-06): notification.sh, pre-tool-use.sh, prefer-code-memory.sh, rtk-rewrite.sh, stop.sh, subagent-stop.sh, tool-budget.sh, autonomy-ask-guard.sh, autonomy-context.sh, autonomy-git-guard.sh, cache-invalidation.sh, cloud-session-bootstrap.sh, codememory-mode.sh, commit-provenance.sh, domain-rules.sh, goal-state.sh, kpi-emit.sh, memory-lint.sh, orca-notify.sh, pr-visual-report.sh, ship-stop-gate.sh.

Custom tools (tools/)

Reusable OpenCode tools exposed via tools/index.ts:

  • tools/run-tests.ts — detects package manager + framework and builds the test command.
  • tools/check-coverage.ts — reads coverage reports and compares against a threshold.
  • tools/security-audit.ts — scans deps + secrets + risky patterns.

(tools/index.ts is the barrel that re-exports them.)

TUI plugins

  • tui-plugins/panda-banner.tsx — SolidJS banner that renders a panda ASCII/block-art header.
  • tui-plugins/autonomy-status.tsx — sidebar capsule for autonomous mode, registered in tui.json. Behaviour is under Autonomous mode.

Claude Code mirror (.claude/)

  • CLAUDE.md — global user instructions (no any, facade != UseCase).
  • settings.json — allow/deny permissions, env (API_TIMEOUT_MS=3000000, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1, CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80), "model": "opus" for the Claude Code main agent, and PreToolUse / PostToolUse / Stop hooks. Conductor and Monolith share this file. Seeded on first install into ~/.claude and into a project's .claude. A model value already set is preserved on reinstall.
  • hooks/*.sh — 21 scripts. The names are under Plugins & hooks.
  • rules/common/*.md + rules/typescript/*.md — 17 files (recounted 2026-11-06). Six under rules/common/ have no paths: key. Six under rules/common/ are path-scoped (code-comments, coding-style, security, testing, cache-invalidation, project-memory). Five rules/typescript/ packs stay path-scoped. Patterns, hooks, and the agent roster are skills.
  • agents/*.md — 26 agent definitions mirroring the OpenCode roster.
  • commands/*.md — Claude commands (/create-pull-request, /update-codemaps, arena, OpenSpec).
  • skills/** — the skill mirror, synced from the canonical set by scripts/sync-skills.sh on install. It is not guaranteed to equal today's skills/ (the canonical set grows between syncs), so treat skills/ as the source of truth and run settings-sync --skills-only to catch the mirror up.

Sync & update

Two directories, one source of truth. The lab is wherever you cloned this repo; the live config dirs are ~/.config/opencode and ~/.claude. Nothing here watches the filesystem — you pull, then sync.

  • install.sh merges additively and never deletes user config. Re-running is safe and idempotent: it refreshes deps, re-merges repo files, and rewrites the marker-fenced env block.
  • scripts/settings-sync.sh is the "from anywhere" command — settings-sync resolves the repo (via SETTINGS_OPENCODE_REPO or well-known clone paths) and runs a full install; settings-sync --skills-only runs the fast skills path; --where prints the resolved repo path.
  • scripts/sync-skills.sh computes the canonical skill union and copies it into every active harness target. installers call it; you can run it standalone.
  • scripts/skill-drift-check.sh is a read-only drift detector: it hashes every copy of a skill across the known roots (repo .claude/skills, .opencode/skills, ~/.config/opencode/skills, ~/.claude/skills) and exits non-zero when two copies of the same skill diverge. Also compares the kept-overlap instruction topics.
  • The config-sync skill is the agent-facing version of the same job: edit an agent/rule/skill here, and it propagates the change across harness dirs.
  • install-cursor.sh builds the Cursor plugin (node scripts/build-cursor-plugin.mjs -> plugins/fmflurry-harness/) and copies it to ~/.cursor/plugins/local/fmflurry-harness; then run Developer: Reload Window in Cursor. The default build is Monolith: the primary agent may write, there is no first-tool gate, and /orchestrate is optional. ./install-cursor.sh --variant conductor (or HARNESS_VARIANT=conductor ./install-cursor.sh) builds Conductor. ./install-cursor.sh --status prints the variant stored in the plugin's .harness-variant. It also installs the agent-harness CLI, using the same helper as install.sh: scripts go to ~/.local/share/fmflurry-harness/scripts/agent-harness and the wrapper is ~/.local/bin/agent-harness. Re-running prints those paths and does not add a second command. Flags: --yes, --link (symlink instead of copy), --migrate-legacy (back up then remove what the old installer copied into ~/.cursor, keeping your own entries), --uninstall, --no-backup, --variant, --status. Limits: no per-agent tool allowlist, delegation by instruction only, Notification hooks unsupported. Tier defaults stay Cursor models: grok-4.7, grok-4.6, and composer-2.5.

Parity phrasing: the two harnesses are synced on install. Recounted 2026-11-06, skills/ holds 80 skills and the shipped .claude/skills/ mirror holds 41. Run settings-sync --skills-only (or scripts/sync-skills.sh) to reconcile, and scripts/skill-drift-check.sh to confirm.

Cursor plugin version

The installed manifest version is version in scripts/cursor-plugin/config.json (0.4.36 in this tree). node scripts/build-cursor-plugin.mjs copies it into plugins/fmflurry-harness/.cursor-plugin/plugin.json and copies scripts/cursor-plugin/CHANGELOG.md into the plugin. node scripts/cursor-plugin/check.mjs fails if those version fields differ or if the changelog has no heading for the current version. The marketplace entry has no version field. Root package.json versions the settings repo (GitHub releases), not this plugin.

Bump that version by hand in each PR that changes plugin content or its build inputs:

  • patch — fixes, chores, and doc tweaks to plugin content
  • minor — new agents, skills, commands, rules, or behavior
  • major — breaking changes: renamed or removed agents or skills, changed tier keys, installer contract changes

From plugin 0.4.1, scripts/cursor-plugin/CHANGELOG.md asks for a patch bump on every later plugin change. The check still only requires a version strictly above the base. It does not reject a minor or major bump.

The check diffs the working tree against the merge-base with the base branch, so a root README edit does not need a bump. The version it must exceed is the base branch tip: origin/master locally, origin/$GITHUB_BASE_REF in GitHub Actions (the workflow fetches that ref), or CURSOR_PLUGIN_BASE when set. If none of those refs exist, the check prints a skip message and continues.

Plugin sources are plugins/fmflurry-harness/, the .claude agents, commands, rules, skills, CLAUDE.md, settings.json, and the hook scripts named in hooks.include, plus skills/, commands/, opencode.jsonc, scripts/build-cursor-plugin.mjs, scripts/sync-skills.sh, and the cursor-plugin config, library, changelog, README template, adapter, setup-harness template, and logo. scripts/cursor-plugin/check.mjs does not ship in the plugin.

bump the plugin version + changelog in any PR touching plugin sources.

How it fits together

The lifecycle for both variants is How a request moves. The four steps below are the OpenCode startup path when the installed variant is Conductor.

  1. Startup: OpenCode loads opencode.jsonc -> 6 always-on instructions -> auto-loads every plugin in plugins/ plus the TUI plugins registered in tui.json. Skills load when their description matches.
  2. Dev: conductor executes — it cannot write files; it dispatches Task calls to specialists. secret-file-guard blocks .env access; tool-budget nudges verification over exploration.
  3. Workflow: conductor routes to specialists through Task (perm-enforced); /plan, /tdd, /security, etc. force the same routing explicitly. The brief contract, question protocol, and verification gate bracket each hand-off.
  4. Idle: the autonomy plugin runs the stop gate and sends the idle notification.

Autonomous mode

Autonomous mode lets the agent take one goal from clarification to a merged PR. Turn it on, then run /ship <goal>. With the flag off, the agent asks before each irreversible step, and a merge needs --confirmed. Turning the flag on does not start work (skills/autonomous/SKILL.md).

The run is a loop, owned by skills/ship/SKILL.md: implement, verify, local review, push and open the PR, CI, then agent-harness ship-merge. A blocker the agent can fix (a confirmed Important finding, a failing check, a conflict, a stale branch, an unresolved thread, a merge refusal) sends it back to fix, then local review again, then push, CI and the merge retry. It ends as done (the PR is merged and the goal worktree is torn down) or escalated.

How to launch it. The goal text is the argument of /ship. The flag is also agent-harness autonomy on|off|status (scripts/agent-harness/autonomy.sh). install.sh installs that wrapper at ~/.local/bin/agent-harness when Claude Code or OpenCode is an install target. install-cursor.sh installs that same wrapper, pointing at ~/.local/share/fmflurry-harness.

  • Claude Code. There is no .claude/commands/ship.md. /ship <goal> is the ship skill, skills/ship/SKILL.md. install.sh runs scripts/sync-skills.sh, which copies it to ~/.claude/skills/ship. /autonomous on|off|status is skills/autonomous/SKILL.md (disable-model-invocation: true, so it stays user-invoked). The behaviour rule is .claude/rules/common/autonomy.md. The Stop hook is .claude/hooks/ship-stop-gate.sh, wired from .claude/settings.json.
  • OpenCode. /ship and /autonomous are pinned in opencode.jsonc (command.ship, command.autonomous), both on conductor, templates commands/ship.md and commands/autonomous.md. The startup rule is instructions/autonomy.md. plugins/autonomy/index.ts blocks the question tool, injects autonomy context, denies forbidden git commands, and re-prompts the root session when the stop gate blocks. The sidebar toggle is tui-plugins/autonomy-status.tsx (registered in tui.json): command palette "Toggle autonomous mode", /autonomy-toggle, or <leader>u.
  • Cursor. /ship <goal> is plugins/fmflurry-harness/commands/ship.md (built from commands/ship.md by scripts/build-cursor-plugin.mjs). It loads plugins/fmflurry-harness/skills/ship/SKILL.md. /autonomous is plugins/fmflurry-harness/commands/autonomous.md and plugins/fmflurry-harness/skills/autonomous/SKILL.md. The always-on rule is plugins/fmflurry-harness/rules/autonomy.mdc. The stop entry in plugins/fmflurry-harness/hooks/hooks.json runs hooks/scripts/ship-stop-gate.sh. That hook calls agent-harness from PATH. install-cursor.sh installs that command at ~/.local/bin/agent-harness.

Review loop. Stage 6 of skills/ship/SKILL.md reviews git diff <base>...HEAD with code-reviewer, security-reviewer, and the stack cop when it applies (angular-cop or dotnet-cop; database-reviewer when SQL changed). The agent confirms each finding against the code. Only a confirmed Important finding blocks. Nit and Pre-existing do not. Tags come from the repo's REVIEW.md when it exists, otherwise from Finding tags in .claude/agents/code-reviewer.md. Each verdict is recorded with agent-harness goal review code|security pass|fail. The push guard (.claude/hooks/autonomy-git-guard.sh) denies git push and gh pr create while an active goal has no passing code and security verdict for the exact diff (a hash of the diff against origin/<base>, ignoring docs/agent-reports/); pushes to backup/* and the report commit are not gated. After the PR is opened it posts one summary comment (skills/ship/references/review-format.md). That comment is an audit trail. ship-merge does not read it. Every later CI or comment fix is reviewed locally before its push.

Repeated findings. Before each fix round the skill pipes the confirmed findings (<reviewer>:<path> or ci:<check>, one per line) to agent-harness goal bump. It normalises them (lowercase, line numbers stripped, sorted, deduplicated) and fingerprints the set. When the fingerprint equals the previous round's, the command marks the goal escalated (no progress), runs agent-harness notify failure, and exits 3. goal.sh and ship-init.sh also set a safety ceiling of max_fix_iterations 10. Empty stdin exits 2. The same bump is used before a CI fix round (stage 9 of skills/ship/SKILL.md).

No-progress rule. Two checks share the name. They are not the same test.

  • skills/ship/SKILL.md (Stop conditions) treats a full loop iteration as no progress when the same Important finding and the same failure remain, or the same non-review blocker fails the same way. A new failure, a new finding, or a green check counts as progress. The agent then runs agent-harness goal escalate. For review findings goal bump also compares a fingerprint of the findings between rounds.
  • .claude/hooks/ship-stop-gate.sh (Cursor copy: plugins/fmflurry-harness/hooks/scripts/ship-stop-gate.sh) counts a stop as no progress only when nothing moved: the PR head, the registered worktree branch tip, .reviews, and fix_iterations. Five consecutive empty stops escalate with no progress after 5 stop blocks. Any of those changes resets stop_blocks to 0. Every counted stop increments total_blocks, and 30 total blocks escalate even when the last stop was progress. Stops are not counted during agent-harness goal wait "<reason>" --ttl 30m (max 24h), or while the hook input, a live pid, an inflight marker, or a test or review process in the worktree shows background work. Before both verdicts pass for the current local tip, the block says to finish local review. After both pass and there is no PR, it says to push and open the PR. While the goal is active and the PR is unmerged, the hook blocks an early stop. If GitHub cannot be read, the hook exits 0 and does not count the stop. OpenCode has no Stop hook. plugins/autonomy/index.ts runs the same script on session.idle of a root session, passes running child sessions, and re-prompts with the reason (instructions/autonomy.md). Conductor and Monolith use this hook.

When it escalates. skills/ship/SKILL.md (Human-only) stops for missing credentials, account limits or billing, an external outage, a product decision the repo cannot answer, or an action on the forbidden list. It also stops on the skill's no-progress rule, on goal bump exit 3, and on the stop-gate caps above. A gitleaks finding or a secret exposure stops the run for security-reviewer and rotation. An open-PR outcome of Wait or cancel escalates (skills/open-pr-check/SKILL.md). The blocked path keeps the worktree, the branch, and the registry (skills/ship/SKILL.md, Blocked path).

What it never does. Hard limits in skills/ship/SKILL.md, and rule (d) in .claude/rules/common/autonomy.md:

  • Merge only through agent-harness ship-merge. Never gh pr merge, and never a push to the base branch.
  • Never git push --mirror, git push --all, or --no-verify. Never weaken a check: skip a test, a job, or a required check, set continue-on-error, delete a check, or lower a threshold.
  • Never remove a worktree with raw git worktree remove. agent-harness worktree-rm <path> --confirmed removes a clean worktree whose branch is merged (including a squash merge detected by gh pr view --json state). agent-harness teardown-merged-worktree <pr> removes the registered goal worktree after that PR is MERGED, in autonomous mode, and deletes its branches and registry. Never delete a branch except through that teardown, agent-harness cleanup, agent-harness prune-backups for leftover backup/* branches, or agent-harness prune-branches for merged local branches nothing claims.
  • Never merge a PR that matches protectedPaths while the flag is on. A human passes --confirmed.
  • Never add a label, post a comment, or create a status to get past a ship-merge refusal.
  • Never notify for progress. The run does not trigger builds or releases.
  • Never tear down a blocked or escalated goal.
agent-harness autonomy on|off|status     # toggle .claude/state/autonomy.on (gitignored, per machine)
/ship <goal>                             # clarify, implement, PR, review, CI, merge
agent-harness ship-merge <pr> [--method squash|rebase|merge]  # the only merge path; add --confirmed in interactive mode
agent-harness notify done "<msg>" <pr>   # notify on question, waiting, done, failure only
agent-harness ship-init <type> <scope> <desc> --goal "<text>"  # first action of /ship: goal worktree + registry (or --adopt <pr>)
agent-harness goal decisions-path        # this checkout's decision log: .claude/state/decisions/<slug>.tsv per goal (created by ship-init, archived to decisions/archive/ by teardown), else .claude/state/decisions.tsv
agent-harness teardown-merged-worktree <pr>  # after MERGED: remove the registered goal worktree, branches and registry (run by ship-merge)
agent-harness cleanup <pr> [--keep-branch] [--no-checkout]  # after MERGED: delete the PR's head branch and goal backups (unregistered PRs; also run by ship-merge; teardown passes --no-checkout)
agent-harness prune-backups [--confirmed]  # leftover backup/* branches no goal or registry lists: delete those in origin/<base>, archive the rest under refs/harness/backups/ (dry run without --confirmed)
agent-harness prune-branches [--confirmed]  # local non-backup branches already in origin/<base> that no goal, registry entry, worktree or HEAD claims: delete them; never remotes (dry run without --confirmed)

Another repo. ship-init, ship-merge, cleanup, teardown-merged-worktree, worktree-rm and goal take a trailing --repo <absolute path>, so a session whose working directory is repo A can manage a goal of repo B without Orca: agent-harness ship-init feat ui x --goal "..." --repo /abs/path/to/B. The path must be the top level of a git checkout: B's main checkout, or a goal worktree of B for goal. A relative path, a subdirectory, a non-git directory, or --repo anywhere but last is refused. The goal registry and goal state are B's. The calling session's stop gate still reads its own checkout, so it neither blocks on nor binds to B's goal. ship-init --repo leaves a per-user marker under ~/.agent-harness/goals-foreign/. While B keeps goal files, every session's git guard sends every push through the full check, which gates a push into B's goal worktree by B's own reviews. The guard allows exactly that trailing shape as one plain command. A cd prefix, an env prefix such as CLAUDE_PROJECT_DIR=, and substitution stay denied.

The ship skill (skills/ship/) owns the stages, and the autonomous skill runs the toggle. The behaviour rules are in .claude/rules/common/autonomy.md (Claude Code) and instructions/autonomy.md (OpenCode).

OpenCode. plugins/autonomy/index.ts enforces the flag: it blocks the question tool, injects autonomy context, denies forbidden git commands, and re-prompts the session when the stop gate blocks. The toggle state (.claude/state/autonomy.on, goal.json) is shared with Claude Code, so toggling in either harness toggles both. Toggle from the command palette ("Toggle autonomous mode"), with /autonomy-toggle, or with <leader>u.

Status panel. tui-plugins/autonomy-status.tsx (registered in tui.json) shows an ● AUTONOMOUS or ○ manual capsule in the session sidebar, then the goal with PR #n, fix i/max, and the status (escalated: <reason>; omitted while active). It refreshes every 3 s and raises a toast on each transition.

Per-repo config. Each repo can set .claude/agent-harness.json. Every key is optional:

Key Default when absent Purpose
base the repo default branch (gh repo view) PR base and the only merge target
requiredChecks [] check-run names that must conclude success, skipped or neutral on the head
reviewStatus unset (no rail) optional. Set it only when the repo has an external status check. The commit status context that must be success on the head
reviewStatusCreator unset (any creator) optional, used with reviewStatus. Login that must have posted the status
verify unset (verification-gate detection) commands the ship verify step runs
protectedPaths unset (no rail) optional regexes. When set, a PR touching a match needs a human merge (--confirmed, which prompts)
mergeMethod unset (repo's first allowed: squash, rebase, merge) optional squash, rebase or merge; overridden by ship-merge --method
{
  "base": "main",
  "requiredChecks": ["build", "test"],
  "reviewStatus": "ci-review",
  "reviewStatusCreator": "github-actions[bot]",
  "verify": ["npm run lint", "npm test"],
  "protectedPaths": ["^\\.github/"]
}

Merge gate. agent-harness ship-merge is the merge step of the loop and the only merge path. It checks hard facts, not opinions. A refusal is input to the loop: the agent fixes the cause and retries. It refuses unless all of these hold:

  • the autonomy flag is on, or --confirmed is passed
  • the PR targets the base branch and is not a draft
  • every requiredChecks entry passed on the head
  • zero unresolved review threads
  • the branch is up to date with the base branch
  • no changed path matches protectedPaths, unless --confirmed is passed (a human merges such a PR)
  • only when reviewStatus is configured: the newest status with that context on the head is success, and its creator matches reviewStatusCreator when set

It then merges pinned to the head SHA. For a goal registered by ship-init, it runs agent-harness teardown-merged-worktree <pr>, which removes the goal worktree, the remote and local head branch, and the registry file, under the checks in the worktree destruction rule. It never touches the main checkout (cleanup --no-checkout), and the goal state (goal.json, autonomy.on) lives in the main checkout whichever worktree runs the command. For an unregistered PR it runs agent-harness cleanup <pr>: that deletes the PR's head branch on the remote and locally (the local branch only when fully merged), deletes the goal's recorded backup branches that the merge contains, moves the others (every pre-rebase snapshot after a squash merge) to refs/harness/backups/<name>, and switches the checkout to the updated base. Cleanup never removes a worktree; it reports one that holds the branch. In autonomous mode cleanup needs the goal to track the PR; once the goal worktree is gone, the registry entry is that proof only when it is the one entry for the PR, records the PR's head branch, is not escalated or blocked, its worktree path no longer exists, and no worktree has the branch checked out. An unregistered PR is refused. --keep-branch keeps the head branch. The merge method is chosen with --method squash|rebase|merge; without it the script uses mergeMethod from .claude/agent-harness.json, else the repo's first allowed method (squash, rebase, merge). A method the repo disallows is refused.

Review. Ship stage 6 runs a thorough local review before any push: code-reviewer, security-reviewer, and the stack cop (angular-cop or dotnet-cop) on the diff. The agent fixes confirmed Important findings and re-runs the review after each fix (the loop stops when the same findings repeat, with a safety ceiling of 10 rounds; it then escalates with the remaining Important findings). The push guard denies a push or gh pr create without a recorded pass. The agent posts one summary comment for a human to audit after opening the PR. That review is a quality step, not a merge rail. No GitHub status is created, and ship-merge does not trust the comment.

Push rules. Pushes to the base branch are forbidden in every mode, with or without force. git push --mirror, --all, and --no-verify are forbidden too. Force pushes (--force, --force-with-lease, -f, +refspec) are allowed on other branches.

Notifications. The run notifies only when a human needs to act, or when the goal ends: question when it must stop for an answer, waiting on a permission or idle prompt, failure on escalation, and done when the PR is merged. No progress notifications.

Limits.

  • These are client-side guardrails, not a security boundary. An agent with shell access can call gh directly.
  • Branch protection on the base branch (required reviews, required checks, restricted pushes) is the real enforcement. Set it on the host.
  • A PR that matches protectedPaths needs a human merge (--confirmed), when that key is set. Without the key, autonomous mode merges every PR that passes the gate.
  • OpenCode does not register Claude Code hooks. plugins/autonomy/index.ts runs autonomy-git-guard.sh before each shell call and ship-stop-gate.sh when a root session goes idle (instructions/autonomy.md).

Parity. The autonomy-status mod (.claude/mods/, status line and band) is Claude Code only. OpenCode has no equivalent.


Français

Ces catalogues décrivent l'arbre Conductor à la racine, sauf mention de Monolith. Le défaut d'installation est Monolith. Le schéma partagé est Choisir une variante et Comment une demande avance. Conductor embarque un conductor en lecture seule et 25 spécialistes. Monolith garde 9 agents de revue et replie les autres rôles dans des skills.

Chiffres recomptés le 2026-11-06 : 26 agents (1 conductor + 25 spécialistes) · 80 skills (skills/*/SKILL.md) · 53 modèles de commandes (dont 37 épinglés dans opencode.jsonc) · 6 instructions chargées au démarrage (13 fichiers dans instructions/) · 17 fichiers .claude/rules/ · 21 scripts dans .claude/hooks/ · 6 serveurs MCP · 4 fichiers d'outils custom · 3 plugins TUI activés dans tui.json.

Changements récents

Livré sur master jusqu'à fa50d8e (2026-10-18). Le numéro du plugin est version dans scripts/cursor-plugin/config.json. L'historique est scripts/cursor-plugin/CHANGELOG.md.

PR Plugin Ce qui est livré
#25 0.2.0 Garde semver dans scripts/cursor-plugin/check.mjs. Une modification des sources du plugin doit porter une version strictement supérieure à la base.
#27 0.3.0 CodeMemory reste éteint dans les sessions cloud et distantes, sauf override. Les tours revue/correctif de ship s'arrêtent à 3.
#28 0.4.0 Les findings sont Important, Nit ou Pre-existing. Seul Important bloque. Le verdict est Approve ou Block.
#29 0.4.1 Échelle d'application : code, puis lint, tests ou analyse statique, puis une règle en prose, puis la revue humaine.
#30 0.4.2 Le REVIEW.md d'un projet est la référence des tags quand il existe. Le modèle de PR ajoute Risk, How to revert et Tier.
#32 0.4.3 Les règles Cursor toujours appliquées passent de 21 fichiers (1438 lignes) à 7 fichiers (502 lignes). Le reste se charge par glob de chemin ou par skill.
#33 0.4.4 create-verification-skill écrit l'override projet de verify-this à partir des commandes build, test et e2e du dépôt.
#35 0.4.6 socratic-design fait un spike lorsqu'un essai de moins de 30 minutes peut trancher la question, et présente ce résultat. Une tâche L est reformulée dans les mots de l'agent avant le plan.

Semver (#25, note de politique dans #29). scripts/cursor-plugin/check.mjs compare les sources du plugin au merge-base avec la branche de base (origin/master, origin/$GITHUB_BASE_REF en GitHub Actions, ou CURSOR_PLUGIN_BASE). La version doit être MAJOR.MINOR.PATCH, strictement supérieure, et le changelog doit avoir un titre pour elle. Le build copie scripts/cursor-plugin/config.json dans plugins/fmflurry-harness/.cursor-plugin/plugin.json. Un edit du README.md racine n'est pas une source du plugin. #25 a livré cette garde en 0.2.0, avec patch, minor et major comme suggestions. Depuis 0.4.1, scripts/cursor-plugin/CHANGELOG.md demande un bump de patch pour les changements de plugin suivants. La garde ne l'impose pas : elle accepte encore un bump minor ou major, et elle affiche toujours ces suggestions.

CodeMemory (#27). FMFLURRY_CODEMEMORY=on|off|auto gagne. Absent, auto, ou toute autre valeur : détection. L'ordre est dans docs/codememory-cloud.md, implémenté dans plugins/code-memory-lib/mode.ts et .claude/hooks/codememory-mode.sh :

  • CLAUDE_CODE_REMOTE vrai (true, 1 ou yes), ou CLAUDE_CODE_REMOTE_SESSION_ID non vide : éteint.
  • Métadonnée Cursor agent/runtime égale à managed, lue par GET /v1/meta-data/agent/runtime sur CURSOR_AGENT_SOCKET (défaut /run/cursor/api.sock) : éteint.
  • CI : GITHUB_ACTIONS, GITLAB_CI, CIRCLECI ou BUILDKITE vrais, ou TF_BUILD ou JENKINS_URL défini : éteint. CI=true seul est ignoré, parce que .claude/settings.json pose CI pour chaque session Claude Code.
  • macOS (uname Darwin), et aucun signal ci-dessus : allumé, même si les services locaux sont arrêtés.
  • Sinon FalkorDB 127.0.0.1:6379 et Qdrant 127.0.0.1:6333 doivent tous les deux accepter une connexion TCP, sinon CodeMemory reste éteint. Une sonde en échec veut dire « down », pas une erreur.

Les hooks et les plugins OpenCode code-memory ne font rien quand la décision est éteinte. FMFLURRY_CODEMEMORY=on le garde allumé dans le cloud. off le garde éteint sur un portable.

Mémoire projet. Activée par défaut. /memory-init (skill project-memory) crée un AGENTS.md racine court (80 lignes environ au plus) et docs/memory/ : INDEX.md, contexts/<bounded-context>.md, des ADR immuables dans decisions/NNNN-<slug>.md, et glossary.md. Chaque doc porte un frontmatter owner, reviewed et refs. Un fichier de contexte n'est lu que si la tâche touche ce bounded context (instructions/project-memory.md). agent-harness memory-lint (.claude/hooks/memory-lint.sh) échoue sur un owner ou un reviewed manquant, une date reviewed de plus de 90 jours, ou une ref morte (chemin ou symbole). Le stop gate de ship ajoute ses constats à la raison du blocage. pr-report-check et le hook gh pr create le lancent, et exigent mémoire : màj ou mémoire : aucun changement dans le corps de la PR quand docs/memory existe. FMFLURRY_MEMORY=off la désactive.

Tags de revue (#28, #30). Le mapping par défaut est Finding tags dans .claude/agents/code-reviewer.md. Important bloque la fusion. Nit ne bloque pas. Pre-existing ne bloque pas, quelle que soit la gravité. Approve veut dire qu'aucun finding Important n'est ouvert (lint vert, et aucun commentaire interdit). Block veut dire qu'au moins un finding Important est ouvert. Il n'y a pas de verdict Warning. scripts/cursor-plugin/check.mjs rejette les anciens mots de sévérité de revue en capitales dans les sources du harness. La liste d'exceptions pour les usages hors revue (GDPR, santé base de données, lignes de risque de /plan, npm audit, CVE) est scripts/cursor-plugin/review-tags.mjs. Quand le dépôt en revue a un REVIEW.md à la racine, ce fichier est le seul mapping. Le reviewer le cite et n'applique pas la table par défaut en second mapping. Ce dépôt livre REVIEW.md.

Échelle d'application (#29). .claude/rules/common/enforcement-ladder.md (copie Cursor plugins/fmflurry-harness/rules/enforcement-ladder.mdc) et instructions/enforcement-ladder.md (chargée depuis opencode.jsonc). Placer le correctif au premier niveau qui peut le tenir : code, puis lint, tests ou analyse statique, puis une règle en prose, puis la revue humaine. Une règle en prose porte why-not-tooled:. Ajouter de la prose toujours chargée suppose d'en supprimer ou d'en raccourcir d'autre dans le même changement.

Modèle de PR (#30). .github/pull_request_template.md contient Summary, Risk, How to revert et Tier. Tier vaut T1, T2 ou T3, selon le blast radius, les chemins protégés et la taille du diff. Ce n'est pas un tag de finding. /setup-harness écrit ce modèle quand .github/pull_request_template.md manque, et laisse un fichier existant (scripts/cursor-plugin/templates/setup-harness.md, construit vers plugins/fmflurry-harness/skills/setup-harness/SKILL.md). commands/pr.md et commands/create-pull-request.md remplissent le modèle quand il existe. Depuis 0.4.18 le modèle a aussi ## Visual report. Le harness commit un HTML show-me et un PNG dans docs/pr-reports/<branch-slug>.html et .png, intègre le PNG et lie le HTML. .claude/hooks/pr-visual-report.sh bloque un corps gh ou az sans cette section. Une coquille de doc ou un bump de version seul peut cocher Skip et écrire la raison. Conductor et Monolith partagent le skill pr-visual-report. agent-harness pr-report écrit les fichiers, agent-harness pr-report-links imprime la section avec des liens absolus épinglés au commit du rapport (un lien relatif ouvre une page de comparaison et est refusé depuis 0.4.33), et agent-harness pr-report-check vérifie le corps.

Rules diet (#32). Plugin 0.4.3 (fa50d8e). plugins/fmflurry-harness/rules/ compte 7 fichiers alwaysApply: true, 502 lignes, contre 21 fichiers et 1438 lignes à 62aa030. En 0.4.3 c'étaient autonomy.mdc, conductor.mdc, enforcement-ladder.mdc, orchestration.mdc, question-handling.mdc, tool-budget.mdc et verification-gate.mdc. rules.always dans scripts/cursor-plugin/config.json liste les six règles common/. Le build Conductor ajoute rules/conductor.mdc. Le build Monolith par défaut du plugin 0.4.19 remplace ce fichier par rules/monolith.mdc et retire la first-tool gate. Ce build n'a pas de rules/always__harness.mdc. Le compte toujours chargé reste 7. Les règles liées à des fichiers restent dans ce répertoire avec alwaysApply: false et globs : code-comments, coding-style, security, testing, et les cinq packs typescript-*. Celles-ci ont quitté l'ensemble toujours chargé et sont des skills : agent-roster, brief-contract, codebase-exploration, git-workflow, harness-parity, hooks, open-pr-check, patterns, performance, worktree-destruction-safety. skills/ai-ecosystem-audit/SKILL.md (Always-on budget) compte les règles globales de session. Plus de 8 règles Cursor alwaysApply: true est un finding confirmé.

Objectif

  • Reproductibilite: meme comportement entre machines/sessions.
  • Qualite: TDD a la demande, verification reguliere, conventions centralisees.
  • Securite: skill security-review disponible à la demande + hooks pre-tool-use (security warnings).

Structure du repo

  • Configs: opencode.jsonc, dcp.jsonc (dynamic context pruning), tui.json (theme TUI).
  • Profils: profiles/<name>/ (override opencode.jsonc + AGENTS.md par profil).
  • Skills: skills/*/SKILL.md (+ ressources auxiliaires) — ensemble canonical, partage avec Claude Code via sync-skills.sh.
  • Prompts agents: prompts/agents/*.txt.
  • Commandes slash: commands/*.md.
  • Plugins OpenCode: plugins/<name>/index.ts (+ plugins/code-memory-lib/ + plugins/lib/, avec plugins/lib/kdco-primitives/).
  • TUI plugins: tui-plugins/*.tsx (registered in tui.json; autonomy-status.tsx is the autonomy sidebar panel).
  • Outils custom: tools/*.ts.
  • Contextes (memos de mode): contexts/*.md.
  • Instructions globales: instructions/*.md (6 chargees au demarrage; le reste est un skill ou un fichier non charge).
  • Scripts: scripts/setup-package-manager.js, scripts/codemaps/generate.ts, scripts/settings-sync.sh, scripts/sync-skills.sh, scripts/skill-drift-check.sh.
  • Installeurs: bootstrap.sh, bootstrap.ps1, install.sh, install-cursor.sh. ./install.sh demande Conductor ou Monolith (defaut Monolith); ./install.sh --yes et settings-sync installent Monolith sans variante. ./install.sh conductor, ./install.sh monolith, --variant et HARNESS_VARIANT font le meme choix sans prompt. orchestration est un alias de Conductor. ./install.sh --local et ./install-cursor.sh sont Monolith par defaut. Une session Claude Code distante (CLAUDE_CODE_REMOTE=true) lance .claude/hooks/cloud-session-bootstrap.sh au SessionStart si le projet ne vendore pas le harness. ./install.sh --status et ./install-cursor.sh --status affichent la variante installee. ./install.sh --local applique aussi .harness-local/ (jamais modifié par l'installeur) par-dessus .claude/, .opencode/, AGENTS.md, .cursor/ et .agents/, y compris quand le clone est atteint par un lien symbolique. Un répertoire ignoré affiche la raison. Le mode local écrit ./.claude/mods/autonomy-status, et Monolith écrit .opencode/instructions/monolith.md. .harness-local/exclude liste les skills et chemins à ne pas réinstaller. Le hook domain-rules reste éteint tant que .harness-local/domain-rules.json ne contient pas "enabled": true. Détail: docs/harness-local.md. ./install.sh --local --status affiche l'overlay et les exclusions.
  • Mirror Claude Code: .claude/CLAUDE.md, .claude/settings.json, .claude/hooks/, .claude/rules/, .claude/agents/, .claude/skills/, .claude/commands/.
  • Exclusions volontaires (.gitignore): node_modules/, antigravity-*, .DS_Store, fichiers locaux .env* sauf .env.example, répertoire runtime skills/skill-creator/.

Configuration: opencode.jsonc

Le fichier orchestre six choses:

  1. instructions: docs toujours chargees au demarrage (6) — routing sous-agent, question handling, verification gate, autonomie, tool budget, enforcement ladder. Le reste est un skill ou une instruction hors tableau (code-comments, coding-style, testing, security).
  2. default_agent: conductor (orchestrateur sans droit d'ecriture).
  3. agent: definitions des sous-agents (prompt + outils autorises). Aucun agent ne pose model, et le fichier n'a pas de model au niveau racine. Chacun utilise le modele de la session.
  4. command: mappe /<name> -> template + sous-agent + subtask; 21 entrees epinglees.
  5. mcp: six serveurs — code-memory actif; context7, blender, wallaby, Figma, smartbear-swagger desactives par defaut. Perms code-memory_* pre-allowlistees pour chaque sous-agent.
  6. plugins : le plugin npm opencode-skill-creator. OpenCode 2 charge seul les dossiers de plugins locaux sous plugins/.

dcp.jsonc est le stub de config du plugin externe optionnel Dynamic Context Pruning.

Agents

Ce tableau est le roster Conductor, defini dans opencode.jsonc (champ agent) — 26 entrees: le primary plus 25 sous-agents. build et plan sont des overrides built-in, livres desactives.

Monolith n'installe pas ce roster. Il garde 9 agents. L'agent principal coordonne et peut ecrire. /orchestrate charge le skill conductor.

Agent Acces Role Declencheur
conductor read-only Orchestrateur. write/edit interdits; chaque modif via Task. Agent par defaut
planner read-only Plan + risques + ordre des phases. Features complexes
architect read-only Design systeme, scalabilite, frontieres de modules. Decisions structurantes
coder writable Implementation pure (hors tests). Self-check build+lint+standards. Gate socratique. Toute modif de code
writer writable Docs/markdown/HTML/texte. Refuse le code source. Prose, README, ADR, rapports
code-reviewer read-only Revue diff/PR. Findings seulement; fixes vers coder. Possede /cop-review. Demandes de revue
comment-judge read-only Verdict rubric sur commentaires; REVIEW (diff) ou PURGE (dossier). JSON. Revue/purge commentaires
haruspex-commentorum writable Purge des commentaires selon verdicts. Triggered-only (purge)
ecosystem-auditor read-only Audit evidence-first parite OpenCode/Claude. /ecosystem-audit
angular-cop read-only Revue pre-merge Angular + TypeScript. Revue PR Angular
dotnet-cop read-only Revue pre-merge .NET 10 Minimal API. Revue PR .NET
gdpr-specialist read-only Conformite GDPR/CNIL (consent, cookies, PII, retention, transferts, breach 72h). Features sensibles
security-reviewer read-only Revue OWASP/secrets/deps. Remediation vers coder. Auth, input, endpoints, secrets
tdd-guide writable (tests) RED → GREEN → REFACTOR + 80%. /tdd refactor pose des characterization tests deja verts. Delegue l'implementation au coder. Features, fixes, refactors
build-error-resolver writable Fix build/typecheck/lint/TS, diff minimal. Build ou lint rouge
e2e-runner writable Tests E2E depuis l'override projet ou un runner decouvert. Parcours navigateur
doc-updater writable Docs generees + codemaps. /update-docs, /update-codemaps
refactor-cleaner writable Suppression code mort + consolidation. Demandes de nettoyage
database-reviewer read-only PostgreSQL/Supabase: schema, perfs, RLS, migrations. Revue SQL/migration/schema
postgres-dba read-only Ops instance live: health, vacuum/bloat, WAL, backups/PITR, pooling, upgrades. /db-health, /db-backup-check
api-spec-architect writable Specs OpenAPI 3.1 Zalando; publication SwaggerHub optionnelle. /api-spec
git-specialist writable (git) Branches, commits, push, PRs. Taches git/commit/PR
scout read-only Manifeste de fichiers pour un scope inconnu. Triggered-only (conductor)
why-investigator read-only Enquete une categorie de preuve. Triggered-only (skill why)
why-synthesizer read-only Fusionne les findings en une reponse ponderee. Triggered-only (skill why)
gaudi writable Blender / art 3D: modelisation, materiaux, lumiere, render, export glTF. Triggered-only (3D)

Modele de session. Aucun agent de opencode.jsonc ne pose model, et le fichier n'en pose pas au niveau racine. L'agent principal utilise le modele choisi pour la session. Un sous-agent utilise le modele de l'agent qui l'a lance (agents OpenCode). Une install Monolith fait de meme: le generateur n'ecrit pas model.

OPENCODE_REASONING_* n'est plus ecrit. Ces variables n'etaient exportees que dans le shell. opencode.jsonc ne les interpolait pas. Les champs de raisonnement d'une entree myMistral decrivent ce fournisseur. Ils ne choisissent pas le modele de la session.

Pour epingler un agent, posez model sur cet agent dans votre propre config OpenCode. Une reinstallation de ce harness n'ajoute pas d'epingle.

Comment marche le harness

Cette section décrit Conductor. Sur Monolith l'agent principal peut écrire dès la première édition, et /orchestrate charge le skill conductor. Le parcours des trois hôtes est Comment une demande avance.

  • Le conductor n'ecrit pas. tools.write: false, tools.edit: false, permission.edit/write: deny; sa Task allowlist enumere chaque specialiste, *: deny bloque le reste. instructions/subagent-routing.md impose un Task-first gate.
  • Flux canonique: planner → (tdd-guide → coder) ou coder → code-reviewer → verify → git-specialist.
    • Fonctionnalite: planner → /tdd (RED) → coder (GREEN) → /verify → /pr → /cop-review → ship-merge.
    • Refactor: planner → /tdd refactor (characterization tests, verts immediatement, puis geles) → coder (restructure sans modifier ces tests) → /blast-radius → /verify (baseline contre treatment sur le meme pin) → /pr → /cop-review → ship-merge.
  • Brief contract (6 champs): TASK, FILES, CHANGE, DONE-WHEN (commande executable), OUT OF SCOPE, CONTEXT ALREADY RESOLVED + BUDGET.
  • Questions: chaque ambiguite taggee [BLOCKING] ou [NON-BLOCKING]; le conductor tente de resoudre depuis le repo avant de demander.
  • Verification gate: aucun "done" sans preuve fraiche (build/lint/tests executes, sortie collee).
  • Tool budget: commandes de verification illimitees; exploration shell limitee (defaut 3/dispatch).
  • Worktree safety: seul chemin de suppression agent-harness worktree-rm <path> --confirmed (sans --confirmed : dry run, exit 3). Checks obligatoires : status, commits non poussés, activité (échec fermé si inconnue ; app Orca fermée : lsof doit montrer qu'aucun processus n'a son répertoire courant dans le worktree, puis la suppression passe par git), autres checkouts du dépôt propres ou snapshotés (refs refs/harness/snapshots/ : contenu, modes, index, fichiers non suivis). Les fichiers ignorés, les dépôts git imbriqués non suivis (signalés en note) et le contenu des submodules ne sont pas couverts. Après suppression : re-scan des autres checkouts ; un checkout modifié n'est restauré que si son HEAD est inchangé et qu'il est propre, sinon exit 4 avec commandes d'inspection et de restauration, refs conservées. Chaque sha de snapshot est affiché avant la libération de sa ref. Les git worktree remove|prune|move (options globales et alias compris), orca worktree rm direct et rm/mv/trash/rsync --delete/find -delete récursifs sur un worktree ou son parent sont refusés par le guard, dans tous les modes. C'est une détection textuelle qui ne voit pas les commandes assemblées à l'exécution : la frontière réelle reste les checks du script. git worktree prune -n reste autorisé. En mode autonome, agent-harness worktree-rm <path> --confirmed retire un worktree propre dont la branche est fusionnée (pointe atteignable, arbres égaux, ou gh pr view --json state à MERGED) et refuse un worktree sale, du travail non fusionné, le checkout principal, et un chemin qui n'est pas un worktree du dépôt. agent-harness teardown-merged-worktree <pr> retire le worktree d'un goal enregistré dont la PR est MERGED, en mode autonome, avec les checks relancés sur la tête de la PR ; il n'utilise jamais --force et conserve le registre si une étape est partielle. Les worktrees de goal sont créés par agent-harness ship-init et enregistrés dans <git-common-dir>/agent-harness/goals/<slug>.json.
  • Codememory-first: les outils code-memory_* d'abord; grep/read en repli seulement.

Orchestration durcie des sous-agents

La delegation est imposee sur deux couches, donc le comportement reste identique que le primary soit Claude, GPT, DeepSeek ou un modele open-weight qui ignore les instructions en prose:

  1. Permissions — conductor a tools.write: false, tools.edit: false, et permission.edit/write: deny dans opencode.jsonc. L'allowlist Task enumere chaque specialiste legal; *: deny bloque le reste. L'orchestrateur n'a litteralement aucun outil pour modifier des fichiers.
  2. Guard plugins + prompt front-loaded — plugins/secret-file-guard/index.ts avorte tout acces read/bash a un fichier .env porteur de secret; plugins/tool-budget/index.ts pousse la verification plutot que l'exploration (ne bloque jamais un appel). prompts/agents/conductor.txt place les regles dures dans les premieres lignes, la table de routage en second, et six exemples few-shot User -> task avec contre-exemples explicites; instructions/subagent-routing.md impose un Task-first gate avant inspection directe.

Chemins possibles: requete normale (routage via Task), mention @agent, commande slash (/plan, /tdd, /security).

Commandes slash

53 modèles dans commands/ (recomptés le 2026-11-06) ; 37 épinglés dans le bloc command de opencode.jsonc. Ce bloc est le set Conductor. Monolith remap une valeur agent repliée : postgres-dba devient database-reviewer, et tout autre nom replié devient main, qui charge le skill correspondant (scripts/variants/dangling-agents.mjs). Beaucoup sont subtask: true. Le bloc épinglé est l'ensemble garanti ; l'auto-découverte éventuelle de commands/ n'est pas vérifiable ici, donc considérer les autres comme Claude-side ou dépendantes de la découverte.

Commande Sous-agent But
/git git-specialist Operations git encadrees (branche/commit).
/push-changes git-specialist Commit + push (avec garde sur upstream).
/plan planner Plan d'implementation.
/tdd tdd-guide Cycle TDD. /tdd refactor fige le comportement actuel.
/api-spec api-spec-architect Generation de specs OpenAPI 3.1.
/cop-review code-reviewer Revue pre-merge directe; selectionne le guide du stack.
/security security-reviewer Audit securite.
/gdpr-review gdpr-specialist Audit conformite GDPR/CNIL.
/build-fix build-error-resolver Resolution build/TS errors.
/e2e e2e-runner Tests E2E depuis l'override projet ou le runner decouvert.
/refactor-clean refactor-cleaner Nettoyage code mort.
/orchestrate planner Orchestration multi-agents.
/verify (conductor) Boucle de verification.
/eval (conductor) Evaluation contre criteres.
/update-docs doc-updater Mise a jour de la doc.
/update-codemaps doc-updater Genere docs/CODEMAPS/.
/test-coverage tdd-guide Analyse coverage.
/skill-create pas de clé agent Génère une skill depuis l'historique git. Tourne comme l'agent par défaut.
/db-health postgres-dba Bilan sante PostgreSQL read-only.
/dependabot-friday git-specialist Triage PR Dependabot (rapport seulement).
/db-backup-check postgres-dba Audit backup/PITR.
/ship conductor Un objectif, de la clarification à la fusion.
/autonomous conductor Active, coupe, ou affiche le mode autonome.
/pr git-specialist Ouvre une PR selon le modèle du dépôt.
/memory-init writer Échafaude la mémoire projet.
/show-me writer Schéma HTML hors ligne et captures PNG.
/show-your-work conductor Journal TSV des décisions.
/comment-judge comment-judge Verdict de rubric sur les commentaires.
/interfectio-commentarum conductor Purge de commentaires Haruspex.
/for-real conductor Reformule le dernier message en langage clair.
/why conductor Justification de conception, avec citations.
/blast-radius conductor Ce qu'un changement peut casser, en exécutant le code.
/chimera conductor Candidats parallèles, puis greffe.
/fix-ci conductor Corrige les checks de PR en échec.
/loop-on-ci conductor Surveille les checks et itère les correctifs.
/get-pr-comments git-specialist Résume les commentaires de revue.
/fix-merge-conflicts git-specialist Rebase à travers les conflits.

Non epinglees (16): /checkpoint, /pm2, /setup-pm, /ecosystem-audit, /create-pull-request, et la famille OpenSpec /opsx-*. Claude-only: arena.md, arena-new-prompt.md.

Skills

Recomptés le 2026-11-06 : skills/*/SKILL.md compte 80 skills. Les groupes ci-dessous nomment cet ensemble. Douze d'entre eux sont dans la dernière puce, hors des groupes plus anciens. skill-creator/ est git-ignoré et hors des 80. scripts/sync-skills.sh calcule l'union canonique (root skills/ ∪ .claude/skills/, root gagne), exclut le runtime skills/skill-creator/, et copie vers chaque cible. Attribution dans skills/THIRD_PARTY_NOTICES.md. Les références de classes d'attaque dans skills/security-review/references/ sont des copies conformes de cloudflare/security-audit-skill au commit c1c8a8c1471069fb0e188eeaff69b8e8db6564a8 (MIT, Copyright (c) 2025-2026 Cloudflare, Inc.). Le texte de licence est LICENSE-cloudflare-security-audit.

  • Planification & design (5): socratic-design, chimera, api-spec-openapi, why, blast-radius.
  • Revue & qualite (6): comment-judge, interfectio-commentarum, verify-this, create-verification-skill, test-behavior-not-implementation, ai-ecosystem-audit.
  • TDD & tests (3): tdd-workflow, tdd, e2e.
  • CI & git (5): fix-ci, fix-merge-conflicts, get-pr-comments, loop-on-ci, git-workflow.
  • Angular (4): angular-clean-architecture, angular-ddd, angular-cop, angular-accessibility.
  • .NET (3): dotnet-clean-architecture, dotnet-ddd, dotnet-cop.
  • Three.js / 3D (1): threejs, dix sujets sous references/.
  • Playbooks PostgreSQL (4): postgres-{health-check,performance-tuning,backup-restore,container-ops}.
  • Playwright E2E (2): playwright-e2e-authoring, playwright-e2e-review.
  • Workflow OpenSpec (1): openspec, onze workflows sous references/.
  • Ecriture & communication (7): humanizer, for-real, caveman, caveman-commit, caveman-review, show-me, show-your-work.
  • Harness & config (5): config-sync, harness-parity, skill-authoring, treetopia, strategic-compact.
  • Securite (1): security-review. Conformite (1): gdpr-compliance. Domaine (2): flurryx, transloco. Standards (1): coding-standards.
  • Skills de role a la demande: planner, coder, writer, doc-updater, architect, refactor-cleaner, scout, gaudi, testing, security, coding-style, code-comments, autonomy, question-handling, enforcement-ladder, tool-budget, verification-gate. Monolith les charge dans la boucle principale. Conductor garde les agents correspondants.
  • Aussi dans l'arbre (12) : agent-roster, autonomous, brief-contract, codebase-exploration, hooks, open-pr-check, patterns, performance, project-memory, pr-visual-report, ship, worktree-destruction-safety.

Les ensembles PostgreSQL et Playwright sont des playbooks projet specifiques a gc.platform. /e2e et e2e-runner ne supposent pas cette stack : ils lisent e2e.json ou decouvrent la commande de demarrage, les ports et le runner (skills/e2e). Les playbooks Playwright ne se chargent que si l'override les nomme. "enabled": false desactive /e2e. Un consommateur qui n'en veut pas omet playwright-e2e-authoring et playwright-e2e-review au vendoring. skill-creator est runtime-only, git-ignore et jamais synchronise.

Instructions & règles

6 instructions de demarrage (instructions/*.md): routage, questions, verification, autonomie, budget d'outils, enforcement ladder. Le reste est un skill ou une regle bornee par paths:.

Le cote Claude Code garde ces six regles sans paths:, plus les regles bornees (commentaires, style, securite, tests) et 5 packs rules/typescript/.

Deux fichiers d'instructions distincts: le CLAUDE.md racine (guidelines comportementales, alimente par les packs via @rules/...) et .claude/CLAUDE.md (instructions globales installees dans ~/.claude, avec l'essentiel cross-projet).

Plugins & hooks

Les plugins sont des dossiers OpenCode 2 construits avec @opencode/plugin@2.2.7 (plugins/<nom>/index.ts, Plugin.define). OpenCode charge chaque dossier de plugins/ ; plugins dans opencode.jsonc ne nomme que le plugin npm opencode-skill-creator.

  • plugins/secret-file-guard/index.ts — bloque l'acces read/bash aux .env porteurs de secret; .env.example/.sample/.template restent lisibles.
  • plugins/mistral-affinity/index.ts — header x-affinity stable pour l'affinite de cache Mistral.
  • plugins/tool-budget/index.ts — pousse la verification plutot que l'exploration (ne bloque jamais).
  • plugins/code-memory/index.ts + plugins/code-memory-lib/ — nudges auto-retrieve / auto-learn CodeMemory (no-op sans CLI).
  • plugins/lib/ (with plugins/lib/kdco-primitives/) — utilities partages.
  • opencode-skill-creator (npm externe) — scaffolding et benchmark de skills.
  • plugins/kpi/index.ts — côté OpenCode du journal KPI.
  • plugins/autonomy/index.ts — côté OpenCode du mode autonome. Voir Mode autonome.
  • plugins/domain-rules/index.ts — éteint tant que .harness-local/domain-rules.json ne l'active pas.
  • Non charges: plugins/ecc-hooks.ts.disabled, plugins/worktree.disabled, plugins/figma-rag.md, tui-plugins/caveman.tsx.disabled.

Hooks Claude (.claude/hooks/, 21 scripts, recomptés le 2026-11-06) : notification.sh, pre-tool-use.sh, prefer-code-memory.sh, rtk-rewrite.sh, stop.sh, subagent-stop.sh, tool-budget.sh, autonomy-ask-guard.sh, autonomy-context.sh, autonomy-git-guard.sh, cache-invalidation.sh, cloud-session-bootstrap.sh, codememory-mode.sh, commit-provenance.sh, domain-rules.sh, goal-state.sh, kpi-emit.sh, memory-lint.sh, orca-notify.sh, pr-visual-report.sh, ship-stop-gate.sh.

Outils custom (tools/)

Outils OpenCode reutilisables exposes via tools/index.ts:

  • tools/run-tests.ts — detecte package manager + framework et construit la commande de test.
  • tools/check-coverage.ts — lit les rapports coverage et compare a un seuil.
  • tools/security-audit.ts — scan deps + secrets + patterns a risque.

TUI plugins

  • tui-plugins/panda-banner.tsx — banniere SolidJS affichant un en-tete panda en art ASCII/blocs.
  • tui-plugins/autonomy-status.tsx — capsule de la barre latérale pour le mode autonome, enregistrée dans tui.json. Le comportement est dans Mode autonome.

Mirror Claude Code (.claude/)

  • CLAUDE.md — instructions globales (no any, facade != UseCase).
  • settings.json — permissions allow/deny, env vars (API_TIMEOUT_MS=3000000, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1, CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80), "model": "opus" pour l'agent principal Claude Code, hooks PreToolUse / PostToolUse / Stop. Conductor et Monolith partagent ce fichier. Initialisé à la première install dans ~/.claude et dans le .claude du projet. Une valeur model déjà présente est conservée.
  • hooks/*.sh — 21 scripts. La liste est sous Plugins & hooks.
  • rules/common/*.md + rules/typescript/*.md — 17 fichiers (recomptés le 2026-11-06). Six sous rules/common/ n'ont pas de clé paths:. Six sous rules/common/ sont bornés (code-comments, coding-style, security, testing, cache-invalidation, project-memory). Cinq packs typescript/ restent bornés.
  • agents/*.md — 26 agents mirroir du roster OpenCode.
  • commands/*.md — commandes Claude (/create-pull-request, /update-codemaps, arena, OpenSpec).
  • skills/** — miroir des skills, synchronisé via scripts/sync-skills.sh à l'install. Pas garanti identique à skills/ du jour (le set canonical grandit entre les syncs): skills/ reste la source de verite; settings-sync --skills-only pour reconcilier.

Sync & mise a jour

Deux repertoires, une source de verite: le lab (ton clone de ce repo) et le live (~/.config/opencode, ~/.claude). Rien ne surveille le filesystem — tu pull, puis tu sync.

  • install.sh merge additivement, ne supprime jamais la config utilisateur; re-executable et idempotent.
  • settings-sync (scripts/settings-sync.sh) resout le repo et lance l'install; --skills-only = chemin rapide skills; --where affiche le chemin.
  • scripts/sync-skills.sh calcule l'union canonique et copie vers chaque harness.
  • scripts/skill-drift-check.sh — detecteur read-only de drift entre copies de skills; sort non-zero en cas de divergence.
  • Le skill config-sync fait la meme propagation cote agent.
  • install-cursor.sh génère un plugin Cursor (node scripts/build-cursor-plugin.mjs -> plugins/fmflurry-harness/) et le copie dans ~/.cursor/plugins/local/fmflurry-harness, puis Developer: Reload Window dans Cursor. Le build par défaut est Monolith : l'agent principal peut écrire, il n'y a pas de first-tool gate, et /orchestrate est optionnel. ./install-cursor.sh --variant conductor (ou HARNESS_VARIANT=conductor ./install-cursor.sh) construit Conductor. ./install-cursor.sh --status affiche la variante lue dans .harness-variant. Il installe aussi le CLI agent-harness, avec le même helper que install.sh : scripts dans ~/.local/share/fmflurry-harness/scripts/agent-harness, wrapper ~/.local/bin/agent-harness. Un second passage affiche ces chemins et n'ajoute pas une seconde commande. Options : --yes, --link (symlink au lieu de copie), --migrate-legacy (sauvegarde puis supprime ce que l'ancien installeur a copié dans ~/.cursor, en gardant vos propres entrées), --uninstall, --no-backup, --variant, --status. Limites : pas de liste d'outils par agent, délégation par instruction uniquement, hooks Notification non supportés. Les tiers restent des modèles Cursor : grok-4.7, grok-4.6 et composer-2.5.

Parité : les harnesses sont synchronisés à l'install. Recomptés le 2026-11-06, skills/ = 80 et le miroir .claude/skills/ = 41. Lancer settings-sync --skills-only pour réconcilier.

Version du plugin Cursor

Le numéro installé est version dans scripts/cursor-plugin/config.json (0.4.36 dans cet arbre). node scripts/build-cursor-plugin.mjs le copie dans plugins/fmflurry-harness/.cursor-plugin/plugin.json et copie scripts/cursor-plugin/CHANGELOG.md dans le plugin. node scripts/cursor-plugin/check.mjs echoue si ces deux versions divergent ou si le changelog n'a pas de titre pour la version courante. L'entree marketplace n'a pas de version. Le package.json racine versionne le depot settings (releases GitHub), pas ce plugin.

Monter la version a la main dans chaque PR qui touche le contenu du plugin ou ses entrees de build :

  • patch — correctifs, chores, retouches de doc du plugin
  • minor — nouveaux agents, skills, commandes, regles, ou comportement
  • major — ruptures : agents ou skills renommes ou retires, cles de tier changees, contrat de l'installeur change

Depuis le plugin 0.4.1, scripts/cursor-plugin/CHANGELOG.md demande un bump de patch pour chaque changement de plugin suivant. Le check exige seulement une version strictement supérieure à la base. Il ne refuse pas un bump minor ou major.

Le check compare l'arbre de travail au merge-base avec la branche de base : un edit du README racine n'exige pas de bump. La version a depasser est la pointe de la branche de base (origin/master, origin/$GITHUB_BASE_REF en CI, ou CURSOR_PLUGIN_BASE). Sans aucune de ces refs, le check affiche un message et continue.

bump the plugin version + changelog in any PR touching plugin sources.

Comment tout s'emboite

Le parcours des deux variantes est Comment une demande avance. Les quatre étapes ci-dessous sont le démarrage OpenCode quand la variante installée est Conductor.

  1. Demarrage: OpenCode charge opencode.jsonc -> 6 instructions globales -> auto-charge chaque plugin de plugins/ plus les plugins TUI enregistres dans tui.json. Les skills se chargent selon leur description.
  2. Dev: conductor execute — il n'a pas le droit d'ecrire; il dispatche des Task vers les specialistes. secret-file-guard bloque l'acces .env; tool-budget pousse la verification.
  3. Workflow: routage via Task (impose par permissions); /plan, /tdd, /security, etc. forcent explicitement le meme routage. Brief contract, question protocol et verification gate encadrent chaque passage.
  4. Idle : le plugin autonomy lance le stop gate et envoie la notification d'inactivité.

Mode autonome

Le mode autonome permet à l'agent de mener un objectif de la clarification jusqu'à une PR fusionnée. Activez-le, puis lancez /ship <goal>. Avec le flag désactivé, l'agent demande avant chaque étape irréversible, et une fusion nécessite --confirmed. Activer le flag ne démarre aucun travail (skills/autonomous/SKILL.md).

Le run est une boucle, tenue par skills/ship/SKILL.md : implémenter, vérifier, revue locale, pousser et ouvrir la PR, CI, puis agent-harness ship-merge. Un blocage que l'agent peut corriger (un finding Important confirmé, un check en échec, un conflit, une branche en retard, un fil non résolu, un refus de fusion) le renvoie vers la correction, puis vers une nouvelle revue locale, puis vers le push, la CI et une nouvelle tentative de fusion. Il se termine en done (PR fusionnée et worktree du goal retiré) ou escaladé.

Comment le lancer. Le texte du goal est l'argument de /ship. Le flag est aussi agent-harness autonomy on|off|status (scripts/agent-harness/autonomy.sh). install.sh installe ce wrapper dans ~/.local/bin/agent-harness quand Claude Code ou OpenCode est une cible d'install. install-cursor.sh installe le même wrapper, qui pointe vers ~/.local/share/fmflurry-harness.

  • Claude Code. Il n'y a pas de .claude/commands/ship.md. /ship <goal> est le skill ship, skills/ship/SKILL.md. install.sh lance scripts/sync-skills.sh, qui le copie vers ~/.claude/skills/ship. /autonomous on|off|status est skills/autonomous/SKILL.md (disable-model-invocation: true, donc invoqué par l'utilisateur). La règle de comportement est .claude/rules/common/autonomy.md. Le hook Stop est .claude/hooks/ship-stop-gate.sh, branché depuis .claude/settings.json.
  • OpenCode. /ship et /autonomous sont épinglés dans opencode.jsonc (command.ship, command.autonomous), tous deux sur conductor, templates commands/ship.md et commands/autonomous.md. La règle chargée au démarrage est instructions/autonomy.md. plugins/autonomy/index.ts bloque l'outil question, injecte le contexte d'autonomie, refuse les commandes git interdites, et relance la session racine quand le stop gate bloque. La bascule de la barre latérale est tui-plugins/autonomy-status.tsx (enregistrée dans tui.json) : palette « Toggle autonomous mode », /autonomy-toggle, ou <leader>u.
  • Cursor. /ship <goal> est plugins/fmflurry-harness/commands/ship.md (construit depuis commands/ship.md par scripts/build-cursor-plugin.mjs). Il charge plugins/fmflurry-harness/skills/ship/SKILL.md. /autonomous est plugins/fmflurry-harness/commands/autonomous.md et plugins/fmflurry-harness/skills/autonomous/SKILL.md. La règle toujours active est plugins/fmflurry-harness/rules/autonomy.mdc. L'entrée stop de plugins/fmflurry-harness/hooks/hooks.json lance hooks/scripts/ship-stop-gate.sh. Ce hook appelle agent-harness depuis le PATH. install-cursor.sh installe cette commande dans ~/.local/bin/agent-harness.

Boucle de revue. L'étape 6 de skills/ship/SKILL.md relit git diff <base>...HEAD avec code-reviewer, security-reviewer, et le cop du stack quand il s'applique (angular-cop ou dotnet-cop ; database-reviewer si le SQL a changé). L'agent confirme chaque finding contre le code. Seul un finding Important confirmé bloque. Nit et Pre-existing ne bloquent pas. Les tags viennent du REVIEW.md du dépôt quand il existe, sinon de Finding tags dans .claude/agents/code-reviewer.md. Chaque verdict est enregistré avec agent-harness goal review code|security pass|fail. Le garde de push (.claude/hooks/autonomy-git-guard.sh) refuse git push et gh pr create tant qu'un goal actif n'a pas de verdicts code et sécurité positifs pour le diff exact (un hash du diff contre origin/<base>, hors docs/agent-reports/) ; les pushes vers backup/* et le commit de rapport ne sont pas gardés. Une fois la PR ouverte, un commentaire de synthèse est publié (skills/ship/references/review-format.md). Ce commentaire est une trace d'audit. ship-merge ne le lit pas. Chaque correctif CI ou de commentaire ultérieur est relu localement avant son push.

Findings répétés. Avant chaque tour de correctif, le skill envoie les findings confirmés (<reviewer>:<path> ou ci:<check>, un par ligne) sur l'entrée standard de agent-harness goal bump. La commande les normalise (minuscules, numéros de ligne retirés, tri, dédoublonnage) et en calcule une empreinte. Quand l'empreinte égale celle du tour précédent, elle marque le goal escalated (no progress), lance agent-harness notify failure, et sort avec le code 3. goal.sh et ship-init.sh posent aussi un plafond de sécurité max_fix_iterations à 10. Une entrée vide sort avec le code 2. Le même bump est utilisé avant un tour de correctif CI (étape 9 de skills/ship/SKILL.md).

Règle d'absence de progrès. Deux contrôles portent ce nom. Ce n'est pas le même test.

  • skills/ship/SKILL.md (Stop conditions) traite une itération complète comme sans progrès quand le même finding Important et le même échec restent, ou quand le même blocage hors revue échoue de la même façon. Un nouvel échec, un nouveau finding, ou un check vert compte comme un progrès. L'agent lance alors agent-harness goal escalate. Pour les findings de revue, goal bump compare aussi une empreinte des findings entre deux tours.
  • .claude/hooks/ship-stop-gate.sh (copie Cursor : plugins/fmflurry-harness/hooks/scripts/ship-stop-gate.sh) compte un arrêt comme sans progrès seulement quand rien n'a bougé : la tête de la PR, la pointe de branche du worktree enregistré, .reviews, et fix_iterations. Cinq arrêts vides consécutifs escaladent avec no progress after 5 stop blocks. Un de ces changements remet stop_blocks à 0. Chaque arrêt compté incrémente total_blocks, et 30 blocs au total escaladent même si le dernier arrêt était un progrès. Les arrêts ne sont pas comptés pendant agent-harness goal wait "<reason>" --ttl 30m (24 h maximum), ni tant que l'entrée du hook, un pid vivant, un marqueur inflight, ou un processus de test ou de revue dans le worktree montre un travail en arrière-plan. Avant que les deux verdicts passent pour la pointe locale, le blocage dit de finir la revue locale. Après les deux verdicts, sans PR, il dit de pousser et d'ouvrir la PR. Tant que le goal est actif et que la PR n'est pas fusionnée, le hook bloque un arrêt anticipé. Si GitHub est illisible, le hook sort 0 et ne compte pas l'arrêt. OpenCode n'a pas de hook Stop. plugins/autonomy/index.ts lance le même script sur session.idle d'une session racine, transmet les sessions enfants en cours, et relance avec la raison (instructions/autonomy.md). Conductor et Monolith utilisent ce hook.

Quand ça escalade. skills/ship/SKILL.md (Human-only) s'arrête pour des identifiants manquants, des limites de compte ou de facturation, une panne externe, une décision produit que le dépôt ne peut pas trancher, ou une action de la liste interdite. Il s'arrête aussi sur la règle d'absence de progrès du skill, sur la sortie 3 de goal bump, et sur les plafonds du stop gate ci-dessus. Un finding gitleaks ou une exposition de secret arrête le run pour security-reviewer et une rotation. Un résultat Wait or cancel du contrôle des PR ouvertes escalade (skills/open-pr-check/SKILL.md). Le chemin bloqué conserve le worktree, la branche et le registre (skills/ship/SKILL.md, Blocked path).

Ce qu'il ne fait jamais. Hard limits de skills/ship/SKILL.md, et règle (d) de .claude/rules/common/autonomy.md :

  • Fusion uniquement par agent-harness ship-merge. Jamais gh pr merge, et jamais un push vers la branche de base.
  • Jamais git push --mirror, git push --all, ni --no-verify. Jamais affaiblir un check : sauter un test, un job ou un check requis, poser continue-on-error, supprimer un check, ou baisser un seuil.
  • Jamais retirer un worktree avec git worktree remove brut. agent-harness worktree-rm <path> --confirmed retire un worktree propre dont la branche est fusionnée (y compris un squash détecté par gh pr view --json state). agent-harness teardown-merged-worktree <pr> retire le worktree du goal enregistré après que cette PR est MERGED, en mode autonome, et supprime ses branches et son registre. Jamais supprimer une branche sauf par ce teardown ou agent-harness cleanup.
  • Jamais fusionner une PR qui correspond à protectedPaths tant que le flag est actif. Un humain passe --confirmed.
  • Jamais ajouter un label, publier un commentaire, ou créer un status pour passer un refus de ship-merge.
  • Jamais notifier un progrès. Le run ne déclenche ni build ni release.
  • Jamais retirer un goal bloqué ou escaladé.
agent-harness autonomy on|off|status     # bascule .claude/state/autonomy.on (gitignored, par machine)
/ship <goal>                             # clarifier, implémenter, PR, revue, CI, fusion
agent-harness ship-merge <pr> [--method squash|rebase|merge]  # seul chemin de fusion; ajouter --confirmed en mode interactif
agent-harness notify done "<msg>" <pr>   # notifier uniquement sur question, waiting, done, failure
agent-harness ship-init <type> <scope> <desc> --goal "<text>"  # première action de /ship : worktree du goal + registre (ou --adopt <pr>)
agent-harness goal decisions-path        # journal de décisions de ce checkout : .claude/state/decisions/<slug>.tsv par goal (créé par ship-init, archivé dans decisions/archive/ par le teardown), sinon .claude/state/decisions.tsv
agent-harness teardown-merged-worktree <pr>  # après MERGED : retire le worktree enregistré, les branches et le registre (lancé par ship-merge)
agent-harness cleanup <pr> [--keep-branch]  # après MERGED : supprime la branche de la PR et les backups du goal, archive sous `refs/harness/backups/` ceux que la fusion ne contient pas (PR non enregistrées ; aussi lancé par ship-merge)
agent-harness prune-backups [--confirmed]  # branches backup/* orphelines (aucun goal ni registre) : supprime celles déjà dans origin/<base>, archive les autres sous refs/harness/backups/ (simulation sans --confirmed)
agent-harness prune-branches [--confirmed]  # branches locales hors backup déjà dans origin/<base>, qu'aucun goal, registre, worktree ni HEAD ne réclame : les supprime ; jamais les branches distantes (simulation sans --confirmed)

Autre dépôt. ship-init, ship-merge, cleanup, teardown-merged-worktree, worktree-rm et goal acceptent un --repo <chemin absolu> final : une session dont le répertoire de travail est le dépôt A gère un goal du dépôt B sans Orca, par exemple agent-harness ship-init feat ui x --goal "..." --repo /chemin/abs/vers/B. Le chemin doit être la racine d'un checkout git : le checkout principal de B, ou un worktree de goal de B pour goal. Un chemin relatif, un sous-répertoire, un répertoire hors git, ou un --repo ailleurs qu'en dernier sont refusés. Le registre et l'état du goal sont ceux de B. Le stop gate de la session appelante lit toujours son propre checkout : il ne bloque pas sur le goal de B et ne s'y lie pas. ship-init --repo laisse un marqueur par utilisateur dans ~/.agent-harness/goals-foreign/. Tant que B garde des fichiers de goal, le git guard de chaque session fait passer chaque push par la vérification complète, qui soumet un push dans le worktree du goal de B aux revues de B. Le guard autorise exactement cette forme finale, en une commande simple. Un préfixe cd, un préfixe d'environnement comme CLAUDE_PROJECT_DIR=, et toute substitution restent refusés.

Le skill ship (skills/ship/) gère les étapes, et le skill autonomous pilote la bascule. Les règles de comportement sont dans .claude/rules/common/autonomy.md (Claude Code) et instructions/autonomy.md (OpenCode).

Configuration par repo. Chaque repo peut définir .claude/agent-harness.json. Toutes les clés sont optionnelles :

Clé Valeur par défaut (absente) Rôle
base la branche par défaut du repo (gh repo view) branche cible de la PR, et seule cible de fusion
requiredChecks [] noms de check-runs qui doivent conclure success, skipped ou neutral sur la tête
reviewStatus non défini (pas de garde-fou) optionnel. À définir seulement si le repo a un status check externe. Contexte du commit status qui doit valoir success sur la tête
reviewStatusCreator non défini (tout créateur) optionnel, utilisé avec reviewStatus. Login qui doit avoir publié le status
verify non défini (détection verification-gate) commandes lancées par l'étape verify du ship
protectedPaths non défini (pas de garde-fou) expressions régulières optionnelles. Quand la clé est définie, une PR qui touche une correspondance nécessite une fusion humaine (--confirmed, qui demande confirmation)
mergeMethod non défini (première méthode autorisée par le dépôt : squash, rebase, merge) squash, rebase ou merge optionnel ; remplacé par ship-merge --method
{
  "base": "main",
  "requiredChecks": ["build", "test"],
  "reviewStatus": "ci-review",
  "reviewStatusCreator": "github-actions[bot]",
  "verify": ["npm run lint", "npm test"],
  "protectedPaths": ["^\\.github/"]
}

Garde-fous de fusion. agent-harness ship-merge est l'étape de fusion de la boucle et le seul chemin de fusion. Il vérifie des faits concrets, pas des avis. Un refus est une entrée de la boucle : l'agent corrige la cause et relance. Il refuse, sauf si toutes ces conditions sont vraies :

  • le flag autonome est activé, ou --confirmed est passé
  • la PR cible la branche de base et n'est pas un brouillon
  • chaque entrée de requiredChecks a réussi sur la tête
  • zéro fil de revue non résolu
  • la branche est à jour par rapport à la branche de base
  • aucun chemin modifié ne correspond à protectedPaths, sauf si --confirmed est passé (un humain fusionne alors la PR)
  • seulement si reviewStatus est défini : le status le plus récent portant ce contexte sur la tête est success, et son créateur correspond à reviewStatusCreator si la clé est définie

Ensuite, la fusion est épinglée au SHA de la tête, puis agent-harness teardown-merged-worktree <pr> s'exécute pour un goal enregistré (sinon agent-harness cleanup <pr>). Le nettoyage supprime la branche de la PR sur le remote et en local (la branche locale seulement si elle est entièrement fusionnée), supprime les branches de backup enregistrées pour le goal, et place le checkout sur la base mise à jour. Le cleanup ne retire jamais de worktree ; il signale celui qui porte la branche. En mode autonome, le cleanup exige que le goal suive la PR ; une fois le worktree du goal retiré, l'entrée du registre en tient lieu seulement si c'est l'unique entrée de la PR, qu'elle enregistre la branche de tête de la PR, qu'elle n'est ni escalated ni blocked, que son chemin de worktree n'existe plus, et qu'aucun worktree n'a la branche extraite. Une PR non enregistrée est refusée. Le teardown retire le worktree du goal, ses branches et son registre, sous les checks de la règle de destruction des worktrees, sans toucher au checkout principal (cleanup --no-checkout). --keep-branch conserve la branche de la PR. La méthode se choisit avec --method squash|rebase|merge ; sans option, le script utilise mergeMethod de .claude/agent-harness.json, sinon la première méthode autorisée par le dépôt (squash, rebase, merge). Une méthode interdite par le dépôt est refusée.

Règles de push. Les pushes vers la branche de base sont interdits dans tous les modes, avec ou sans force. git push --mirror, --all et --no-verify sont aussi interdits. Les force pushes (--force, --force-with-lease, -f, +refspec) sont autorisés sur les autres branches.

Revue. L'étape 6 du ship lance une revue locale approfondie avant tout push : code-reviewer, security-reviewer, et le cop du stack (angular-cop ou dotnet-cop) sur le diff. L'agent corrige les findings Important confirmés, relance la revue après chaque correction (la boucle s'arrête quand les mêmes findings reviennent, avec un plafond de sécurité de 10 tours ; l'agent escalade alors avec les findings Important restants). Le garde de push refuse un push ou gh pr create sans verdict positif enregistré. L'agent publie, après l'ouverture de la PR, un commentaire de synthèse que l'humain peut auditer. Cette revue est une étape de qualité, pas un garde-fou de fusion. Aucun status GitHub n'est créé, et ship-merge ne fait pas confiance à ce commentaire.

Notifications. Le run notifie seulement quand un humain doit agir, ou quand l'objectif se termine : question quand il doit s'arrêter pour une réponse, waiting sur un prompt de permission ou d'inactivité, failure en cas d'escalade, et done quand la PR est fusionnée. Aucune notification de progression.

Limites.

  • Ce sont des garde-fous côté client, pas une frontière de sécurité. Un agent avec accès shell peut appeler gh directement.
  • La protection de branche sur la branche de base (reviews requises, checks requis, push restreints) est le vrai mécanisme d'application. À configurer sur l'hébergeur.
  • Une PR qui correspond à protectedPaths nécessite une fusion humaine (--confirmed), quand la clé est définie. Sans cette clé, le mode autonome fusionne toute PR qui passe les garde-fous.
  • OpenCode n'enregistre pas les hooks Claude Code. plugins/autonomy/index.ts lance autonomy-git-guard.sh avant chaque appel shell et ship-stop-gate.sh quand une session racine passe idle (instructions/autonomy.md).

Parité. Le mod de statut autonome (.claude/mods/, barre d'état et bandeau) est réservé à Claude Code. OpenCode n'a pas d'équivalent.

About

Custom OpenCode settings

Resources

Stars

170 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages