Agent workflows
Advanced feature
Agent workflows are an advanced, developer-facing capability for orchestrating AI agents against a Noted folder. They are driven through the MCP server; ordinary note-taking never requires them. The in-app Agent panel appears only for notes that already contain agent-workflow metadata.
Agent workflows turn a Noted folder into an agent workspace using a file-first protocol: the plan, tasks, runs, reviews, and state all live in normal notes, as visible JSON you can read and repair by hand. A shared runtime engine — used by both the MCP server and the app — enforces the state machine, approval gates, and task dependencies so state cannot drift into an illegal shape.
The mapping
| Note | Role |
|---|---|
| Folder | The project or codebase workspace |
| Workflow note | Goal, task index, global state, and event log |
| Task note | One task or subtask, with acceptance criteria and evidence |
| Runs note | Command executions: sandbox notes, timeouts, exit codes, output |
| Reviews note | Model or human review findings |
| Output note | The final acceptance check |
The model stays flat because the note store allows one level of folders. Tree structure is encoded by stable IDs and parentId fields, not by nesting.
File names
Use deterministic names inside the project folder:
project-folder/
wf-WF001-agent-runtime.md
task-T001-schema.md
task-T001.1-events.md
task-T002-ui-panel.md
runs-WF001.md
reviews-WF001.md
output-WF001.mdIDs are stable. Titles may change, but agents should avoid renaming files unless you explicitly ask for cleanup.
Metadata
Agent state is not YAML frontmatter — it is a visible JSON block under a ## Agent Metadata heading, so a human can inspect and repair it:
{
"notedAgent": true,
"schemaVersion": 1,
"type": "task",
"id": "T001.1",
"workflowId": "WF001",
"parentId": "T001",
"dependsOn": ["T001"],
"status": "todo",
"owner": null
}(Noted still preserves ordinary Markdown YAML frontmatter separately, by storing it as a noted-frontmatter HTML comment; see Architecture.)
States
Workflow
draft → awaiting_plan_approval → ready → running → awaiting_review
→ awaiting_output_approval → done
→ blocked / failed / cancelledTask
todo → ready → claimed → running → review → verified → done
→ blocked / failed / staleRun
queued → running → succeeded / failed / timed_out / cancelled / needs_approvalIllegal transitions are rejected by the engine.
Approval modes
Each workflow runs under an approval mode that decides which checkpoints require sign-off:
| Mode | Requires approval for |
|---|---|
autonomous | Nothing (unless an operation is destructive or external) |
plan | The plan, before task execution |
action | Risky commands, installs, deletes, network, broad edits |
review | Work must be reviewed before completion |
release | Final commit, push, PR, export, or publication |
manual | All major transitions |
Gates and enforcement
The engine enforces approval modes by detecting bypasses: a direct transition that would skip a gate's request state is refused. For example, under plan mode a workflow cannot jump draft → ready because that skips the plan gate; the engine returns a gate_required error instead.
Gate states are exit-only, via approval or rejection:
- Workflow:
awaiting_plan_approval,awaiting_review,awaiting_output_approval - Task:
review - Run:
needs_approval
Approving moves to the gate's approve target; rejecting moves a workflow or task to blocked (or a run to cancelled), recording the reason. A blocked workflow is recoverable by restarting through draft.
Tasks additionally respect dependencies: a task cannot become ready, claimed, or running until every task in its dependsOn is verified or done.
Events
State changes and evidence are append-only events. Prefer the append_agent_event tool over free-form edits:
{
"type": "TaskStatusChanged",
"actor": "agent",
"at": "2026-05-25T10:30:00.000Z",
"nodeId": "T001",
"status": "review",
"summary": "Implementation ready for review"
}MCP tools
| Tool | Purpose |
|---|---|
create_agent_workflow | Scaffold the workflow, task, runs, reviews, and output notes in a folder |
append_agent_event | Append a structured JSON event to an agent note |
advance_agent_state | Move a workflow/task note to a new status (enforcing the machine, gates, and dependencies) |
approve_agent_gate | Resolve a pending gate the approval mode does not require, moving to its approve target |
reject_agent_gate | Move the pending gate to blocked/cancelled with a reason |
create_agent_workflow takes the folder, a workflow id, title, and goal, an optional approval_mode (default plan), and an optional list of tasks (each with an id, title, optional parent_id, and optional depends_on).
Who approves
A gate the workflow's approval mode requires (plan, action, review, release; all four in manual) is the user's checkpoint: approve_agent_gate refuses it and says to approve it in Noted, from the Agent panel or the Workflows page. An agent can still send such a gate back with reject_agent_gate, and can approve a gate state that an autonomous workflow entered on its own.
Every event, transition and decision made through MCP is recorded as coming from the connected client (mcp:<client name>). An actor argument is kept beside that name as a label (mcp:claude-code (reviewer)); it never replaces it, so nothing written by an agent can read as written by the user.
Optimistic concurrency
Because an agent and a human may touch the same note, the advance_agent_state, approve_agent_gate, and reject_agent_gate tools accept an optional expected_updated_at. If the note changed since it was read, the call fails with a stale error rather than clobbering the newer state.
The Agent panel
Inside the app, the Agent right-panel drives the same engine as the MCP tools — Approve, Reject, and Advance operate through advance / approveGate / rejectGate and persist the note. When a task's governing workflow cannot be found, both callers fail safe to manual mode.
The workflows board
Workflows in the sidebar (shown once the vault has a wf-… note) lays a workflow out as a board: one column per task state, from To do to Done, with Blocked, Failed and Stale after them when something is in them. A vault with several workflows has a picker at the top.
- What waits for what. A task lists the tasks it depends on, each marked done or not yet, and the tasks it holds back. A dependency on a task that is not in the workflow is flagged, since the engine treats it as unmet; tasks that depend on each other in a loop are named in a warning, because none of them can start.
- Decisions. A task in
review, and a workflow in one of its gate states (awaiting_plan_approval,awaiting_review,awaiting_output_approval), shows Approve and Reject. Rejecting asks for a reason, which is recorded in the event. The decision goes through the sameapproveGate/rejectGateas the Agent panel and the MCP tools: the state moves, an event is appended to the note, and a task's new state is mirrored into its workflow note. - Stale boards are refused. The notes are read again when you decide. If an assistant moved the task (or the workflow) since the board was loaded, nothing is written and the board refreshes.
- Where the board gets its data. The workflow note's
tasks[]mirror, which the tools keep in step with each task note. Workflow notes are found by their name,wf-<id>-<title>.mdin any folder, as the scaffold names them; a renamed one is not listed.
Current status
The workflow and task lifecycles are fully wired end-to-end. Two parts of the schema are defined but not yet exercised by the shipped tools:
- The run lifecycle (the
queued → running → …states) — scaffoldedrunsnotes are treated as evidence logs, and no shipped tool advances a governedrun. - The
actionapproval mode — it is accepted and stored, but does not yet gate any workflow or task transition.
Treat both as reserved for a future revision rather than active checkpoints.
Where it lives
The engine is a pure, well-tested module in shared/agent/ (types, stateMachine, gates, dependencies, engine, metadataBlock), shared verbatim between the MCP server and the renderer so both enforce identical rules.