Roadmap
Canonical sequencing for project-agent-manager (binary pam). Each phase delivers a working increment and ends at a gate expressed as commands to run or outcomes to observe — never as a vague quality adjective. Beyond Phase 0, dates are deliberately omitted: the contract here is ordering and gates, not scheduling.
Companion doc: 071-risks-and-open-questions.md (risk register, open questions, decision schedule).
1. Product frame (context only)
pam is a multi-host, central-orchestrated platform that combines hierarchical project/task management (Project → Milestone/Epic → Task → Subtask; board columns todo/doing/done/cancelled) with AI task orchestration driving subscription LLM CLIs (claude/codex/grok/gemini) inside tmux sessions on each execution host (dedicated socket pam, session names pam-<8hex>), live-observable from a web dashboard embedded in the orchestrator binary via rust-embed. A central orchestrator (pam serve) owns the API, dashboard, and PostgreSQL; workers (pam worker) on Unix hosts (macOS primary, Linux secondary — ADR-011) execute the sessions over outbound-only connections (ADR-012). Windows and mobile are excluded. Headless -p execution is excluded by design. Details live in 001-system-overview.md and 030-http-api.md / 040-cli.md — this file does not restate them.
2. Phase overview
Status legend: planned / in-progress / done / superseded.
3. Dependencies
graph LR
P0["Phase 0 — scaffold + docs"] --> P1["Phase 1 — PM domain"]
P1 --> P2["Phase 2 — tmux executor v1"]
P1 --> P3["Phase 3 — web SPA v1"]
P2 --> P4["Phase 4 — provider adapters"]
P2 --> P5["Phase 5 — interactive attach"]
P3 --> P5
P5 --> P6["Phase 6 — desktop shell + packaging"]
In words:
- Phase 1 requires Phase 0 (scaffold to build on).
- Phase 2 requires Phase 1 (runs reference tasks/work items in the store).
- Phase 3 requires Phase 1 (SPA renders PM data). It does NOT require Phase 2: the live-pane gate can be exercised against any session on socket
pam, including one started by hand — though in practice Phase 2 will usually be available. - Phase 4 requires Phase 2 (adapters execute through the worker’s executor).
- Phase 5 requires Phases 2 + 3 (worker sessions to attach to; SPA to host xterm.js).
- Phase 6 requires Phase 5 (the shell wraps the full interactive product; the shell choice is settled — Tauri v2, ADR-006 — but is not exercised before then).
4. Phase details
Phase 0 — Foundation: docs, scaffold, CI (current)
Status: in-progress (started 2026-08-29).
Note (2026-08-29, later same day): the design pivoted to the multi-host topology — PostgreSQL backend, central orchestrator + per-host workers (ADR-012). Phase 0 deliverables (docs, compiling scaffold, CI) keep their shape; the store crate adopts PostgreSQL and the worker command appears at Phase 1/2 as written below.
Scope:
- Docs tree: 001-system-overview.md, 002-data-model.md, 010-tmux-executor.md, 020-provider-adapters.md, 004-implementation-reference.md; 030-http-api.md and 040-cli.md; 050-ui-dashboard.md; roadmap + risks (this pair). Four mermaid diagrams under
docs/assets/diagrams/. - Cargo workspace scaffold: 5 crates (pam-core, pam-store, pam-executor, pam-api, pam-cli), each compiling with a smoke test.
- CI workflow running the full verification chain on every commit.
Gate (runnable, all must exit 0):
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo build --workspace
cargo test --workspace
Plus observable outcomes: docs link/frontmatter checks pass; git log --oneline main shows the Phase 0 commits. Commits are local only — push is deferred to September 2026 (OQ-1 in the risks doc); the remote URL is unconfirmed until then.
Phase 1 — PM domain
Scope:
- pam-core: domain types for the hierarchy (Project → Milestone/Epic → Task → Subtask) and statuses (todo/doing/done/cancelled); board column semantics (a move is a status change).
- pam-store: sqlx migration 0001 implementing the PostgreSQL schema from the 002-data-model.md;
Storetrait;PgStore;MemStoregated behind a test-support feature. - pam-cli + pam-api:
pam serve,pam migrate,pam project add/list/show/archive,pam task add/list/show/move/board/done— all commands through the central API (ADR-007).
Gate (runnable):
- Against a PostgreSQL instance (ephemeral container acceptable):
pam task add→pam task list→pam task move→pam task doneround-trips;pam task showreflects each transition. - Parity: the shared, parameterized Store test suite runs against both
PgStoreandMemStoreand passes identically. pam task boardrenders the todo/doing/done/cancelled columns with tasks placed by status.
Exit note: the pam binary/crate prefix freezes at Phase 1 exit (OQ-2); blocked-as-label and hierarchy depth defaults (OQ-6) must hold or be overturned by then.
Phase 2 — worker + tmux executor v1
Scope:
- Worker agent:
pam workerregisters outbound with the orchestrator (worker token), heartbeats, and executes dispatched runs;pam host add/list/disable/enablemanages the registry. - Spawn:
tmux -L pam new-session -s pam-<8hex>withpam exec run <id>as the session’s foreground wrapper process; the wrapper fetches its run spec from the central API and spools signals across partitions. - Persisted session registry mapping runs to hosts and session names; reconciliation on worker start adopts known sessions and flags unknown
pam-*ones; orchestrator marks hosts offline on heartbeat loss without force-failing their runs. pam run start/list/stop/logs/paneand web-relayed attach; local CLI attach only for runs on the local host.- tmux safety 4-rules enforced in code, per the 010-tmux-executor.md: dedicated socket
pamonly (never the default socket); session-name regex^pam-[0-9a-f]{8}$validated before any tmux command; cleanup limited to own sessions on socketpam; send-keys allowlist.
Gate (runnable):
- Start a run with a stub echo-CLI provider:
pam run listshows it with its host,pam run paneshows its output,tmux -L pam list-sessionson that host shows exactly thepam-<8hex>session. - Crash path:
kill -9the worker, restart it;pam run listreconciles — every run appears exactly once (no duplicates) and everypam-*session on socketpamis accounted for by the registry or cleaned up (no orphans). - Partition path: stop the orchestrator mid-run, restart it; the wrapper’s spooled
run.started/run.finishedsignals replay and the run record converges without manual repair. - Duplicate-delivery path: POST the same one-shot signal (e.g.
run.finished) twice; the run record shows exactly one status transition and theeventsjournal holds exactly one journalled event for it — signal delivery is idempotent, no phantom transition. - Stale-attempt path: POST a signal stamped with an
attemptolder than the run’s currentruns.attempt(a dead incarnation’s late replay); afterwards both therunsrow and theeventsjournal are unchanged — no status write, no event emitted. - Safety path: with a decoy session present on socket
pamunder a non-conforming name, and an unrelated session on the default socket,pam run stop/cleanup leaves both decoys untouched (verify withtmux -L pam list-sessionsandtmux list-sessions).
Phase 3 — web SPA v1
Scope:
- Leptos scaffold under
web/(a Cargo workspace member);trunk build --releaseoutputweb/distembedded into pam-api via rust-embed. - axum serves the SPA, the HTTP API per 030-http-api.md, and an SSE endpoint streaming the read-only pane.
- UI: projects list, board, task detail, live read-only pane.
- Auth posture: bearer token over TLS (users/CLI) + separate worker token (OQ-7 superseded by ADR-012; see OQ-10) — no accounts.
Gate (runnable/observable):
cargo build --workspacesucceeds withweb/distembedded: run the built binary withweb/distrenamed away on disk — the SPA still serves (proves embedding, not static-file serving).- Browser at
127.0.0.1:PORTshows the board populated with real data and a live-updating pane from a running session (a session started viapam run start, or any session on socketpamcreated by hand).
Phase 4 — provider adapters
Scope:
- Provider catalogs for claude/codex/grok confirmed + gemini optional if installed as TOML (argv templates, env mapping, hook config, version constraints), per the 020-provider-adapters.md.
- Env normalization + proxy injection applied by the
pam exec runwrapper pre-spawn:ANTHROPIC_BASE_URL/OPENAI_BASE_URL/GEMINI_BASE_URLplusHTTP(S)_PROXY. - Completion ladder in code: manual > wrapper journal > provider-native hooks POSTing
/api/internal/runs/{id}/signals; the pane-idle heuristic is a UI hint only. Provider hooks ship behind a config flag (off by default). - Restart policy: bounded retries with backoff, configurable per provider.
pam provider doctor: CLI presence/version against catalog constraints, catalog validity, tmux >= 3.3.
Gate (runnable):
- Two real providers each complete a scripted task end-to-end from
pam run startto a recorded completion, with DISTINCT completion signals: one run’s completion captured via wrapper exit (journal), the other via a provider-native hook POST — the signal source is visible and different in the two run records. pam provider doctorexits 0 on the dev machine.
Exit note: task-status auto-transition on a trusted signal stays config-gated and OFF by default unless OQ-5 is overturned by this gate.
Phase 5 — interactive attach
Scope:
- WS attach endpoint + PTY relay: portable-pty hosting
tmux -L pam attachfor the target session. - Single-writer lease per run: acquire/renew/release; lease state visible via the API; clear rejection error for a second writer.
- xterm.js client rendering bidirectional IO; read-only viewers multiplex the same outbound stream with no input path at the protocol level; activity feed UI.
Gate (runnable/observable):
- Browser A attaches to a run and types; the keystrokes are visible in the tmux pane (verify via
tmux -L pam capture-pane -por by observing output) and stream to Browser B, which remains read-only. - While A holds the lease, an attach attempt from Browser C (or a re-attach attempt from B) is rejected with a clear lease error (observable HTTP/WS error) and no input flows from the rejected client.
Phase 6 — desktop shell + packaging
Scope:
- Implement the Tauri v2 shell (decision accepted 2026-08-29 — monitoring thin client, never an execution node; comparison record in 050-ui-dashboard.md; formerly OQ-4, resolved). Shell targets macOS and Linux desktops, matching the execution node (ADR-011); the macOS build ships first and the Linux build follows the Linux execution-node verification (OQ-9).
- Implement the chosen shell as a wrapper: sidecar daemon or linked core — the web UI codebase stays single-source.
- cargo-binstall metadata; release polish (app icon, naming, packaging defaults).
Gate (runnable/observable):
- The built
.app(or dmg) launches on the dev Mac, starts or attaches to the same core, and passes the Phase 3 gate through the shell webview: board and a live-updating pane visible in the shell window. - cargo-binstall metadata is present and validates locally (dry run, no network publish required).
5. Deferred / backlog (explicitly out of scope for now)
6. Gate conventions
- All commands run from the repository root on the dev machine (currently macOS — the primary worker platform per ADR-011; the secondary Linux target is verified per OQ-9 when a Linux environment is available).
- From Phase 1 on, gates assume a reachable PostgreSQL (a local ephemeral container is acceptable) and a locally running orchestrator + worker (
pam serve+pam workeron the same machine is the dev shape of the multi-host topology). - Where a gate is an observable outcome (browser, tmux pane), the observation is the verification; record the result by updating the phase status and
last_verifiedin this frontmatter. - CI runs the headless subset of gates (fmt, clippy, build, test, docs checks). Browser- and tmux-interactive checks are verified manually at phase exit.
- A phase flips to
doneonly when every item in its gate has passed; partial completion keeps itin-progresswith a note.
References
- 001-system-overview.md — system architecture
- 002-data-model.md — schema and store design
- 010-tmux-executor.md — executor and tmux safety rules
- 020-provider-adapters.md — catalogs, env injection, completion ladder
- 030-http-api.md, 040-cli.md — interface contracts
- 050-ui-dashboard.md — dashboard IA and shell comparison
- 071-risks-and-open-questions.md — risk register and open questions