feat: project-orchestrator — engine@v0.1.0 submodule, PO config, fleet.toml registry, mgmt scripts, docs, Nix
The PO is itself a project using the agent-orchestrator harness (engine/ submodule pinned at v0.1.0). Adds: agents.toml (one persistent fleet-management agent) + prompts/; fleet.toml (the sole project<->harness<->ref registry) + docs/fleet-registry.md; scripts/ (fleet.py + create/start/stop/update-project.sh); docs/manage-projects.md + docs/bootstrap.md; flake.nix/.lock devShell (python311+tmux+git); README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
95
docs/manage-projects.md
Normal file
95
docs/manage-projects.md
Normal file
@ -0,0 +1,95 @@
|
||||
# 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.
|
||||
|
||||
```bash
|
||||
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):
|
||||
|
||||
1. `git init -b main <parent>/<name>`.
|
||||
2. Vendor the harness: `git submodule add <engine-url> engine`, then `git -C engine checkout <ref>`.
|
||||
The submodule pin **is** the recorded harness version inside the project (no other metadata).
|
||||
3. Scaffold the harness config with the harness's own initializer
|
||||
(`python3 engine/agents.py init .`), and stamp a unique `session_prefix`. This writes
|
||||
`agents.toml` + `prompts/` — **harness config only**.
|
||||
4. Add a `.gitignore` for runtime state (`.ao-state/`), and an initial commit.
|
||||
5. **Separately** (only with `--register`, or by hand): append a `[[project]]` block to the PO's
|
||||
`fleet.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:
|
||||
|
||||
```bash
|
||||
( cd <parent>/<name> && python3 engine/agents.py status )
|
||||
```
|
||||
|
||||
And confirm isolation — the project must contain **no** PO/fleet metadata:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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`) — `prompts/supervise.md` does this on the
|
||||
PO's periodic wake.
|
||||
Reference in New Issue
Block a user