How it works
From one goal to a plan you can follow
Six stages, in a loop. You say what you want. PO plans it, orders the tasks, recalls what the project knows, runs the work, checks it and saves what was learned. Under each stage you can open the technical details.
Plan → Order → Recall → Run → Verify → Learn, then back to Recall. What stage 6 saves is what stage 3 recalls on the next plan.
The loop
The loop, stage by stage
Scroll: each picture is drawn like the screens of the product. The example is a team weekend.
Stage 1 of 6
You say what you want, you get a plan
You describe the result in one sentence. The assistant turns it into a plan with tasks. Each task has steps, and each step says how to check it is done.
Under the hood
The result is saved as a plan with a priority and its constraints, then split into tasks. Each task says what it depends on and lists its steps. Each step carries the check that proves it is done.
Plans, tasks and steps are saved as data, not as free text in a chat. The screens and the runner read the same statuses.
plan(action: "create", title, description, priority: 8, constraints: [{ constraint_type: "performance", … }])task(action: "create", plan_id, title, depends_on: [task_id], steps: [{ description, verification }])- Plan status: draft, approved, in_progress, completed, cancelled.
- Constraint types: performance, security, style, compatibility, other.
- code(action: "plan_implementation", auto_create_plan: true) drafts a plan from the code graph.
Stage 2 of 6
Tasks that do not depend on each other go together
PO sorts the tasks. A task waits only for the tasks it needs. All the others can start now, at the same time.
Under the hood
A task starts only when everything it depends on is completed. PO turns these links into waves: wave 1 holds every task with no unmet prerequisite, wave 2 holds what wave 1 unlocks, and so on.
Tasks in the same wave are independent, so they run at the same time. The longest chain of dependencies, the critical path, sets the minimum number of waves.
plan(action: "get_waves", plan_id)plan(action: "get_critical_path", plan_id)- plan(action: "get_dependency_graph") returns the task DAG.
- task(action: "get_next") returns the next unblocked task, highest priority first.
- When a run is resumed, waves are recomputed and finished waves are skipped.
Stage 3 of 6
The assistant looks up what the project already knows
Before each task, the assistant reads the notes and decisions that apply. So it does not ask the same questions again.
Under the hood
Before a task, the assistant reads the project memory: notes (warnings, guidelines, patterns), decisions with their reasons and, for a code project, the code around the files it will touch. A search by meaning finds the closest matches first.
Then PO follows the links between notes. A note that did not match the question can still appear, because a note that did match is strongly linked to it. The link weakens at each step, and notes that have faded are left out.
note(action: "search_semantic", query, project_slug)decision(action: "search_semantic", query)admin(action: "search_neurons", query, max_hops: 2)note(action: "get_context", entity_type: "file", entity_id)- Spreading activation defaults: 20 seed notes, 2 hops, the signal halves at each hop, 10 results.
- 40% of the result slots are reserved for notes reached through synapses.
- A propagated score is the parent score x synapse weight x note energy x decay.
Stage 4 of 6
Assistants do the tasks, group by group
Each task goes to its own assistant. The tasks of a group run at the same time, and the next group waits.
Under the hood
plan(action: "run") starts the runner on its own git branch. For each wave it starts one agent session per eligible task and runs them in parallel, up to a limit (4 by default).
Each task gets a prompt built from the project memory: its description, steps and constraints, the notes linked to it, the persona and skills that match, and a summary of what earlier waves did. A guard watches the session for idle time, repeated calls and timeouts, and sends a hint when the agent drifts.
plan(action: "run", plan_id, cwd, project_slug)plan(action: "run_status", plan_id)- A task is profiled simple, complex or creative from its tags, steps and files. The profile sets its time limit and cost budget.
- Simple: 600 s and $0.50. Complex: 3600 s and $2.00. Creative: 1800 s and $1.00.
- Runs are saved, so a run can be resumed after a restart. plan(action: "cancel_run") stops one.
Stage 5 of 6
A group is done when its checks pass
Before the next group starts, PO checks the work. The steps must be closed and no sensitive file may be left in the changes. For a code project, PO also checks that it still builds.
Under the hood
When a wave ends, the runner verifies it before the next one starts. It checks that the agents produced commits, that every step is completed or skipped, that the project builds and that the diff contains no sensitive file.
The run itself is a state machine. A lifecycle protocol moves from approved to executing to post_run, and every move needs an explicit trigger. A task whose agent fails or times out is retried once by default, with the error as context.
protocol(action: "transition", run_id, trigger: "child_completed")step(action: "get_progress", task_id)- Build check: cargo check, npm run build or go build ./..., by detected language.
- Sensitive files refused: .env, credentials.json, *.pem, *.key and similar.
- Tests are an option, off by default. plan-runner-reviewed adds an awaiting_review state for a person.
Stage 6 of 6
What was learned is saved for next time
When the work is done, what was decided and learned is written back to the project memory. The next plan starts with it.
Under the hood
When a task completes, the runner writes back without calling a model: it links the commits to the task and the plan, creates a context note from the git log, and ties decisions to the files they affect.
The assistant adds what only it knows: decisions with their alternatives, warnings, patterns. Notes used together grow closer. Notes that are never used lose energy and go stale. An episode records the request, the path through the states and the outcome. The next plan starts at stage 3 with all of it.
decision(action: "add", task_id, rationale, alternatives)note(action: "create", note_type: "gotcha", content, anchors)episode(action: "collect", run_id, project_id)admin(action: "reinforce_neurons", note_ids)- Staleness grows with the time since the last activity, at a rate that depends on the note type. note(action: "confirm") resets it.
- Skills emerge from clusters of strongly linked notes (admin(action: "detect_skills")).
Responsibilities
Who does what
PO handles the mechanics, so the assistant can focus on the work.
PO does, without being asked
- Sorts the tasks into groups and starts the assistants.
- Checks each group: steps closed, no sensitive file, and the build for a code project.
- Links the changes to the task and writes a note about what happened.
- Keeps the changes of each run on its own git branch.
- Records which persona and skills helped.
The assistant does, through its tools
- Searches notes and decisions before it starts.
- Creates plans, tasks and steps, and updates their status.
- Saves decisions with their alternatives and what they affect.
- Writes warnings, guidelines and patterns, tied to what they are about.
- Moves a procedure forward, step by step.
Entry points
Three ways to start the loop
From your AI tool
Claude Code, Cursor or another AI tool connected to PO. You describe the result. It plans, orders and recalls, then saves what it learned at the end.
From the chat
The chat built into PO talks to the same assistant. Each message carries the matching skills, the notes and decisions that apply, and what is in progress.
On its own
A plan can run when nobody is there. It starts on a schedule or when an event happens, with a pause between two starts. The start types are schedule, webhook, event and chat.
Memory
PO remembers what you decide and learn
Notes, decisions and the links between them stay attached to your project. PO finds them again when they are useful. Scroll to watch a memory grow.
Invented example: a small event project. The names in the graph are illustrations, not your data. Colors and shapes are those of the product graph.
1 of 5
Your files become dots
PO starts from what is in the project: documents, spreadsheets, files. Each one is a blue dot.
2 of 5
Plans and tasks join in
Plans and tasks are added to the same picture. Each task is linked to the files it touches.
3 of 5
Notes and decisions stay linked
What you learn becomes a note. What you decide becomes a decision. Both stay linked to the files and to each other.
4 of 5
Related things group together
Items about the same subject move close to each other. You see the main themes of the project at a glance.
5 of 5
PO finds the answer along the links
You ask a question. PO finds the notes that match (cyan). Then it follows the links to related items (violet), even when the words are different.
Under the hood: the names of the links
These are the names the product uses for the links in its graph. You do not need them to use PO.
- CONTAINSA plan contains its tasks.
- IMPORTSA file uses another file.
- AFFECTSA task touches a file.
- CO_CHANGEDTwo files that often change together, seen in the history of the code.
- SYNAPSEA link between notes, decisions and files. Links nobody uses fade away.
Try it
Watch an assistant work with PO
Pick a request. You see the answer in plain words, and the calls the assistant makes to PO behind the scenes. Open a call to see its details.
Two notes apply: the place must be close to a train station, and last year the menu had nothing vegetarian. I will write the plan around both.
The plan has 3 tasks in 2 waves. The shortlist and the date poll do not depend on each other, so they happen at the same time. Booking waits for both.
Simulated demo: the answers are scripted and no server is contacted. The calls and their arguments are the real ones.
Get started
Give your agents a memory and a plan
Install the orchestrator, connect Claude Code over MCP, and let your first agent read the project before it writes a line.
Or start from the terminal
brew install this-rs/tap/project-orchestrator