The route-bound execution guard turns KnowledgeOS from an advisory checklist into a stricter execution harness.
The goal is simple: an agent should not mutate a project merely because a path is writable. The write must also belong to the selected task route.
Route is intentionally a policy guard, not a heavyweight workflow engine. Many real tasks are mixed: documentation plus code, research plus refactor, migration plus report. KnowledgeOS therefore uses route profiles to set boundaries, evaluation profiles, and human gates, while leaving fine-grained capability choice to dispatch-task.
In short:
route-task = what task policy applies, where writes may go, and what completion gate is required
dispatch-task = which orchestrator, subagent, MCP, skill, or script should be considered
Making route more complex is not automatically better. The safer default is a small number of policy profiles plus visible dispatch evidence.
check-route-write combines two gates:
.agent-os/write-policy.yamldecides whether the path is generally safe..agent-os/workflows/router.yamldecides whether the path is inside the task route'sallowed_outputs.
Example:
./bin/knowledgeos check-route-write \
--project-root /path/to/project \
--task-id T001 \
--path .agent-os/workspace.yamlIf the write is generally safe but outside the task route, the command returns route_output_denied.
run-task now requires:
- task status is
readyorin_progress; - task type resolves through
route-task; - route status is
routed.
This prevents agents from creating official run envelopes for backlog, completed, cancelled, or unknown-route tasks.
Agents should not hand-edit lifecycle evidence files. The default write policy now human-gates direct writes to:
.agent-os/runs/**/run.yaml.agent-os/runs/**/context-pack.md.agent-os/runs/**/spec-snapshot.md.agent-os/runs/**/plan.md.agent-os/runs/**/eval.md.agent-os/runs/**/phases.ndjson.agent-os/runs/**/command-events.ndjson.agent-os/runs/**/step-events.ndjson.agent-os/runs/**/capability-events.ndjson.agent-os/runs/**/effect-assertions.ndjson.agent-os/runs/**/postflight.md.agent-os/tasks.yaml.agent-os/specs.yaml.agent-os/specs/**.agent-os/evals.yaml.agent-os/read-policy.yaml.agent-os/write-policy.yaml.agent-os/dispatch-policy.yaml.agent-os/tool-registry.yaml.agent-os/workflows/router.yaml.agent-os/phase-policy.yaml.agent-os/fabric-link.yaml
The CLI commands can still write their own task/evidence state. Manual writes to those files are treated as a governance change or possible spoofing attempt.
complete-task closes a task only after the run has evidence of evaluation success, spec/context/plan evidence, lifecycle phase evidence, declared outputs, effect verification, and required postflight.
By default, the run must first pass knowledgeos eval-task. The generated eval.md must include both Generated By: knowledgeos eval-task and Status: passed.
The run must also pass verify-lifecycle, which checks .agent-os/runs/<RUN_ID>/phases.ndjson against .agent-os/phase-policy.yaml.
verify-lifecycle also checks command evidence from .agent-os/runs/<RUN_ID>/command-events.ndjson, so a hand-written phases.ndjson is not enough.
verify-lifecycle also checks capability visibility. A run must contain dispatch-task --run-id evidence, and required dispatch stages must either have a matching capability-event record or an explicit public skip reason in the dispatch phase evidence.
The run must also pass verify-context, which checks context-pack.md, spec-snapshot.md, plan.md, and the matching command evidence. If the active spec changes after the run snapshot, completion fails with spec_drift.
The run must also pass verify-effects, which checks .agent-os/runs/<RUN_ID>/effect-assertions.ndjson and matching artifact-assert command evidence. A hand-written effect ledger is not enough. If an effect assertion claims a capability_event_id, that id must exist in the same run's capability-events.ndjson; bogus links are rejected. Agents must relay the returned EFFECT_VERIFY_OK marker before claiming effect verification success.
Effect strictness is project-level:
observe: record the state without blocking.warn: allow completion but write warnings into the receipt.enforce: block completion when declared output effects are missing or forged.off: allow only with a receipt-visible downgrade reason.
If .agent-os/fabric-link.yaml sets postflight_required: true, complete-task runs the shared-fabric after-task.sh hook and requires [SYNC_OK] in stdout. If the hook cannot run, the task cannot complete unless the agent uses --allow-pending-postflight "<reason>", and that pending reason is written into the receipt.
Then complete-task writes:
- run receipt;
- run handoff;
.agent-os/receipts/latest.md;.agent-os/handoffs/current.md;- completed run status;
- completed task status.
- postflight evidence when postflight is required.
complete-task rejects run ids containing path separators. This prevents a malicious or mistaken ../ style value from escaping .agent-os/runs/.
doctor now checks that every router profile has:
- an
eval_profilethat exists in.agent-os/evals.yaml; - non-empty
allowed_outputs. - a complete
run-task -> context-pack -> plan-task -> phase-task -> eval-task -> verify-context -> verify-lifecycle -> verify-effects -> complete-tasklifecycle order.
This catches incomplete routes before agents rely on them.
For substantial work, the recommended local flow is now:
doctor
-> route-task
-> check-route-write for each planned path
-> run-task
-> dispatch-task --run-id records dispatch evidence for this run
-> context-pack writes/refreshes spec-snapshot.md and context-pack.md
-> plan-task writes the public execution plan
-> trace-step records public operational progress when useful
-> phase-task records route/plan/review/dispatch/execute/report public evidence
-> capability-event records MCP / skill / subagent / orchestrator / important script use
-> execute
-> eval-task writes deterministic eval evidence after checks pass
-> verify-context
-> verify-lifecycle
-> artifact-assert records real side-effect proof as EFFECT_OK
-> verify-effects emits EFFECT_VERIFY_OK with status and counts
-> complete-task
-> complete-task runs required postflight
Shared Fabric still owns global boot, memory lanes, and optional external postflight persistence. KnowledgeOS owns project-local route, write, run, phase ledger, eval, receipt, handoff state, and the completion-time postflight gate.
This is not a sandbox. It is a harness-level execution guard.
It helps prevent:
- accidental writes to raw materials;
- writes outside the selected task's output scope;
- official run evidence for unrouted tasks;
- task completion without a command-generated spec snapshot, context pack, and plan;
- silent spec drift after a run starts;
- task completion without a passing eval;
- task completion without required public phase evidence;
- task completion without required real artifact effect evidence;
- silent completion when required postflight is missing;
- run-id path traversal into unrelated files.
It does not replace OS-level file permissions, runtime sandboxing, code review, or human approval for high-risk actions.
The route-bound execution guard tests cover:
- allowed route writes;
- out-of-route write denial;
- immutable path denial;
- non-ready task rejection;
- unknown route rejection;
- missing eval rejection;
- missing plan/context rejection;
- spec drift rejection;
- missing lifecycle rejection;
- postflight-required rejection when the hook is missing;
- safe task completion after
eval-taskrecordsStatus: passed; - safe task completion after
verify-lifecycleandverify-effectspass and postflight returns[SYNC_OK]; - run-id path traversal rejection.