The PO's job is to manage projects on request, not watch them live. Remove the hourly wake/sweep entirely: - agents.toml: watch="heal" (recover-if-dead), no `wake` field - prompts/supervise.md: deleted - prompts/orchestrator.md, README.md, docs/bootstrap.md, docs/manage-projects.md: drop sweep/wake references; document operator-driven, no periodic sweep Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.0 KiB
Managing projects — the PO runbooks
These are the flows the project-orchestrator (the AI in prompts/orchestrator.md, or a human
operator) follows. The PO is AI-driven, not contract-bound: for any harness it doesn't already
know, it reads that harness's docs and works out how to drive it. The helper scripts here cover the
common agent-orchestrator case; treat them as conveniences, not a rigid interface.
The one invariant across every flow: knowledge is one-directional (PO → project). Nothing about the PO or the fleet is ever written into a project repo.
Create a project
Goal: a new, self-contained project repo — the chosen harness vendored as engine/ at a pinned
ref, a harness config scaffolded by that harness, and no PO/fleet metadata — plus (separately) a
fleet.toml entry on the PO side.
scripts/create-project.sh <name> \
[--dir <parent>] # where to create it (default: ./projects)
[--engine-url <url>] # harness repo (default: the agent-orchestrator repo)
[--ref <ref>] # harness ref to pin (default: v0.1.0)
[--prefix <session-prefix>] # tmux namespace in the config (default: <name>-)
[--register] # also append a [[project]] entry to fleet.toml
What it does, step by step (so the PO can also do it by hand for a non-default harness):
git init -b main <parent>/<name>.- Vendor the harness:
git submodule add <engine-url> engine, thengit -C engine checkout <ref>. The submodule pin is the recorded harness version inside the project (no other metadata). - Scaffold the harness config with the harness's own initializer
(
python3 engine/agents.py init .), and stamp a uniquesession_prefix. This writesagents.toml+prompts/— harness config only. - Add a
.gitignorefor runtime state (.ao-state/), and an initial commit. - Separately (only with
--register, or by hand): append a[[project]]block to the PO'sfleet.toml. This is PO-side; it never lands in the project.
Verify the new project standalone — it must work with no knowledge of any PO:
( cd <parent>/<name> && python3 engine/agents.py status )
And confirm isolation — the project must contain no PO/fleet metadata:
cd <parent>/<name>
grep -ril -e 'fleet' -e 'project-orchestrator' -e 'project orchestrator' . --exclude-dir=engine --exclude-dir=.git || echo "clean: no PO/fleet metadata"
(Exclude engine/ — that's the upstream harness, whose own docs legitimately describe being
driven by a PO; that is the harness documenting a consumer, not this project knowing about a fleet.)
Start / stop a project
Drive the project's harness. For an agent-orchestrator project:
scripts/start-project.sh <name> [agent...] # → engine/agents.py up (in the project dir)
scripts/stop-project.sh <name> [agent...] # → engine/agents.py down
Both resolve <name> → location via fleet.toml. For a remote-only location, clone it locally
first. For a non-agent-orchestrator harness, the wrapper bows out — read that harness's docs and
drive it directly.
Update a project's harness
Bumping the engine is per-project and opt-in — it touches only that project's repo; every other project keeps its own pin, so one bump can't break another.
scripts/update-project.sh <name> <new-ref> # checkout new ref in the project's engine/ + commit
Then update the project's ref in fleet.toml and python3 scripts/fleet.py validate.
List / status the fleet
python3 scripts/fleet.py list # one line per project: name, enabled, harness@ref, location
python3 scripts/fleet.py status # + a total/enabled/disabled summary
This reads only fleet.toml. To also check live state, drive each enabled project's harness
(engine/agents.py status --config <project>/agents.toml). The PO does this on request — there
is no periodic fleet sweep; this repo manages projects when asked, it does not watch them live.