# Agent Fleet — Project Files

agent-fleet keeps up to two small files in a project's `.ai/` directory. They
have different readers and different lifetimes, so they are kept separate.

| File | Read by | When |
|------|---------|------|
| `.ai/agent-fleet-overrides.md` | `spec-driven-development`, `planning-and-task-breakdown`, `browser-testing-with-devtools`, `git-workflow-and-versioning`, `compound-learning` (the `rules:`/`docs:` keys of `## agent-hub`), `agent-hub` pi harness | Every run of those skills / every session start of the harness |
| `.ai/agent-fleet-setup.md` | `guided-workspace-setup` | Only when setup is run or re-run |
| `.ai/stt.json` *(optional)* | `pi-voice-stt` extension | Every pi session start, when the extension is installed |

The `.ai/stt.json` file is present only when the optional `pi-voice-stt` voice-dictation
extension has been configured (by guided setup or by hand). Like the overrides file it holds
**no secrets** — it names the env vars (`apiKeyEnv`, plus the Azure endpoint var) whose values
live in a gitignored root `.env`. See [pi-voice-stt config](#ai-sttjson) below.

Keep them split: the overrides file is loaded into context constantly, so it
must stay minimal; the install record is consulted rarely, so it can be large.

## The overrides file — `.ai/agent-fleet-overrides.md`

Some skills and pi harnesses need facts specific to each project — where specs
and plans are saved, how to start a dev server, whether the agent may create
branches, or which user-facing language a dispatcher should use. Each reader
ships a sensible **default**; a project that needs something different declares
it here, and the reader picks it up.

- **Location:** `.ai/agent-fleet-overrides.md` at the project root.
- **Format:** Markdown. One `## <section-name>` section per skill or harness reader, with terse
  `key: value` lines. Block values use the `key: |` multi-line form. No prose
  and no install detail — readers parse it by key and load it on every run/session start.
- **Commit it.** Shared project configuration belongs in version control. Make
  sure no `.gitignore` rule (for example a broad `.env*` pattern) excludes it.
- **No secrets.** For anything sensitive (test-account credentials), reference
  the **name** of an environment variable; the real value lives in a gitignored
  `.env`.
- If the file is absent, or a reader has no section in it, that reader uses its
  built-in default.
- **Validation.** Because an unknown section or key silently falls back to the
  default, typos are invisible at runtime. `agent-fleet doctor` (and the
  `/doctor-agent-fleet` command) validates the file — unknown sections,
  unknown keys in known sections, invalid values for the mechanically parsed
  `agent-hub` keys, missing `rules:` folders, and unset `## env` vars — as
  **advisory, warn-only findings**; it never edits the file.

### `spec-driven-development`

| Key | Default | Meaning |
|-----|---------|---------|
| `spec-dir` | `docs/prds/{area}` | Directory specs are written to |
| `naming` | `PRD{n}-{topic}` | File name pattern; `{n}` = next free PRD number, `{topic}` = kebab-case slug |

Default output: `docs/prds/{area}/PRD{n}-{topic}.md`.

### `planning-and-task-breakdown`

| Key | Default | Meaning |
|-----|---------|---------|
| `plan-dir` | `docs/plans/{area}` | Directory plans are written to |
| `naming` | `PLAN-{prd-name}-{phase}` | File name pattern; `{phase}` suffix only when a plan spans multiple files |
| `todo` | `embedded` | `embedded` keeps the task list inside the plan; `separate` writes a standalone `todo.md` |

Default output: `docs/plans/{area}/PLAN-{prd-name}-{phase}.md`, task list embedded.

### `browser-testing-with-devtools`

This skill has **no default** — the section is required for browser testing,
because dev-server commands and login flows cannot be guessed.

| Key | Meaning |
|-----|---------|
| `dev-server` | Command to start the local dev server |
| `ready-check` | How to confirm the server is up |
| `base-url` | Root URL for navigation |
| `auth-flow` | Steps to log in (multi-line `|` block) |
| `roles` | Test account per privilege level, referenced by env-var name |
| `notes` | Anything else the agent should know (certs, seed data, ...) |

### `git-workflow-and-versioning`

| Key | Default | Meaning |
|-----|---------|---------|
| `branching` | `never` | `never` = agent works in the current branch and never creates or switches branches; `allow` = agent may create feature branches |

### `agent-hub`

Read by the `.pi/harnesses/agent-hub/` pi harness on every session start. The canonical
section name is `## agent-hub`; the harness also accepts the legacy `## agent-team` name
(from before the standalone `agent-team` harness was retired), so existing project
override files keep working unchanged. When both sections are present their keys merge,
with later lines winning.

The `rules:` and `docs:` keys are also read outside the harness: the `compound-learning`
skill (and the `/compound` claude-code/opencode commands built on it) resolves them as the
targets an end-of-session compound pass writes lessons to.

| Key | Default | Meaning |
|-----|---------|---------|
| `language` | `English` | User-facing language the dispatcher uses for every `ask_user` question, every `context` field, and every summary. Specialist task strings always stay in English regardless. |
| `persona-gate` | `off` | When `on`, blocks input at session start until an orchestrator persona is picked. |
| `model.<persona>` | persona frontmatter `model:` | Replaces the named persona's default model for this project (a full pi model spec). |
| `models.<persona>` | persona frontmatter `models:` | Replaces the named persona's model-candidate list for `/agent-model` and `/models` profiles (comma-separated pi model specs). |
| `thinking.<persona>` | persona frontmatter `thinking:` | Replaces the named persona's pi `--thinking` reasoning level for this project: one of `off`, `minimal`, `low`, `medium`, `high`, `xhigh`. Switchable at runtime with `/agent-model-thinking <persona>`. An invalid value is ignored with a session-start warning. |
| `subagents.<persona>.<role>` | persona frontmatter `subagents:` | Replaces or adds one delegate sub-role for this project: `<model>[, tools=<caps>]`. Other declared roles keep their frontmatter values. |
| `delegate-depth.<persona>` | persona frontmatter `delegate_depth:` (default/max 1) | Replaces the persona's delegation depth budget: `0` makes its delegate tool refuse (delegation off for this project), `1` lets it spawn terminal children. Values above 1 are clamped to 1; children at remaining depth 0 do not receive delegate tooling. |
| `rules` | none | Comma-separated repo-relative folders holding the project's own rule files (HOW — implementation patterns the work must comply with). Resolution is **index-first**: when a folder has a top-level `README.md`/`index.md`, personas read it first and follow its loading manifest (session bundles, conditional-load lists) instead of bulk-reading the tree; a folder without an index is searched **recursively** through all subfolders. The harness tells every dispatched specialist where the rules live and how to resolve them; the planner and code-reviewer personas read the relevant rules, validate their subject against them, and pass them on (cited in plan acceptance criteria / handed to delegate sub-reviewers). Missing folders produce a session-start warning. |
| `docs` | none | Comma-separated repo-relative documentation **entry points** (WHAT/WHY — architecture, standards, decisions): canonical files (e.g. `Docs/AGENTS.md`) or doc folders (personas start from a folder's `README.md`/index). Unlike `rules`, docs orient rather than bind: every dispatched specialist and research helper is told to read the entry points relevant to its task and follow their links instead of bulk-reading doc trees; the code-reviewer flags changes that alter documented behavior without a doc update; the documenter treats the entry points and the trees they link as the docs it maintains. Missing paths produce a session-start warning. |
| `research-keep` | `4` | How many **finished** manual/persona research helpers the hub retains (LRU by finish time) so they stay resumable via `/agents-cont rN`; older ones are pruned along with their session files. `all` disables the cap. Auto-research pipe helpers (spawned for `NEEDS_RESEARCH:` pauses) are always pruned as soon as they finish — their findings persist as files under `.pi/agent-sessions/findings/`. Running helpers are never pruned. An invalid value is ignored with a session-start warning. |

Example — switch the dispatcher to Bulgarian, pin the builder to sonnet, raise the
code-reviewer's thinking level, move the code-reviewer's docs sub-reviewer to a
different model, and point the team at the project's rule folders and doc entry
points:

```markdown
## agent-hub
language: Bulgarian
model.builder: github-copilot/claude-sonnet-4.6
models.builder: github-copilot/claude-sonnet-4.6, github-copilot/claude-haiku-4.5
thinking.code-reviewer: xhigh
subagents.code-reviewer.docs: github-copilot/claude-sonnet-4.6, tools=read,grep
delegate-depth.code-reviewer: 1
rules: docs/rules, .ai/rules
docs: Docs/AGENTS.md, Docs/architecture/ARCHITECTURE_OVERVIEW.md
```

### `env` (optional, read by the doctor)

The overrides file references environment variables by **name** — test-account
credentials for `browser-testing-with-devtools`, the `pi-voice-stt` API key —
while the values live in a gitignored root `.env`. The optional `## env`
section declares which names the project's readers expect, so a fresh clone
can find out what's missing *before* a skill fails mid-run:

| Key | Meaning |
|-----|---------|
| `required` | Comma-separated env-var **names** (never values) the project's sections reference |

```markdown
## env
required: APP_TEST_ADMIN_USER, APP_TEST_ADMIN_PASS, AZURE_SPEECH_KEY
```

No skill or harness loads this section. Its only reader is `agent-fleet doctor`
(and `/doctor-agent-fleet`), which warns when a declared name is neither set in
the environment nor declared in the workspace root `.env`.

### Per-peer env files (`env_file:` in peers.yaml)

Fleet peers spawned by `just team-up` / `just hub-team` can carry their own
environment: an `env_file:` entry in `.pi/agents/peers.yaml` names a
**repo-relative** KEY=VALUE file (same format as `.env`, no shell evaluation)
that herdr injects into the peer's pane before the command runs — no `source`,
no leaking into sibling panes. The file must exist at spawn (team-up refuses
otherwise, never mid-run), and its **values never appear in `--dry-run`
output** — only the path. Keep these files gitignored exactly like the root
`.env` this section describes.

## The setup file — `.ai/agent-fleet-setup.md`

The `guided-workspace-setup` skill writes this file to record what it installed
into the project — which skills, commands, personas, and extensions, by what
method, and when. It reads the file on a re-run to add, update, or remove
artifacts without reinstalling everything. No other skill loads it.

| Section | Meaning |
|---------|---------|
| `workspace-summary` | Workspace path, coding agent, **agent-fleet version**, project shape, checks discovered |
| `install-status` | Installed artifacts, their targets, and the method (`copy` or `symlink`) |
| `doctor-runs` | One line per doctor pass (preflight / postflight, repaired / deleted / skipped counts) |
| `verification` | Checks confirming the install |

### The `version:` line

`workspace-summary` carries a `version:` line set to the package version that
performed the install (e.g. `version: 1.4.2`). It drives the version-aware
update flow — on every re-run, `guided-workspace-setup` compares this against
the current package version and:

1. Reads `CHANGELOG.md` between the two versions.
2. For each installed artifact, runs a three-way diff between
   *source@recorded*, the installed copy on disk, and *source@current*.
3. Surfaces the result in the install menu using these `Status` values:

| Status | Meaning |
|---|---|
| `installed · upgrade available` | Source changed upstream; user copy still matches the old source → clean refresh |
| `installed · conflicting upgrade` | Source changed upstream AND user modified the copy → menu shows the three-way diff before overwriting |
| `installed · removed upstream` | Artifact gone in the new version → menu proposes deletion (subject to the removal-scope rule) |
| `not installed · new in this version` | New artifact added in the new version → menu offers it, marked `★` if recommended |

The diff sources at *source@recorded* are read from the package's
`.versions/<x.y.z>/` snapshot tree, which the release pipeline writes for every
published version. If the snapshot is missing (e.g. an unpublished local
build), the skill falls back to "treat installed copy as canonical" and
prompts for an explicit baseline.

### Pre-versioning workspaces

A workspace whose `agent-fleet-setup.md` predates the `version:` line is
treated as "pre-versioning". On first re-run, `guided-workspace-setup` prompts
for a clean baseline: either accept the installed artifacts as matching the
current source (stamp the current version), or re-run the install from scratch.

Commit this file if the team should share install state — keep paths relative
so it stays portable. A self-referencing checkout (agent-fleet itself) may
instead `.gitignore` it, since its recorded paths are local to one machine.

## The `/orchestrate` command and its team config

`/orchestrate` turns the main session (Claude Code) or primary agent (OpenCode)
into an **orchestrator** that drives a config-defined team of installed
subagents — subagents cannot nest, so all dispatching is the main session's job.
The default team is `planner` + `builder` (no reviewer); the orchestrator routes
the team as a **runtime roster, not a fixed `researcher → planner → builder`
pipeline** — it skips planning when a plan already exists, re-runs `researcher`
at any point, and loops back to `planner` when the build surfaces a wrong plan.
It honours the existing subagent handoff markers: `PLAN_FILE: <path>` from the
planner, and `NEEDS_RESEARCH: <question>` from planner/builder (which dispatches a
read-only `researcher` and resumes the paused persona with the findings inlined).

The named teams live in a per-agent config that mirrors pi's
`.pi/agents/teams.yaml` (a map of team-name → ordered persona list, first key =
default; `researcher`/`deep-researcher` deliberately unlisted but always
available). The reader differs by runtime: pi's harness parses its YAML, while
`/orchestrate` has the **command's instructions** read the YAML via the Read tool
(no harness runtime in claude-code/opencode):

| | Config file | Command |
|---|---|---|
| claude-code | `.claude/orchestrate-teams.yaml` | `/orchestrate` |
| opencode | `.opencode/orchestrate-teams.yaml` | `/af-orchestrate` |
| pi | `.pi/agents/teams.yaml` | via the `agent-hub` harness (no `/orchestrate`) |

Switch teams at runtime with `/orchestrate <team> "<task>"` (parallel of pi's
`/agents-team`); use `/orchestrate team=<name> <task>` to disambiguate when the
task text starts with a word that collides with a team key.

**Guided-setup behaviour.** `guided-workspace-setup` offers `/orchestrate`
**`★`-recommended** for claude-code + opencode (hidden for pi via the existing
source-availability filter — there is no `.pi/prompts/orchestrate.md`), and
installs the agent's `orchestrate-teams.yaml` as a **companion** of the command
(a user-edited config is preserved on uninstall, never silently clobbered).
Two artifacts stay **claude-only**: the lifecycle **hooks** (they register into
`.claude/settings.json`, which opencode/pi have no install path for) and the
**`AskUserQuestion` questionnaire menu mode** (the primary menu interaction on
claude-code). The orchestrate command and its team config are *not* claude-only —
they ship for opencode too.

## Templates

### `.ai/agent-fleet-overrides.md`

Copy this in and delete the sections you don't need — anything absent falls
back to that reader's default.

```markdown
# Agent Fleet — Project Overrides
#
# Each section is applied ON TOP of the skill's built-in defaults.
# Keys not listed keep the default. Absent file/section → pure defaults.

## spec-driven-development
spec-dir: docs/prds/{area}
naming:   PRD{n}-{topic}

## planning-and-task-breakdown
plan-dir: docs/plans/{area}
naming:   PLAN-{prd-name}-{phase}
todo:     embedded

## browser-testing-with-devtools
dev-server:  <command to start the local dev server>
ready-check: <url or check that confirms the server is up>
base-url:    <root url>
auth-flow: |
  1. Navigate to <login url>
  2. Submit credentials for the role needed by the screen under test
roles:
  admin:  env APP_TEST_ADMIN_USER / APP_TEST_ADMIN_PASS
  player: env APP_TEST_PLAYER_USER / APP_TEST_PLAYER_PASS
notes: |
  <anything else: self-signed certs, required seed data, ...>

## git-workflow-and-versioning
branching: never

# Optional for pi agent-hub; omit this section to keep default English.
# (`## agent-team` is still accepted as a legacy alias for this section.)
## agent-hub
language: <language name>
rules: <repo-relative rule folder>[, <another folder>]
docs: <repo-relative doc entry point>[, <another file or folder>]

# Optional; names (never values) of env vars the sections above reference.
# Only `agent-fleet doctor` reads this — it warns when one is unset.
## env
required: <ENV_VAR_NAME>[, <ANOTHER_NAME>]
```

### `.ai/agent-fleet-setup.md`

Written and maintained by `guided-workspace-setup`; shown here for reference.

```markdown
# Agent Fleet — Workspace Setup
#
# Maintained by the guided-workspace-setup skill.

## workspace-summary
agent:   claude-code
method:  copy
version: 1.4.2
shape:   <one line on the project shape>

## install-status
skills:     [spec-driven-development, test-driven-development, code-review-and-quality]
commands:   [spec, plan, build]
personas:   [code-reviewer]
extensions: []
harnesses:  []
harness-support: []   # justfile (managed region) + scripts/agents companions; tracked when any harness is installed
updated:    2026-05-22

## verification
- Every recorded artifact exists at its target path.
- No secrets are stored in this file.
```

### `.ai/stt.json`

Optional. Present only when the `pi-voice-stt` extension is installed and configured. Read by
the extension on every pi session start, ahead of the global `~/.pi/agent/stt.json`. Holds the
non-secret provider config; the API key (and Azure endpoint) live in a gitignored root `.env`
as named env vars, which the `justfile`'s `dotenv-load` exposes to the session.

```json
{
  "language": "bg-BG",
  "provider": {
    "type": "azure",
    "apiKeyEnv": "AZURE_SPEECH_KEY",
    "locales": ["bg-BG", "en-US"]
  }
}
```

Corresponding gitignored `.env` at the repo root:

```sh
AZURE_SPEECH_ENDPOINT=https://<resource>.cognitiveservices.azure.com
AZURE_SPEECH_KEY=<your-resource-key>
```

For the OpenAI-compatible backend, `provider.type` is `openai` with `baseUrl` / `model` and an
`OPENAI_API_KEY` env var instead. Full schema: [.pi/extensions/pi-voice-stt/README.md](../.pi/extensions/pi-voice-stt/README.md).
