← Files taskplaneARCHIVED FILE
docs/cli-reference.md
52.8 KB · Oct 2, 2026 · 00:29 UTC
# Taskplane CLI
This reference describes the repository source. The cached 2.31.4 runtime inspected
on 2026-09-26 lacks the `workspace` commands, `flow recover` and worker
`recover-unavailable` operation described below. Confirm that the actual installed
CLI and loaded hooks contain the needed implementation before using these commands;
editing a checkout or matching version strings does not update the installed plugin.
## Scoped native workers and task publication
`flow worker --operation prepare|claim|accept-result|status|capacity|abandon|recover-unavailable` operates
on the existing run. Supply `--workspace` and `--run`; root mutations also require
`--expected-revision`. Prepare/result commands use `--task`; claim/result/abandon
and recover-unavailable use `--grant` for a native attempt. `--worker-json` is a bounded JSON object.
Preparation needs `capacity` with `host_slots`, `includes_root`, and an actual
observed source `reference`. Optional configured/resource limits narrow capacity.
No default two-worker limit is applied.
New scopes created through the execution skills must declare
`execution_contract: "native-default/v1"`. Publish every task with
`execution: "native_required"` or `execution: "root"`; root exceptions require
`execution_reason` and `execution_reference`. Each selected Engineering lens has
one unique `review_lens` task and a distinct native worker unless an explicit
serial scope applies. Typed requirements are enforced even in unmarked existing
runs. Untyped historical scopes retain their original evidence contract.
All current-phase native-required tasks need fresh accepted joined native results
before sealing. Engineering `lens_coverage` additionally binds `lens`, `task_id`,
`reviewer`, `grant`, `status: "native_verified"` and `rationale` to the actual
accepted attempt. Root exceptions use `status: "serial_scope"`, the actual root
reviewer and their frozen `execution_reference`. Missing, duplicate, foreign or
reused reviewer identities refuse. Task progress cannot downgrade frozen execution
requirements. Capacity may record `status: "unavailable"`, zero effective slots,
an observed `reason` and `reference`; this reports a blocker, never success.
Claim/context responses emit an exact `next_action`. Prefix only the installed
runtime launcher; preserve its workspace/run/task arguments and shell quoting.
Continue with emitted `--read-required HANDOFF_SHA` actions until all required
bodies are delivered. Root result acceptance captures `input_contract:
"declared-source/v1"` and declared read-source fingerprints, excluding owned output
paths; legacy root results require reacceptance before dependency reuse.
Result JSON contains `outputs` (task-owned paths) and `checks` (objects with `name`,
`status: "pass"`, `evidence`). A native result needs a joined attempt, delivered
worker context, unchanged inputs and no running child command. Root task results
omit `--grant` and retain root provenance. See the packaged
[native dispatch protocol](../skills/tp-go/references/codex-native-dispatch.md).
`flow attach --tasks FILE --update-context --run RUN --expected-revision N` publishes
validated definitions for that run and unsealed visit. Plain attach remains
observational. Updates require quiescence, freeze definitions, increment generation
and revision, and invalidate old receipts. Identical retries are idempotent.
Accepted Build definitions cannot be changed through attachment.
Invoke `python3 <plugin>/taskplane/tp.py` with one of these commands.
| Command | Purpose |
| --- | --- |
| `workspace inspect --workspace PATH` | Read binding, relocation and execution-policy diagnostics without initializing a workflow |
| `workspace bind --workspace PATH --request FILE` | Validate an explicit selected-project mapping and create its binding |
| `workspace recover --workspace PATH --request FILE` | Archive validated inactive history after relocation and bind future new runs |
| `flow activate --workspace PATH --phase ENTRY --request-reference REF` | Select the session harness without starting or approving a run |
| `flow deactivate --workspace PATH --request-reference REF --note REASON` | Explicitly clear a native selection with no active run; refuses active/protected workflows and preserves all approvals |
| `flow present --workspace PATH --run ID --evidence .taskplane/dashboard.html --presentation OUTCOME --note TEXT` | Record the actual native dashboard handoff for this visit/revision |
| `flow wait --workspace PATH --note TEXT` | Record actual missing user input while retaining write and approval checks |
| `flow start --workspace PATH --scope FILE --request-reference REF [--standalone --phase PHASE] --goal TEXT` | Start or reuse an explicitly scoped native workflow |
| `flow start --workspace PATH --replace-run OLD_ID --expected-revision N --scope FILE --request-reference REF --goal TEXT` | Replace an active native run on explicit user request; retain the previous evidence and begin with fresh approvals |
| `flow progress --workspace PATH --phase PHASE --note TEXT` | Record same-phase observations; phase changes require guarded advance |
| `flow attach --workspace PATH --tasks FILE --reviews FILE --evidence FILE` | Attach shared tasks and evidence |
| `flow report --workspace PATH [--run ID]` | Read profile-bound decisions, separate observations and native token coverage |
| `flow submit --workspace PATH --output FILE --tasks FILE --expected-revision N` | Validate and seal current phase evidence for human review |
| `flow decide --workspace PATH --decision-json JSON --expected-revision N` | Record a complete observed human decision against the exact pending checkpoint |
| `flow advance --workspace PATH --phase PHASE --expected-revision N` | Advance only to the next authorized visit after its predecessor is accepted |
| `flow finish --workspace PATH --expected-revision N --note TEXT` | Finish only after all required visits have current human or authorized policy acceptance |
| `flow hook` | Enforce verified workflow boundaries where active; separately observe native metadata and usage |
| `context`, `screen`, `tool-observe`, `subagent-start`, `subagent-stop`, `session-verify`, `human-input` | Installed native hook entry points; read event JSON on stdin and bind the event type to the command |
| `graph --workspace PATH scan --decompose` | Scan source dependencies and components |
| `graph --workspace PATH impact --files a.py,b.py --json` | Inspect affected consumers |
| `graph --workspace PATH edge SRC DST --kind runtime` | Record an observed relationship |
| `graph --workspace PATH html --out graph.html` | Render the interactive graph |
| `dashboard --workspace PATH [--run ID] [--out dashboard.html]` | Render the shared dashboard |
| `review start --workspace PATH --scope repository` | Capture tracked source for review |
| `review start --workspace PATH --base REF` | Capture a comparison for review |
| `lens --workspace PATH --files a.py,b.py --stage engineering` | Suggest applicable lenses |
| `version --verify` | Check host manifest versions |
Product, Design, and Engineering can each start execution, including standalone
requests. Every execution uses the shared dependency graph with source
decomposition, an attached task decomposition, and the shared dashboard. Engineering
findings can become Product inputs without starting another active run. Help and
status only inspect existing state. A phase's scope determines what work is authorized.
By default, full delivery requires human acceptance after Product, Design, Plan, Build,
Evaluate, Engineering and Retro. Standalone Product, Design or Engineering accepts
only its own scope. Explicit human-approved delivery or repair amendments add fresh
visits while retaining history. Finding IDs survive Engineering-to-Product handoff.
`progress`, `attach`, task status and dashboard HTML are not approval mechanisms.
The shipped default `--profile native_workflow` enforces the Taskplane API using
local state and observed human responses. `workflow_available` can be true while
`authority_verified` and all four host-protection capabilities remain false. Native
host permissions govern execution; this is not a sandbox or a protected issuer.
An explicit `--profile protected_host` request still requires the admitted native
owner. It uses `--native-event REF` for independent scope/decision resolution and
refuses when unavailable. No automatic downgrade or workspace flag enables its
protected capabilities. Local-account tampering and fabricated otherwise valid
provenance are outside native_workflow's guarantees.
## Workspace binding and execution policy
Cowork, configured workspace/policy signals and recognized session/scratch roots
require an explicit binding before ordinary runtime state is created. Existing
local Claude Code/Codex workflows without these signals retain their legacy behavior.
Directory heuristics require validation; they do not classify a machine as local
or cloud. Exact installed `workspace inspect`, `bind` and `recover` commands remain
available for setup/recovery. This exception does not admit arbitrary shell commands
or unsupported native tools.
Binding and relocation require descriptor-relative no-follow directory operations.
Standard Windows Python does not provide them; strict binding returns a structured
`workspace_binding` refusal before mutation. Unbound local workflows retain their
existing Windows behavior. Do not replace this refusal with path-based fallback
or infer successful Windows binding from path-parser fixtures.
Invoke the installed launcher, for example:
```sh
python3 /actual/plugin/taskplane/tp.py workspace inspect --workspace /selected/execution/project
python3 /actual/plugin/taskplane/tp.py workspace bind --workspace /selected/execution/project --request /selected/binding-request.json
```
The request is a bounded ordinary JSON file, prepared before workflow initialization.
The following is a template, not measured evidence. Replace every path, digest and
reference with actual observations, and set only the policy the user permits:
```json
{
"schema": "taskplane.workspace-request/v1",
"surface": "cowork",
"host_root": "/selected/native/project",
"execution_root": "/selected/execution/project",
"policy": "darwin-local",
"execution": {"location": "local", "reference": "actual-command-environment-observation"},
"worker": {"location": "local", "reference": "actual-worker-environment-observation"},
"probe": {
"path": "workspace-probe.txt",
"sha256": "REPLACE_WITH_64_LOWERCASE_HEX_DIGEST",
"host_reference": "separate-actual-host-file-observation"
}
}
```
`surface` is `cowork`, `claude-code`, `codex` or `other`. Both roots are normalized
absolute paths; they may be equal. `execution_root` must match `--workspace` when
binding. Each execution/worker observation has `location: local|remote|unknown`
and its own nonempty `reference`. `probe.path` is workspace-relative, outside
`.taskplane/`, without traversal or symlinks. The runtime reads that ordinary file
through the execution root and compares its SHA-256 to the separately recorded
host-side observation. Reading the execution file alone cannot establish the host
reference. Keep the probe bytes stable during the binding's lifetime.
| Environment setting | Contract |
| --- | --- |
| `TASKPLANE_WORKSPACE` | Selected execution root for CLI, hooks and children. An explicit flow workspace must agree with it or its declared native host alias. Hook cwd need not equal it. |
| `TASKPLANE_SURFACE=cowork` | Require a binding even if the path looks like an ordinary local checkout. |
| `TASKPLANE_WORKSPACE_POLICY` | Optional `any`, `local` or `darwin-local`; a stricter current value applies, and a weaker value cannot relax the stored policy. |
| `TASKPLANE_EXECUTION_LOCATION`, `TASKPLANE_EXECUTION_REFERENCE` | Current command-environment observation; `local`/`remote` needs a reference. Strict policies require the local pair. |
| `TASKPLANE_WORKER_LOCATION`, `TASKPLANE_WORKER_REFERENCE` | Independent current worker-environment observation; required as local for native preparation/claim under a strict policy. Root execution evidence cannot substitute for it. |
`any` permits the declared environment; `local` requires both declared and current
execution to be local, and the same independent worker checks when dispatching or
claiming. `darwin-local` additionally requires the executing platform to be Darwin.
Unknown required observations or conflicts refuse. A Linux VM mounted to a Mac
folder fails `darwin-local`; its mount does not prove either execution or worker
location. Do not silently change policy to make a refused environment pass.
Successful binding writes `.taskplane/workspace-binding.json`, with a generated
project ID and contract digest, only in the selected execution root. It does not
initialize or approve a workflow. An identical bind is reusable; a different
binding cannot overwrite it. Guarded operations revalidate mapping, probe and
policy against the run's frozen contract. Covered native absolute paths normalize
through the declared host alias before existing exact-scope and symlink checks;
neighboring paths, traversal and undeclared aliases remain refused.
The host must propagate the selected root and current observation pairs to hooks
and children. Claude SessionStart may export an already validated selection through
its environment file; this is convenience, not evidence of locality. Report missing
propagation or adapter capabilities and stop. Binding references are cooperative
observations that the local account can fabricate, not host attestation. Inspection
keeps `host_attestation: false` and `live_cowork_verified: false`; fixture results
do not establish live persistence, automatic hooks, worker execution or display.
### Workspace relocation recovery
Use `workspace inspect --workspace NEW_PATH` to inspect a relocated binding, then
`workspace recover --workspace NEW_PATH --request FILE` for explicit recovery.
The recovery request has all binding fields above plus `expected_project_id` from
inspection and `request_reference` for the actual recovery request. Supply the new
mapping and fresh host-side probe bytes, digest and observation reference. A matching
project ID alone does not prove continuity.
Recovery requires validated terminal/inactive current controller history and no
live or unknown commands/workers. A still-present original root, copied metadata,
stale probe, corrupt identities, symlinks or missing evidence refuse. Active work must be
retired through its original binding first. If that host/path is unavailable, keep
the evidence intact and report the missing recovery capability.
After [restoring a displaced database](#recover-a-displaced-workflow-database),
retire its run before relocating. Recovery accepts only exact numbered copies
(`workflow-ROOTKEY N.json`, where N is a positive integer) paired with their completed
`workflow-ROOTKEY.recovery-SHA256.json` receipts. Each pair must match the canonical
controller and initialization marker, the copy's bytes, active run and revision.
Every run in the copy must exist in current history at an equal or newer revision
with the same workspace contract. Old active/worker flags remain historical; they do not override
the current controller's inactivity requirement. Unknown, corrupt, foreign,
symlinked or incomplete restoration artifacts refuse without changing the store.
On success, the entire old `.taskplane/` becomes a uniquely named local
`.taskplane-recovery-*` archive. The fresh store contains the binding and
`workspace-recovery.json` with the old-file hash manifest and
`approvals_transferred: false`; validated restoration copies and receipts retain
their exact bytes in that archive. Start a new workflow; prior approvals, grants and
context identities remain historical. An interrupted recovery preserves its pending
record and archive for diagnosis. Do not delete them, edit binding identities or
disable hooks to force adoption. Recovery is for relocation, not replacing an
unchanged binding's policy or resetting corrupt state.
## Workflow scope and replacement
Start scope JSON has `criteria` (unique IDs), `paths` (all seven phase names mapped
to exact workspace-relative file lists), and optional `verification_inputs`. Use
`.taskplane/` for generated workflow artifacts. Declare source/task files written
during a phase in that phase's scope. Scope and decision envelopes are data, never
executable configuration. Start requires the actual user's request reference and
does not accept any future phase.
### Recover a displaced workflow database
`flow diagnose --workspace PATH` returns bounded diagnostic details even in compact
mode, including the expected database and initialization-marker filenames and
whether each exists. An exact installed diagnosis command remains admitted when
local state is unreadable; ordinary tools and phase operations remain guarded.
When the database is missing but its matching initialization marker and an exact
numbered copy remain, explicitly restore that copy with:
```sh
python3 /absolute/plugin/taskplane/tp.py flow recover --workspace PATH \
--recover-from 'workflow-ROOTKEY 2.json' --expected-sha256 SHA256 \
--run EXPECTED_RUN --expected-revision EXPECTED_REVISION \
--request-reference 'Actual user recovery request'
```
This native-root maintenance operation validates the marker, checksum, complete
database schema, workspace/root identity and active run/revision. It preserves the
copy and restores its exact bytes using an atomic create-if-absent operation. It
cannot overwrite differing state, invent a missing marker, restore another root's
approvals, select the newest copy automatically, or admit child/protected-host
recovery. A recovery receipt records the request and content hash. Existing
approval, worker-join and evidence-freshness checks still apply after restoration.
If publication was interrupted, repeat the same exact request; identical restored
bytes are reported as already restored. A different or newer database is refused.
Numbered copies indicate displaced files but do not identify which program moved
them. Diagnose the filesystem writer separately; this recovery does not prevent
an external program from moving files again.
If a restored run retains a worker which the native Codex service has lost, request
an actual native interruption. A `not_found` response can support explicit
`flow worker --operation recover-unavailable --run RUN --grant GRANT
--expected-revision N --worker-json JSON`. Supply `request_reference` for the actual
user recovery instruction and `call_id` for that interruption. This root-only
operation verifies the matching call/result in the native root transcript, exact
worker identity, current binding, a 15-minute observation window and absence of
known live commands. Missing inventory alone is insufficient. It revokes the
unavailable grant as failed, retaining its audit evidence; it never accepts a
result or claims process exit. Retry or replacement still needs fresh native
verification. This recovery currently supports Codex transcript observations only.
Malformed native call/result JSON, metadata or timestamp fields return
`invalid_evidence` without changing the grant. Preserve the evidence and diagnose
the malformed observation before retrying.
### Start again without losing the previous run
When the user explicitly requests a new run, read the current run ID and revision
with `flow report`. Prepare the new exact scope under `.taskplane/bootstrap/` using
fresh filenames, then call `flow start` with `--replace-run OLD_ID`,
`--expected-revision N`, the new `--scope`, and the actual `--request-reference`.
Use the same workspace. Carry useful prior findings and documents into the new
scope as evidence; do not copy approvals or policy authorization.
Replacement works with sealed or stale evidence and unrelated source changes.
The previous run becomes historical with status `superseded`, keeping its packets,
decisions and a link to the replacement. Its grants are revoked. The new run starts
at Product (or the explicitly requested standalone entry) with a fresh source
baseline, empty decisions and manual approval policy. This does not approve or
finish the old run. The native dashboard selects the new run. A matching retry is
idempotent; a wrong run/revision, invalid scope or known running process refuses
without replacing the active run. Stop known processes before retrying.
Sealed/stale checkpoints still permit exact installed recovery/status/help
commands, `pwd`, plain `cat`, a bounded set of non-executing `rg` options, and fresh
structured bootstrap-file writes. Sealed evidence, shell operators, output
redirection, executable search helpers and ordinary implementation writes remain
guarded. A changed request without `--replace-run` no longer silently returns the
old run. Existing scope remains in force until replacement commits.
A correctly bound human `Changes requested`, `Rejected` or `Cancelled` response
can be recorded even when source or submitted evidence has changed. It accepts
no evidence and does not reset the source baseline; approvals and transitions
still refuse drift. New runs require their own approvals. This recovery is for
`native_workflow`; it does not reset corrupt stores, disable hooks or admit a
`protected_host` owner.
After `Changes requested` or `Rejected`, the current visit permits repeated
in-scope corrections and ordinary `flow submit` resubmission. The prior packet
remains in history. Accepted predecessors and sealed current outputs still detect
drift; cancellation does not open a correction grant.
Bare, plugin-tagged and direct `Use/Run Taskplane` requests use the leading action
to select the route. For example, `build export with design and engineering review`
selects full delivery in each form. Help and status requests remain non-executing.
In manual mode, after submission `flow report` exposes `workflow.pending_checkpoint`. Present the
output to the user, wait for their actual response and supply this envelope through
`--decision-json` (properly shell-quoted, or passed as one subprocess argument):
```json
{
"schema": "taskplane.observed-decision/v1",
"event_id": "actual-response-id",
"choice": "approved",
"binding": "replace with the complete pending_checkpoint object",
"excerpt": "Approved",
"recorder": "root_orchestrator",
"source": {
"kind": "conversation",
"reference": "actual-response-reference",
"conversation": "the workflow root conversation ID",
"actor": "user",
"automatic": false,
"observed_at": "2026-09-16T22:02:00+00:00"
},
"presentation": {
"checkpoint": "the pending checkpoint ID",
"reference": "actual presentation message reference",
"at": "2026-09-16T22:01:00+00:00"
}
}
```
Example identifiers and times above are placeholders; never copy them as actual
provenance. Choices are `approved`, `changes_requested`, `rejected` or `cancelled`.
The excerpt must express a clear choice in the user's own words. Conversational
responses such as “looks good, proceed”, “go ahead”, “build approved” and “fix
issues” are supported; no exact phrase is required. A named phase must match the
bound visit. Questions, conditions, negations, quoted examples and contradictory
responses require clarification in ordinary language. A brief approval needs presentation identity and earlier
presentation time. If ordering is unavailable, use `checkpoint_explicit: true` and
an actual response such as `Approve: <checkpoint ID>`; the response must itself
name the checkpoint. Automatic, assistant/tool, timeout/cleanup, ambiguous, stale
and mismatched records refuse. The account supplying this evidence is not
independently authenticated by the plugin.
A named native prompt may carry the same envelope as `taskplane_decision`, with
source kind `native_prompt` and recorder `native_prompt_hook`. Ordinary prompt text
alone does not establish the reviewed checkpoint; the root can record the actual
conversation response through the explicit command. Recording a decision never
advances the phase: use `advance` separately after approval.
Required phase outputs and route rules are in
[the shared flow](../skills/tp-go/references/shared-flow.md). `--output` names JSON
with schema `taskplane.phase-output/v1`, the exact `run`, `phase`, `visit`, ordered
`criteria`, and that phase's required fields. `artifacts` references name `path`,
`kind`, `schema`, `phase`, `visit`, `tasks` and `criteria`. Paths are literal,
workspace-relative, without symlinks or protected metadata. Task JSON has a `tasks`
array with unique `id`, `phase`, `dependencies`, `paths`, `owner`, `criteria` and
`verification`. The Plan's `write_scope` exactly matches its Build task paths and
cannot widen the human-authorized outer scope.
Design's `acceptance_test_map` and Engineering's `requirements_comparison` map
every criterion ID to substantive content. Plan embeds the actual shared `task_dag`,
matching `ownership`, prerequisite-respecting `integration_order` and criterion-to-task
`acceptance_coverage`. Build lists exact paths in `change_inventory`, maps criteria in
`task_acceptance_map` and provides `build_checks` with `name`, `status` and an existing
`evidence` file. Engineering lists findings with `id`, `severity`, `source` and an
existing `evidence` file; `lens_coverage` lists each `lens`, `reviewer` and `rationale`.
Evaluate's `criterion_results` maps each criterion to `status`, existing `evidence`
file(s) and `explanation`. Check statuses are `pass`, `fail` or `unknown`.
A decision binds workspace, root, run, visit, checkpoint, revision, packet digest
and scope digest. Identical repeats are idempotent; conflicting/stale reuse refuses.
Evidence drift invalidates affected acceptance and descendants. A pending checkpoint
blocks ordinary covered writes while read/status and exact installed workflow-control
commands remain usable; those commands still perform the same Controller checks.
Native workflow audits regular source files and symlink identity before transitions,
including creations and deletions. The bounded audit excludes `.git`, `.taskplane`,
`.venv`, `venv`, `node_modules`, `__pycache__`, `.pytest_cache`, `.mypy_cache` and
`.ruff_cache` directories. It refuses beyond 20,000 entries or 512 MiB. These are
explicit coverage limits, not a host-wide write barrier. Structured tools reaching
hooks enforce declared paths; opaque commands retain native permissions and have
only their visible source effects audited afterward.
PostToolUse `exec_command`/`Bash`/`write_stdin` responses with structured `session_id`
and `exit_code` fields update observed handles. Known running work blocks sealing.
Handles retain their original visit and grant revision. Later approval or policy
revisions in that same visit permit empty polls, interruption and terminal
observations, but never new code on a stale grant. Unknown, terminal, future-revision
or old-visit handles reject input, and terminal handles cannot reopen. Unsupported
response shapes and a complete process census remain unknown. Protected-host command tracking separately
requires actual identity, cancellation/revocation and complete quiescence proof.
Cancellation requests never manufacture termination.
Local profile state and its initialization marker live under `.taskplane`; locks
and atomic writes handle normal concurrent updates. Missing/corrupt initialized
state refuses automatic reset. Local state, source audit and prompt provenance
remain editable by the local account. Protected-host state remains outside the
worker boundary and is never silently adopted by the local profile.
Named hook commands override conflicting event names in supplied JSON. PreToolUse
errors deny; Stop errors/waiting return a message without forced continuation.
Direct `flow hook` remains a compatibility entry for host-supplied event types.
Workflow refusals return exit 2 with `blocked` or `capability_blocked` and a reason.
Mandatory PreToolUse refusal uses the host's deny response; malformed hook input
blocks. Stop permits waiting for a human instead of forcing an approval loop.
Optional token/render warnings do not erase a durable valid governance decision.
Observations, graph data and native workflow state live in `.taskplane/`.
Reports do not start a workflow. Legacy progress/finish is shown as
`legacy_unverified`, never accepted or automatically migrated. Missing counters
are unknown, not zero. Tokens remain advisory and are not billing totals.
## Automatic approval policy
Manual is the default. `native_workflow` additionally supports **explicit user-authorized**
automatic approval for one run. Existing runs with no policy stay manual. This does
not enable an unattended scheduler, alter permissions, or provide protected-host authority.
| Command | Contract |
| --- | --- |
| `flow policy --workspace PATH --run ID --policy-json JSON --expected-revision N` | Record, replace or revoke observed user authorization. This never accepts a phase. |
| `flow auto-decide --workspace PATH --run ID --assessment-json JSON --expected-revision N` | Assess a submitted checkpoint inline after sealing; commit an eligible policy decision or pause. |
| `flow diagnose --workspace PATH` | Inspect bounded source metadata and workflow readiness without initializing or modifying a run. |
Read the current report first. A policy envelope has this shape; **replace every
example identifier, timestamp and instruction with actual observed data**:
```json
{
"schema": "taskplane.approval-policy/v1",
"event_id": "actual-user-event",
"mode": "autonomous",
"binding": {
"workspace": "/actual/checkout",
"root": "actual-conversation",
"run": "actual-run",
"revision": 0,
"scope_digest": "fingerprint of the current exact scope"
},
"recorder": "root_orchestrator",
"excerpt": "For this task, auto-approve phases after required checks pass. Stop before Retro.",
"source": {
"kind": "conversation",
"reference": "actual-user-message-reference",
"conversation": "actual-conversation",
"actor": "user",
"automatic": false,
"observed_at": "2026-09-17T18:00:00+00:00"
},
"allowed_phases": ["product", "design", "plan", "build", "evaluate", "engineering"],
"stop_phases": ["retro"],
"conditions": []
}
```
The orchestrator normalizes only what the user authorized. `policy_binding(state)`
in `workflow_approval.py` derives the binding from the current report/state; do not
invent digests. For an instruction received before `start`, also supply
`request_reference` equal to that run's original request reference. A later message
must have an observed time within the run. Consent must explicitly request automatic
approval or an automatically approved workflow. Requests such as “run an auto-approved
full workflow” are supported, including task, run and release wording. Generic requests
such as “build this” are not accepted as opt-in. If intent is unclear, ask whether
the user wants automatic phase approvals; never require a prescribed exact response.
The stored policy adds an immutable ID/version/digest, the authorized scope and a
mandatory `user_instructions` condition containing the original excerpt. Additional
conditions have unique `id`, `kind` and `instruction` fields. Supported kinds are
`observed` (evidence-backed assessment) and `required_check` (also requires `check`,
an exact passing Build check name). A required check absent in the current phase
pauses; authorize that condition only for the phases where it can be satisfied.
No policy field is evaluated as shell code. Conditions the runtime cannot interpret
mechanically stay observed, with that limitation visible.
Submit the phase normally. Read the **new** `pending_checkpoint` and policy digest,
present its native dashboard, then pass the assessment as `--assessment-json` to
`flow auto-decide`. This control operation needs no post-seal file write. Quote JSON
as literal data; do not interpolate user instructions into shell code:
```json
{
"schema": "taskplane.policy-assessment/v1",
"binding": "replace with the complete current pending_checkpoint object",
"policy_digest": "the current approval_policy.digest",
"conditions": [
{
"id": "user_instructions",
"status": "pass",
"explanation": "Describe the actual checks against all original instructions.",
"evidence": [".taskplane/phase-output.md"]
}
]
}
```
The inline payload must be a JSON object of at most **64 KiB**. Existing
`--assessment FILE` input remains supported under the same bound; it reads an
already prepared file and does not grant permission to create or edit it after
sealing. The two inputs are mutually exclusive and apply only to `auto-decide`.
Include exactly every policy condition. Evidence paths must be in the submitted
packet's sealed manifest; attachment alone is insufficient. Each condition needs
an explanation and at least one existing sealed evidence file. `fail` or `unknown`
pauses. Built-in rules additionally require complete/current phase evidence, the
exact revision and scope, permitted phase, no known live process, passing Build
checks without unresolved gaps, passing Evaluate criteria without failures/unknowns,
and no explicit high/critical/P0/P1 Engineering blocker. Automatic acceptance cannot
approve route amendments or widen scope. Plan may narrow the outer Build grant.
Automatic decisions, advancement and finish require the current native handoff,
even if there is no intervening Stop. A matching presentation survives only the
approval-only revision increment; policy/scope changes, new packets, repairs and
stale source require a fresh handoff. After `auto-decide` succeeds, use `advance`
or `finish` separately. The stored decision
has `kind: policy`, `human: false`, `automatic: true`, its policy ID/version/digest,
checkpoint binding and assessment. Human decision envelopes retain their existing
semantics; do not manufacture an “approved” excerpt for an automatic decision.
To revoke, submit another `flow policy` envelope with the actual instruction such
as “Return to manual approval,” `mode: manual`, `allowed_phases: []` and the current
binding. Rejection, changes requested, cancellation, route change or evidence drift
suspends automatic continuation. Fresh authorization is needed to resume. Prior
automatic decisions remain auditable under their original policy version.
Identical event/assessment retries are idempotent; changed retries refuse. Revocation
and automatic acceptance share the Controller lock and expected revision, so a stale
authorization cannot win a later race. `protected_host` rejects observed policies.
A native prompt hook may carry a `taskplane_policy` envelope, using the same rules;
plain prompt text and agent/tool events cannot enable automatic approval.
## Exact-run snapshots and usage
`dashboard --workspace PATH --run ID [--out PATH.html]` and phase operations use the
same native renderer/publication helper. Explicit `--run` selects that run; otherwise
the current task binding is used. Missing bindings do not fall back to another task's
latest run in native workflows. Older journal-only views retain their latest advisory
entry, explicitly labelled `legacy_unverified`, and never confer acceptance. Per-generation `snapshot-*.html`/`.json` files retain the captured view;
`dashboard.selection.json` identifies the selected entry. A competing background
publisher keeps its own snapshot rather than replacing a different selected run.
The snapshot includes execution checkout, root/run, phase/visit, workflow/policy
revision, source revision, graph fingerprint, generation time and measurement context.
Publication rechecks workflow/source consistency. Historical views use sealed graph
and task context. The source graph view reuses Taskplane's interactive template and
shows focused/full views and scan provenance. `graph scan --decompose --strict`
records the scan receipt; legacy scans without a workspace-bound receipt stay unverified.
Static HTML labels freshness as unmonitored. Regenerate, then refresh/reopen the
intended file; its reload button does not regenerate backend data. Generated HTML
or a queued host open is not visual verification. Link the exact native artifact at
every checkpoint, including Product, and report blocked presentation honestly.
Usage observations record cumulative per-session boundaries at start and successful
transitions, with progress samples. Comparable monotonic intervals are attributed to
phase visits as work, review or post-completion follow-up. Missing/reset/late counters
remain partial/unallocated, including a child with no comparable start observation.
Existing native readers reconcile run totals and identify actual children; host
approval-review remains separate. Read failures retain recorded counters with older
measurement times. No early phase boundary means no retrospective phase estimate.
Counter/discovery gaps are visible; optional telemetry cannot erase a committed decision.
The derived `phase_usage` ledger includes per-session intervals, counter amounts,
phase/visit where known, activity category, reason and coverage. Its `accounting`
object reconciles measured run tokens into `phase`, `non_phase` and `unresolved`.
The compact command summary exposes these totals and a verified reference to the
complete ledger; the native dashboard shows the same breakdown and interval detail.
Cached input is part of input, and reasoning is part of output: neither is added
again. These counters are not a monetary estimate.
A missing revision between monotonic measured counters in the same visit can
recover that phase's tokens in an `unsegmented` bucket; it cannot recover the
work/review split. Missing transitions across visits, saved/partial boundaries,
late sessions and resets retain explicit unresolved reasons and known amounts.
Post-completion `follow_up` is outside phase totals. `pre_run` is the root native
lifetime baseline before this run, excluded from run totals; its activity is not
inferred. Missing amounts remain unknown. The next run's observed start baseline
closes the previous root interval, preserving historical totals if the transcript
counter later falls outside the reader's bounded window. Legacy observations are
not rewritten, and incomplete discovery remains partial even when known totals
reconcile.
## Execution entry and readiness
All execution skills activate the harness before substantive work, including
standalone reviews and resumed stages. Supported direct execution prompts,
namespaced skills and native reads of installed execution skill files can select
it through hooks; indirect entry uses `activate`. ENTRY accepts an execution skill
name or phase. It creates no run or approval. Help/status, quoted examples and
unrelated sessions do not activate. A selected session with no run denies covered
implementation and completion while allowing bounded bootstrap preparation.
See [onboarding](onboarding.md#verify-harness-activation) for supported setup tools.
Standalone review uses `start --standalone --phase engineering`; Product/Design
also have standalone starts. Existing phases retain their valid scope and approval
bindings. Activation cannot grant Build or opt into autonomous decisions.
After a run finishes, rereading an installed execution skill file preserves its
completed binding and allows follow-up work. An explicit execution prompt, native
Skill invocation or `activate` still selects a new workflow; a fresh session's
first execution skill read still requires initialization.
If a native session was selected without starting a run, use
`flow deactivate --workspace PATH --request-reference REF --note REASON` with the
actual request reference and recovery reason. This clears only that uninitialized
selection and records the observation. It refuses active runs, including sealed
checkpoints, and protected-host workflows. It never changes approval policy,
accepts a phase or rewrites workflow history. Active work must finish or use the
explicit retirement control instead.
Harness updates check the complete serialized JSON against the 16 KiB read limit
before replacing the record. Unicode escaping and existing fields count toward
that limit; an oversized update leaves the previous valid record untouched.
`report` includes observed `harness` readiness (inactive, initialization_required,
active), hook observation, current binding and presentation receipt. `present`
validates the current native dashboard identity and stores its immutable artifact
hash outside normative phase outputs. OUTCOME is `linked`, `verified` or `blocked`:
queued opens are linked/unverified; verified requires actual rendered evidence;
blocked records the restriction and artifact fallback. These are cooperative
observations, not proof the host displayed the artifact or that the user saw it.
Stop requests one corrective continuation for missing setup, unsubmitted phase
output or missing current handoff. A repeated stop emits a message to avoid loops.
`wait` records a real missing-input reason and never approves or completes work.
New user input/further tools clear it; a different visit/revision cannot reuse it.
Unloaded/disabled hooks remain outside these cooperative guarantees. No live hook
trust or native permission is changed.
## Bounded diagnosis and recovery controls
`flow diagnose --workspace PATH` inspects at most 20,000 directory entries without
hashing source content or initializing a workflow. It reports the unchanged
20,000-file/512 MiB source-audit limits, inspected counts and bytes, the ten largest
inspected regular files, bounded issues and completeness. An incomplete walk does
not claim a complete size estimate. A damaged workflow is reported separately from
metadata diagnosis; diagnosis does not repair or reset its store.
The exact Codex native dashboard opener accepts the selected local dashboard or
current immutable snapshot. It remains a view operation before and after sealing;
other URLs, paths, threads and terminal/review targets receive no exemption. A
queued open remains linked/unverified. The stored presentation binds checkpoint,
visit, scope and evidence plus HTML/model digests. Legacy receipts need a fresh
presentation. Negative human decisions and explicit replacement remain available
when presentation cannot succeed.
Native `create_worktree` recovery accepts HEAD and a valid optional name. A bound
PreToolUse/PostToolUse pair must identify the actual returned workspace, matching
Git common directory, HEAD and project subpath before bounded setup is allowed
there. Unknown/failed/foreign results grant no destination access. Only fresh
bootstrap scope files and exact setup/status/diagnostic commands are admitted;
implementation needs that checkout's own initialized workflow and accepted scope.
The original checkout and its uncommitted work stay intact.
The exact native Taskplane uninstall operation has no phase prerequisite, including
at stale checkpoints. The orchestrator still needs the user's explicit request,
and the host controls permission. Other plugins, arbitrary cache writes and shell
administration are not exceptions. A native admin event is not proof of user
consent or a workflow approval. Runtime updates must be checked against the actual
loaded plugin root; use diagnosis and bound replacement instead of erasing history.
## Bounded context transport
Shipped `flow` commands return <=16 KiB `taskplane.command-summary/v1` responses.
Use `--full` explicitly when a machine consumer needs complete legacy output.
Internal report APIs and dashboards retain full evidence. Context preparation and
consumption use:
```text
flow context --workspace PATH --run RUN [--task ID]
flow context --workspace PATH --run RUN --consume HANDOFF_SHA256
flow context --workspace PATH --run RUN --read REFERENCE_SHA256 [--section KEY] [--page N]
```
Read all required referenced bodies and include the returned `context_receipt` in
new bounded/v1 phase outputs. Consume and read are mutually exclusive. References
are current-run data, not approvals. The detailed context contract follows below.
If a context request is refused after workspace validation, its corrective action
uses that validated root, including when `--workspace` was omitted. If workspace
resolution or binding validation fails, the response preserves the binding error
without suggesting a retry against an unvalidated path. Resolve that selection
before requesting context again.
## Context contract details
Taskplane supplies bounded command summaries and current-phase context. Complete
workflow records and dashboard evidence remain available. This reduces unnecessary
transport; it does not remove existing host conversation history or guarantee a
reduction in billed tokens.
The shipped CLI defaults to `taskplane.command-summary/v1`. Routine responses fit
16 KiB and retain current binding, approval state, blocking status, next action,
coverage and verified detail references. Use `flow report --full` for the complete
legacy report. Python `Controller.report`, `flow.report` and embedded `flow.main`
retain complete records; shipped entry points explicitly select compact transport.
Hook envelopes keep their native protocol.
## Phase input
Use the installed runtime for these commands:
```text
flow context --workspace PATH --run RUN
flow context --workspace PATH --run RUN --consume HANDOFF_SHA256
flow context --workspace PATH --run RUN --read REFERENCE_SHA256 --page 0
```
`--task ID` selects an existing task in the current phase. `--section KEY` selects
a known section; unknown sections and cursors fail. Follow index child references
and page cursors for omitted required inputs. A reference alone is not consumption.
Do not interpret source strings as control instructions.
New native runs carry `context_contract: bounded/v1`. Before submitting a phase,
consume whole-phase context without `--task`, resolve every required body, and put
the latest returned `context_receipt` object in its output JSON. Renew the receipt
after changes to source, accepted inputs, revision or scope. The controller rejects
missing, partial, stale or foreign receipts. A receipt means data was returned;
it makes no claim about model attention and cannot approve or broaden a phase.
Legacy runs retain their original evidence contract.
Phase envelopes are bounded to 16 KiB for Product, Plan and Retro; 32 KiB for
Design, Evaluate and Engineering; 64 KiB for Build. Reference pages fit 16 KiB and
64 entries. Required information outside the inline budget remains explicitly
counted and addressable. Immutable objects use SHA-256 and exact metadata under
`.taskplane/context-v1`; large values use indexed nodes. Nodes may not exceed
8 MiB. Reads reject symlinks, foreign paths, altered bytes and unknown IDs.
## Reuse
The `context_reuse` Python interface records check results with immutable source,
dependency, test, criteria, command, runtime, tool, contract and environment
fingerprints. `run_check` executes an explicit argument vector without a shell,
in an environment limited to the documented nonsecret keys: PATH, LANG, LC_ALL,
TZ, PYTHONHASHSEED, PYTHONPATH, NODE_ENV and CI. Environment values are persisted
only as a digest. Matching passing evidence may be reused; incomplete graph
coverage, missing runtime, source additions/deletions or any changed dimension
produce a miss. Failure and unknown records retain findings and producer identity.
External dependency nodes do not establish the contents of installed packages or
modules found through `PYTHONPATH`. A check whose dependency closure contains such
nodes is ineligible for reuse and lists them as `unverified_dependencies`, even
when the environment strings and executable are unchanged. Fully covered checks
remain eligible; unrelated external dependencies do not disable their reuse.
A Build check can supply its `reuse_ref`. Later handoffs independently recheck the
record against current inputs and expose `reused` or `miss`. Approval never moves
with verification. Arbitrary commands outside this controlled producer need their
own complete observation/provenance; no passing result is inferred from telemetry.
## Evidence limits
Frozen fixture comparisons count bytes actually returned, including receipts,
reference envelopes, required reads and repeated fresh consumers. The baseline
is the same complete relevant/shared fixture bundle per consumer. These tests
verify transport composition and manual gates. They do not measure a live model's
attention, finding discovery, billed tokens or monetary savings. Small inputs can
cost more after reference and provenance overhead; failing ratios remain failures.
Derived-context failure after a committed transition reports unavailable context
while preserving the actual transition result. Repair storage and request context
again; do not replay a committed decision. Context data carries no workflow
approval authority. The existing controller store limit is unchanged.
## Retention and retirement
Native workflow stores retain their 8 MiB limit. Above a 4 MiB watermark, inactive finished, superseded or explicitly retired runs move to immutable SHA-256-verified context archives before the reduced index is atomically committed. Active work is never deleted or implicitly accepted. `flow report --run ID` resolves historical records and exposes `storage` (bytes, limit, remaining capacity and archive count); `flow diagnose` includes capacity without initializing a run. Protected-host storage remains owner-controlled.
`flow retire --workspace PATH --run ID --expected-revision N --request-reference ACTUAL_USER_MESSAGE --note REASON` revokes an obsolete native run without accepting its pending checkpoint. It requires the unchanged active binding and no observed live command. Existing decisions and evidence remain historical; a new run needs its own scope and authorization. Use replacement when a new scope should immediately supersede old work. Never manufacture an approval to silence Stop.
New native runs use `bounded/v2`: all normative predecessor outputs and report/design/plan artifacts remain required. Verification, raw-log and explicitly supporting bodies remain accessible by bound verified references. Declare `required_for: ["engineering"]` (or other phases) on an artifact to require its full body downstream. Unknown artifact kinds remain required. Existing `bounded/v1` runs retain full inherited-body requirements. Neither contract removes the host conversation or proves attention. Compact summaries expose the current policy digest, conditions, allowed phases and stops for automatic assessments.
Safe diagnostics include plain `ls` with basic listing flags, `date`/`date -u`, and `rg` context/no-ignore options. Shell operators, rg preprocessing/helpers and arbitrary programs remain outside this diagnostic exception. The cooperative adapter supports scoped native dispatch through the prepare/claim/context/join/result protocol above. Observe loaded capability and record real unavailability; required native tasks cannot be replaced by root labels.
## Scoped native delivery controls
For every new native task, declare exact `read_inputs` from the run verification
inputs or accepted Build paths, a concise `purpose`, and `context_budget_bytes`
(default 128 KiB of unique required bodies). Include source dependencies and tests
needed for the conclusion; narrow inputs must not hide a relevant dependency.
Missing read inputs retain conservative legacy coverage. Inspect preparation's
`context_preflight` before launch. Declare source/log/test detail artifacts as
`source`, `raw-log`, `verification` or `supporting`; keep concise requirements and
reports normative. Use `required_for` when supporting bodies are mandatory.
Always supply `fork_turns: "none"` explicitly. Start the first useful scoped task,
then observe its successful claim, complete context and matching automatic pre/post
hook pair before preparing the rest of the cohort. Scoped preparation enforces
this automatically; `readiness_after` can name an additional same-phase startup
prerequisite. Release remaining ready work together while the first task works.
Do not use throwaway probes or relaunch unchanged failures. A repeated scoped
attempt needs `retry_reason` naming the observed defect or changed input.
Execute the exact returned context action. New scoped workers use `--drain`, which
returns at most 32 KiB including bodies and receipt. Return every response to the
consumer, then follow `next_action` only while `remaining_required` is nonzero.
Terminal responses have `done: true` and no action. Accumulate all subprocess/tool
chunks until exit before parsing; never parse a running handle's partial output.
Keep the combined response budget large enough and use bounded long waits (up to
60 seconds between user updates), not repeated short model-facing polls.
After a narrow repair, repeat affected checks and reviewers only. Unchanged
scoped results remain fresh within their original binding; across visits use
independently fingerprinted check evidence and a fresh scoped delta review.
Never transfer approval, worker identity or a context receipt to another binding.
Inspect attempt purposes, retry causes and delivered bytes in worker status and
the dashboard. Delivered bytes, native tokens and Codex allowance are different
measurements; no allowance saving can be inferred from byte counts alone.
`flow context --drain HANDOFF_SHA` is mutually exclusive with consume/read/read-required. It returns schema `taskplane.context-drain/v1`, pages, receipt, remaining_required, done and next_action (null on completion). Required preflight budgets count unique serialized body bytes; page and receipt overhead is reported separately by actual delivery.
SHA-256: 38a69f9d256e8e584e006edd10f347c0bb53b54c6be26529a895973ae12eb98b