{"id":"c19e2ea8-c07b-49f5-9c40-262785ad7c8c","entityType":"agent","slug":"clawhub-jimmylegendary-taskops","name":"TaskOps","canonicalUrl":"https://www.xpersona.co/agent/clawhub-jimmylegendary-taskops","canonicalPath":"/agent/clawhub-jimmylegendary-taskops","generatedAt":"2026-10-11T10:50:20.118Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T07:09:25.773Z","emptyReason":null},"description":"Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution log... Skill: TaskOps Owner: jimmylegendary Summary: Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution log... Tags: latest:0.5.4 Version history: v0.5.4 | 2026-06-16T11:48:56.544Z | user Add taskops daemon supervisor with user-systemd install/start/status/logs/uninstall lifecycle. v0.5.3 | 2026-06-16T11:07:43.678Z | user","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s175t2e2n8hr9v2jphatfs57ah83qsr1:taskops","sourceUrl":"https://clawhub.ai/jimmylegendary/taskops","homepage":"https://clawhub.ai/jimmylegendary/skills/taskops","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/jimmylegendary/taskops","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/jimmylegendary/skills/taskops","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution log..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:09:25.773Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:09:25.773Z","emptyReason":null},"stars":null,"forks":null,"downloads":1127,"packageName":null,"latestVersion":"0.5.4","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:09:25.705Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T07:09:25.773Z","lastCrawledAt":"2026-10-11T07:09:25.705Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T07:09:25.705Z","lastVerifiedAt":null,"highlights":[{"version":"0.5.4","createdAt":"2026-06-16T11:48:56.544Z","changelog":"Add taskops daemon supervisor with user-systemd install/start/status/logs/uninstall lifecycle.","fileCount":62,"zipByteSize":88625},{"version":"0.5.3","createdAt":"2026-06-16T11:07:43.678Z","changelog":"TaskOps v0.5.3: harden queue runner stale lease recovery, attempt finalization, and timeout documentation.","fileCount":62,"zipByteSize":88168},{"version":"0.5.2","createdAt":"2026-06-15T20:01:59.546Z","changelog":"Add queue-backed runner watch mode, retry attempt caps, OpenClaw chat progress reports, and stable dogfood smoke deadlines.","fileCount":62,"zipByteSize":88111},{"version":"0.5.1","createdAt":"2026-06-15T05:32:55.099Z","changelog":"TaskOps v0.5.1: queue projection, queue-backed runner once, runner attempts, progress report ledger, and Node 22 queue runtime requirement.","fileCount":63,"zipByteSize":87006},{"version":"0.5.0","createdAt":"2026-05-13T18:25:05.187Z","changelog":"Simple Honest Long-Run Loop: add taskops next, explain, and guarded close commands; reinforce TaskOps as a work-truth protocol for long-running AI agent work.","fileCount":62,"zipByteSize":85494},{"version":"0.4.5","createdAt":"2026-05-13T16:12:30.378Z","changelog":"Runner dogfood improvements: snapshot extension, all_closed, unblock-check, blocker rechecks, and runner smoke coverage.","fileCount":61,"zipByteSize":83601},{"version":"0.4.4","createdAt":"2026-05-12T03:31:03.869Z","changelog":"Sharpen README positioning across GitHub, npm, and ClawHub: TaskOps as an agentic execution control layer, with a smaller quick loop and AI-assisted refactor example.","fileCount":61,"zipByteSize":82681},{"version":"0.4.3","createdAt":"2026-05-12T03:21:26.926Z","changelog":"Fix dry-run decomposition reuse when the child task group/version already exists; runner dispatch semantics from 0.4.2 retained.","fileCount":61,"zipByteSize":82138}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s175t2e2n8hr9v2jphatfs57ah83qsr1:taskops","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T10:50:20.115Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimmylegendary-taskops/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T07:09:25.773Z","emptyReason":null},"readme":"Skill: TaskOps\n\nOwner: jimmylegendary\n\nSummary: Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution log...\n\nTags: latest:0.5.4\n\nVersion history:\n\nv0.5.4 | 2026-06-16T11:48:56.544Z | user\n\nAdd taskops daemon supervisor with user-systemd install/start/status/logs/uninstall lifecycle.\n\nv0.5.3 | 2026-06-16T11:07:43.678Z | user\n\nTaskOps v0.5.3: harden queue runner stale lease recovery, attempt finalization, and timeout documentation.\n\nv0.5.2 | 2026-06-15T20:01:59.546Z | user\n\nAdd queue-backed runner watch mode, retry attempt caps, OpenClaw chat progress reports, and stable dogfood smoke deadlines.\n\nv0.5.1 | 2026-06-15T05:32:55.099Z | user\n\nTaskOps v0.5.1: queue projection, queue-backed runner once, runner attempts, progress report ledger, and Node 22 queue runtime requirement.\n\nv0.5.0 | 2026-05-13T18:25:05.187Z | user\n\nSimple Honest Long-Run Loop: add taskops next, explain, and guarded close commands; reinforce TaskOps as a work-truth protocol for long-running AI agent work.\n\nv0.4.5 | 2026-05-13T16:12:30.378Z | user\n\nRunner dogfood improvements: snapshot extension, all_closed, unblock-check, blocker rechecks, and runner smoke coverage.\n\nv0.4.4 | 2026-05-12T03:31:03.869Z | user\n\nSharpen README positioning across GitHub, npm, and ClawHub: TaskOps as an agentic execution control layer, with a smaller quick loop and AI-assisted refactor example.\n\nv0.4.3 | 2026-05-12T03:21:26.926Z | user\n\nFix dry-run decomposition reuse when the child task group/version already exists; runner dispatch semantics from 0.4.2 retained.\n\nv0.4.2 | 2026-05-12T03:17:37.592Z | user\n\nRunner dispatches runnable, decomposition, exploration, blocked, and waiting semantics.\n\nv0.4.1 | 2026-05-07T20:39:10.743Z | user\n\nPatch release after v0.4.0: polish npm package README and metadata; TaskOps closure/delegation model unchanged.\n\nv0.4.0 | 2026-05-07T20:17:48.828Z | user\n\nAdd work roots, explicit EoW closure nodes, delegated waiting run nodes, bidirectional task-run refs, and independent runs storage.\n\nArchive index:\n\nArchive v0.5.4: 62 files, 88625 bytes\n\nFiles: examples/md-first-minimal/project-alpha/index.md (621b), examples/md-first-minimal/project-alpha/project-log.md (251b), examples/md-first-minimal/project-alpha/steps/step-1/index.md (444b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/index.md (566b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/nodes/node-compare-layout.md (655b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/phase-log.md (150b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/results/result-0001.md (864b), examples/md-first-minimal/project-alpha/steps/step-1/step-log.md (109b), examples/md-first-minimal/project-alpha/summary.md (270b), examples/md-first-minimal/README.md (403b), examples/minimal-project/graph.json (3183b), examples/minimal-project/summary.md (1176b), examples/self-dogfood-obsidian-vault/index.md (250b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-commit-findings-1__node-choose-next-improvement.md (940b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-commit-findings-1__phase-commit-findings-1-root.md (603b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-converge-findings-1__node-summarize-findings.md (1042b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-converge-findings-1__phase-converge-findings-1-root.md (615b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-commit-execution-1__node-lock-execution-findings.md (982b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-commit-execution-1__phase-commit-execution-1-root.md (621b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-execution-2__node-build-self-dogfood-example.md (1113b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-execution-2__phase-diverge-execution-2-root.md (627b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__node-read-cli-surface.md (940b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__node-read-phase1-spec.md (976b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__phase-diverge-surface-1-root.md (615b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-execution-2__node-validate-self-dogfood.md (960b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-execution-2__phase-verify-execution-2-root.md (621b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-surface-1__node-verify-phase1-usable.md (1046b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-surface-1__phase-verify-surface-1-root.md (609b), examples/self-dogfood-obsidian-vault/phases/step-followups__phase-commit-findings-1.md (1190b), examples/self-dogfood-obsidian-vault/phases/step-followups__phase-converge-findings-1.md (1177b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-commit-execution-1.md (1197b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-diverge-execution-2.md (1220b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-diverge-surface-1.md (1507b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-verify-execution-2.md (1191b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-verify-surface-1.md (1177b), examples/self-dogfood-obsidian-vault/projects/dogfood-phase1-project.md (654b), examples/self-dogfood-obsidian-vault/steps/step-followups.md (743b), examples/self-dogfood-obsidian-vault/steps/step-self-dogfood.md (1568b), examples/self-dogfood-project/graph.json (17884b), examples/self-dogfood-project/summary.md (6489b), README.md (2500b), references/cli.graph-task.md (5797b), references/core-model.md (8835b), references/decomposition-protocol.md (3247b), references/examples.expected-results.json (2590b), references/expected-result.schema.json (1450b), references/md-first-format.md (8709b), references/md-first-vnext-spec.md (13964b), references/obsidian-plugin-mvp-spec.md (6869b), references/phase1-graph-task-spec.md (4454b), references/phase2-obsidian-spec.md (2524b), references/phases.json (4196b), references/result-record.schema.json (790b), references/rules.graph-task.md (6274b), references/run-readiness.md (8930b), references/schema.graph-task.json (5881b), references/test-levels.json (1264b), scripts/graph_task.py (63616b), skill-card.md (2855b), SKILL.md (16906b), tests/test_graph_task_cli.py (18944b), _meta.json (126b)\n\nFile v0.5.4:SKILL.md\n\n---\nname: taskops\ndescription: \"Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution logs, exploration, delegation/waiting, EoW closure, validation, summaries, and runner-driven progress.\"\n---\n\n# TaskOps\n\nTaskOps is a **work-truth protocol**, not just a task manager. It exists so that AI agents can be trusted with hours/days/weeks of work without pretending tasks are done, silently stopping, asking \"what next?\", or executing a wrong plan. Plans lie, logs drift, and TODO lists make agent work look simpler than it is; TaskOps separates task decomposition from execution reality and forces explicit, file-backed closure.\n\nUse it when the user needs to know what should happen, what actually happened, what is blocked or delegated, and whether work is truly closed.\n\n## Canonical rule\n\nTaskOps v1 is **md-first**.\n\nCanonical state lives in markdown files arranged around:\n- `task-groups/`\n- `snapshots/`\n- `runs/<run-id>/`\n- non-canonical `derived/`\n\nDo **not** treat `.taskops/queue.sqlite`, `graph.json`, or generated canvases as durable semantic truth. SQLite is an execution projection/ledger, not the task graph source of truth.\n\n## Read these first\n\n- `references/core-model.md`\n- `references/md-first-format.md`\n- `references/decomposition-protocol.md`\n- `references/run-readiness.md`\n- `../examples/taskops-canonical-minimal-v1/`\n\n## Current operating model\n\n- Task graph = decomposition truth\n- Run graph = execution truth\n- Work = top-level objective container (`entityType: work`; legacy `project` can still be read)\n- Task groups are versioned\n- Snapshots materialize selected version paths\n- EoW (End of Work) is an explicit terminal node, not just a status field\n- Run graphs are independent under `runs/<run-id>/` and may reference external runs/tasks without being merged\n- Task↔run traceability is bidirectional: task `runRefs` plus run-node `sourceTaskId` / `sourceTaskGroupVersionId`\n- Delegation/waiting belongs in the run graph as `type: delegate` / `status: waiting` with delegatee, request, expected output, and optional timeout metadata\n- Markdown is canonical; canvas/views are derived\n- SQLite queue state is a rebuildable execution projection plus lease/report ledger\n- Shared status vocabulary: `pending | active | done | blocked | waiting | cancelled`\n- Before execution, classify task run readiness as `runnable | needs_decomposition | needs_exploration | blocked`\n- Use `needs_exploration` when the objective is meaningful but the system does not yet know enough to decompose honestly; exploratory runs may search, try, debug, prototype, and reflect to learn constraints for the next graph update\n\n## Decomposition discipline\n\n- Start with a one-line objective.\n- Decompose depth 1 by default.\n- Do not turn decomposition into an activity checklist.\n- A task can be large but not decomposable yet; if the missing knowledge blocks honest decomposition, create an exploratory run and feed the result back into the task graph.\n- A terminal selected branch is not closed until an EoW node is attached.\n- Do not continue past a delegated/waiting run node until it resolves, is cancelled, or times out into an explicit follow-up.\n\n## Preferred CLI\n\nUse the npm CLI first:\n\n```bash\ntaskops validate <path>\ntaskops summary <path>\ntaskops show <path> --json\ntaskops classify-runnable <work-dir> <task-id> --json\ntaskops next <work-dir> --json\ntaskops explain <work-dir> --json\ntaskops close <work-dir> <run-node-id|task-id> [--reason <reason>] [--json]\ntaskops init <dir> --id <id> --title <title> --objective <objective>\ntaskops vault-init <vault-dir> --repo-url <url> --branch <branch> --auto-sync true\ntaskops git-status <vault-dir>\ntaskops git-sync <vault-dir> --message <message>\ntaskops watch-sync <vault-dir> --debounce-ms 5000\ntaskops decompose <work-dir> --task-group-id <id> --spec <spec.json>\ntaskops refactor <work-dir> --task-group-id <id> --spec <spec.json> --supersedes <version-id>\ntaskops run <work-dir> [--run-id <id>] [--agent <agent-id>] [--executor dry-run|openclaw-agent] [--max-steps <n>] [--until <iso-timestamp>] [--timeout <seconds>] [--loopback none|self] [--max-loopbacks <n>] [--json]\ntaskops queue sync <work-dir> [--json]\ntaskops queue list <work-dir> [--json]\ntaskops queue claim <work-dir> [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--json]\ntaskops queue heartbeat <work-dir> <lease-id> [--ttl-seconds <n>] [--json]\ntaskops queue release <work-dir> <lease-id> [--status done|failed|cancelled] [--json]\ntaskops queue reports <work-dir> [--json]\ntaskops runner once <work-dir> [--runtime dry-run|openclaw-cli] [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--timeout <seconds>] [--report-sink none|ledger|openclaw-chat-inject] [--master-session-key <key>] [--json]\ntaskops runner watch <work-dir> [--runtime dry-run|openclaw-cli] [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--timeout <seconds>] [--report-sink none|ledger|openclaw-chat-inject] [--master-session-key <key>] [--poll-interval-ms <n>] [--max-waves <n>] [--max-idle-cycles <n>] [--idle-exit-after-seconds <n>] [--until <iso-timestamp>] [--continue-on-failure] [--json]\ntaskops daemon run <work-dir> [--name <name>] [--runtime dry-run|openclaw-cli] [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--timeout <seconds>] [--report-sink none|ledger|openclaw-chat-inject] [--master-session-key <key>] [--poll-interval-ms <n>] [--daemon-poll-interval-ms <n>] [--failure-backoff-ms <n>] [--max-daemon-cycles <n>] [--continue-on-failure] [--json]\ntaskops daemon unit <work-dir> [--name <name>] [--runtime dry-run|openclaw-cli] [--json]\ntaskops daemon install <work-dir> [--name <name>] [--runtime dry-run|openclaw-cli] [--start] [--dry-run] [--json]\ntaskops daemon start|stop|restart|status|logs|uninstall <name> [--json]\ntaskops restart <work-dir> --from <task-id> [--instruction <text>] [--instruction-file <path>] [--reason <text>] [--json]\n```\n\n## Honest-loop commands\n\nThese three commands are the small surface area that keeps long-running agents honest. They never silently mutate progress:\n\n- `taskops next <work-dir> --json` — returns the one next honest action: `execute`, `decompose`, `explore`, `wait`, `delegation_pending`, `blocked`, `done`, or `no_runnable`. Use it instead of guessing what to do next.\n- `taskops explain <work-dir> --json` — explains why work is or is not closed: closure summary, next honest action, and concrete open reasons (missing EoW, blockers, waiting delegations, runnable/decompose/explore tasks, validation errors).\n- `taskops close <work-dir> <run-node-id|task-id> [--reason <reason>] [--json]` — make EoW closure explicit and guarded. It refuses to close a task that already has an EoW, has open child branches, or is not yet `done` unless `--reason manual_verified` is supplied. It refuses to close a run node unless its status is `done`/`cancelled` or an explicit reason (`failure`, `superseded`, `cancelled`, `manual_verified`) is supplied. Use this rather than editing EoW files by hand.\n\n## Running TaskOps work\n\n`taskops run <work-dir>` is the canonical way to advance a TaskOps work graph. The skill is passive guidance; the runner is the layer that actually mutates state.\n\n- Use `taskops run <work-dir>` instead of editing run nodes / EoW / runRefs / child task groups by hand. The runner deterministically picks the next task (active snapshot order, then `task.order`, then `id`), classifies it, and dispatches the matching action.\n- The runner handles three task readiness states each as one bounded step:\n  - `runnable` — creates the run node, executes via the executor, marks the task done, writes the task and run EoW nodes, and creates the `closes_with` edge.\n  - `needs_decomposition` — creates a `type: decomposition` run node, expands the task graph with a child task group and a v1 version (dry-run synthesizes a deterministic placeholder; `openclaw-agent` delegates authoring to the agent and verifies the result), sets the parent task's `childTaskGroupId`, closes the parent task with EoW reason `decomposed_by_runner`, and extends the active snapshot's `selectedVersions` so the new child task group/version becomes visible to later steps of the same runner invocation.\n  - `needs_exploration` — creates a `type: exploration` run node, writes a reflection artifact at `runs/<run-id>/artifacts/<run-node-id>.md`, then marks the parent done with EoW reason `exploration_recorded_by_runner` and sets its `runReadiness` to `needs_decomposition` so the next pass can author informed children.\n- `blocked` tasks are excluded from execution. If only blocked tasks remain the runner stops with `blocked_only`.\n- Before each selection pass, the runner rechecks blocked tasks with `blockedBy` references. If every referenced task/run node blocker is `done` or `cancelled`, it reopens the task (`status: pending`) and clears `runReadiness: blocked` unless `unblockRunReadiness` is set. Use `taskops unblock-check <work-dir> --dry-run --json` to inspect this without mutation.\n- `status: waiting` tasks and non-delegate run nodes, and `type: delegate` run nodes that are not yet `done`/`cancelled`, pause the runner with stop reason `waiting` or `delegation_pending`. Delegate type wins over generic waiting, so `type: delegate` + `status: waiting` reports `delegation_pending`. Surface the pause to the user; do not auto-skip.\n- Prefer `--executor openclaw-agent --agent <agent-id>` for real execution, decomposition, and exploration. Default `--agent` is `main`. Only use `--executor dry-run` for smoke tests, reviews, or to demonstrate the graph mutations without touching an external agent — it produces synthetic success and never performs real work. The synthetic decomposition placeholders are explicitly `runReadiness: blocked` so they cannot be mistaken for real progress.\n- `--max-steps <n>` bounds the total number of actions (execute + decompose + explore). `--until <iso-timestamp>` bounds wall-clock work. Both are optional and **combine with OR semantics**: stop before a new step if either limit is reached.\n- If neither `--max-steps` nor `--until` is supplied, the runner defaults to `--max-steps 1` — exactly one step, then stop.\n- When the user says something like \"before tomorrow 9am\" or \"by EOD\", convert the requested deadline to an explicit ISO-8601 timestamp **with timezone** before passing it as `--until`. Do not pass natural-language deadlines.\n- Stop reasons reported back: `all_closed`, `no_runnable`, `blocked_only`, `waiting`, `delegation_pending`, `max_steps`, `deadline_reached`, `max_loopbacks`, `task_failed`, `validation_failed`. `all_closed` means the selected work is fully closed by task + run EoW with no waiting/delegated/blocked work; `no_runnable` means nothing actionable but the work is not yet closed. Always surface the reason to the user.\n- The runner appends to `runs/<run-id>/events.jsonl` and `runs/<run-id>/run-log.md`, and holds a `.taskops-runner.lock` directory inside the work root while running. Do not launch a second runner against the same work until the lock is gone.\n- Do **not** instruct the executing agent to call `taskops run` again — it runs one task. Recursion is the orchestrator's job, not the worker's.\n- `--loopback none` (default) keeps the cautious behaviour: every pending `type: delegate` stops the runner. Pass `--loopback self` to let the runner auto-resolve *self-delegates* (`delegateeType: self`, `delegateeRef: self`, or `delegateeRef: <work-id>`) by opening a `type: loopback` resolution node, executing the loopback once, writing a `loopback` edge, and closing both the loopback and the original delegate (`reason: self_loopback_resolved`, `resolvedBy: self_loopback`). Non-self delegates are still surfaced as `delegation_pending`. Each loopback counts against `--max-steps` and a separate `--max-loopbacks` budget (default `3`); exceeding it stops with `max_loopbacks` and leaves the delegate open. The executing agent inside a loopback must still not call `taskops run` recursively — orchestration stays at the runner.\n- `taskops restart <work-dir> --from <task-id> --instruction \"<text>\" [--reason <text>] [--instruction-file <path>] [--json]` rolls the active version of the containing task group forward to a new version, marks the prior version `selected: false` and `supersededByVersionId`, points the active snapshot at the new version, and updates the task group's `activeVersionId`. Upstream tasks (`order < target.order`) keep their status and gain `preservedUpstream: true` with a fresh `preserved_upstream_after_restart` EoW when they were done leaves. The target task is reset to `pending` with `restartInstruction`, optional `restartReason`, `restartedFromVersionId`, and `restartedAt`. Downstream tasks (`order >= target.order`, excluding the target) are reset to `pending`. Historical runs/run nodes/EoWs are not modified — they remain as evidence. Use this instead of editing tasks by hand when an upstream change invalidates a task and its downstream.\n\n## Queue projection and watch runner\n\n`taskops queue sync <work-dir>` creates or refreshes `.taskops/queue.sqlite` from the canonical markdown state. The database is rebuildable projection state for queue items, leases, attempts, and progress reports. Deleting it and syncing again must not destroy semantic truth.\n\n`taskops runner once <work-dir>` claims one executable queue item, runs exactly that claimed task through a runtime adapter, releases the lease, refreshes the queue projection, and optionally writes a progress report ledger row.\n\n`taskops runner watch <work-dir>` is the local always-on primitive. It loops over `runner once`, waits when no queue item is currently claimable, and exits with `all_closed` when TaskOps closure says the work is complete. Bounds such as `--max-waves`, `--max-idle-cycles`, `--idle-exit-after-seconds`, and `--until` are for tests, controlled sessions, and supervised deployments. Watch mode defaults to `--max-attempts 3`; pass `--max-attempts 0` only when an external supervisor owns retry safety.\n\nImportant boundary:\n\n- SQLite does not call OpenClaw and does not execute triggers by itself.\n- The watch runner is the process that stays alive and invokes the runtime adapter.\n- `taskops daemon install <work-dir> --name <name> --start` is the preferred unattended local mode. It writes a user-systemd service around `taskops daemon run`, not around `runner watch`, so normal `all_closed` watch exits do not become systemd restart loops.\n- `taskops daemon run` repeatedly starts watch cycles, preserves stop reasons, sleeps between cycles, and is the foreground process that systemd supervises.\n- `--runtime openclaw-cli` maps to same-host `openclaw agent --json`.\n- Use `--timeout <seconds>` with `--runtime openclaw-cli` for unattended waves. Internal timeout finalizes the attempt as failed and releases the lease; external shell `timeout` should be a supervisor last resort, not the normal control path.\n- If a runner process is externally killed after claiming a lease, the next queue sync/list/claim operation marks the expired lease stale, finalizes any linked running attempt as failed, and lets the fingerprint retry cap decide whether to reclaim it.\n- `--max-attempts <n>` skips queue items whose current markdown fingerprint already has `n` failed runner attempts. Editing the task markdown changes the fingerprint and resets the retry budget.\n- Watch mode stops on the first failed wave by default to avoid retry loops. Use `--continue-on-failure` only with `--max-attempts` or a separate retry/attempt guard.\n- `--report-sink ledger` records progress in `.taskops/queue.sqlite`.\n- `--report-sink openclaw-chat-inject` delivers progress to `--master-session-key` with `openclaw gateway call chat.inject` and records delivery success/failure in the same SQLite report ledger.\n- Future dashboard/webhook sinks should not change TaskOps graph truth.\n\n## Git-backed vault rule\n\nIf the user is working in an Obsidian vault that should stay aligned with a GitHub repo, prefer:\n\n1. `taskops vault-init ... --repo-url ... --auto-sync true`\n2. keep `.taskops/taskops-sync.json` in the vault root\n3. use the desktop Obsidian plugin or `taskops watch-sync`/`taskops git-sync` so local vault edits are pushed back to GitHub instead of drifting\n\n## Legacy note\n\n`python3 scripts/graph_task.py ...` still exists as a migration aid for the earlier graph-task prototype.\nOnly use it when the task is explicitly about legacy behavior or migration.\n\n## Minimum validation before claiming success\n\nRun:\n\n```bash\ntaskops validate <work-dir>\ntaskops summary <work-dir>\n```\n\nIf you changed the skill itself, also run:\n\n```bash\npython3 /home/jimmy/.npm-global/lib/node_modules/openclaw/skills/skill-creator/scripts/package_skill.py <skill-dir> <output-dir>\n```\n\nFile v0.5.4:examples/md-first-minimal/README.md\n\n# md-first minimal example\n\nThis example demonstrates the proposed vNext canonical layout where markdown files are the source of truth.\n\nIt intentionally stays tiny:\n- 1 Project\n- 1 Step\n- 1 Phase\n- 1 Node\n- 1 Result\n- log files at each structural level\n\nUse it to pressure-test:\n- folder naming rules\n- YAML frontmatter shape\n- append-only result handling\n- Obsidian navigation\n- future plugin parsing\n\nFile v0.5.4:README.md\n\n# TaskOps skill\n\n**AI agent work cannot be managed as a flat TODO list.**\n\nTaskOps is a markdown-canonical execution control protocol for keeping human + AI work honest: separate the decomposition truth from execution reality, record blockers and delegation explicitly, and only close work when there is visible evidence.\n\n## Canonical shape\n\nTaskOps v1 separates:\n- **work root** at `index.md` with `entityType: work`\n- **task graph** under `task-groups/`\n- **snapshot selection** under `snapshots/`\n- **execution truth** under independent `runs/<run-id>/` graphs\n- **EoW terminal nodes** under task-version `eow/` folders and run `nodes/`\n- **derived views** under `derived/`\n\nMarkdown is canonical.\nDerived canvas/views are not.\n\n## Current surfaces\n\n- `../cli/` — installable `taskops` CLI for `init / validate / summary / show / decompose / refactor / run` plus git-backed vault setup/sync\n- `../obsidian-plugin/` — Obsidian explorer + derived canvas export for TaskOps v1 projects, with desktop git auto-sync support when configured\n- `scripts/graph_task.py` — legacy graph-task prototype kept only as migration/source material\n\n## Main working references\n\n- `../docs/CORE_MODEL.md`\n- `../docs/MD_FIRST_FORMAT.md`\n- `../examples/taskops-canonical-minimal-v1/`\n- `SKILL.md`\n\n## Core operating loop\n\n```bash\ntaskops init <work-dir> --id <id> --title <title> --objective <objective>\ntaskops validate <work-dir>\ntaskops summary <work-dir>\ntaskops classify-runnable <work-dir> <task-id> --json\ntaskops run <work-dir> --executor dry-run --max-steps 1 --json\n```\n\nUse `dry-run` for smoke tests and graph rehearsals. Use `--executor openclaw-agent --agent <agent-id>` when the user wants real agent execution.\n\n## Good fit\n\nTaskOps is strongest for complex agentic work such as refactors, migrations, research-to-implementation loops, and multi-step investigations where the user needs to know:\n\n- what the goal is\n- how it was decomposed\n- what actually ran\n- what got blocked, delegated, or explored\n- why a branch is truly closed\n\n## Validation stance\n\nPrefer the CLI for current validation and summaries:\n\n```bash\ntaskops validate <work-dir>\ntaskops summary <work-dir>\n```\n\nFor a git-backed Obsidian vault workflow:\n\n```bash\ntaskops vault-init <vault-dir> --repo-url <github-repo-url> --branch main --auto-sync true\ntaskops git-sync <vault-dir> --message \"Sync vault changes\"\n```\n\nOnly use the legacy Python script when the work is explicitly about old graph-task compatibility or migration.\n\nFile v0.5.4:_meta.json\n\n{\n  \"ownerId\": \"kn73mypx9fx9qehs8agyh3drs183bb1y\",\n  \"slug\": \"taskops\",\n  \"version\": \"0.5.4\",\n  \"publishedAt\": 1781610536544\n}\n\nFile v0.5.4:references/cli.graph-task.md\n\n# graph-task CLI surface\n\n> Legacy prototype note: this CLI currently operates on `graph.json` runs.\n> In the md-first direction, treat its outputs as legacy behavior, migration help, or derived snapshots/exports — not canonical markdown state.\n\nUse the bundled CLI with:\n\n```bash\npython3 scripts/graph_task.py <command> ...\n```\n\nAll commands accept either:\n- a run directory (the CLI will use `graph.json` inside it), or\n- a direct path to `graph.json`\n\n## Shared status vocabulary\n\nUse the same minimal status set everywhere:\n- `pending`\n- `active`\n- `done`\n- `blocked`\n- `cancelled`\n\n## Commands\n\n### init\nCreate a new run directory with `graph.json` and `summary.md`.\n\n```bash\npython3 scripts/graph_task.py init ./runs/demo \\\n  --id demo-project \\\n  --title \"Demo project\" \\\n  --description \"Test graph\" \\\n  --goal \"Reach a validated state\"\n```\n\nTo initialize inside a git-backed vault/work repo, point `path` at the desired local checkout directory and pass a repo URL. The CLI will clone or refresh the checkout, then create the run under `<checkout>/<project-id-slug>/`.\n\n```bash\npython3 scripts/graph_task.py init ./tmp/company-vault \\\n  --repo-url https://github.company.com/ORG/obsidian-vault.git \\\n  --repo-branch main \\\n  --id graph-task-demo \\\n  --title \"Graph task demo\" \\\n  --description \"Repo-backed run\" \\\n  --goal \"Write into a project-specific folder\"\n```\n\n### show\nRender the current graph as a summary or raw JSON.\n\n```bash\npython3 scripts/graph_task.py show ./runs/demo\npython3 scripts/graph_task.py show ./runs/demo --format json\n```\n\n### add-step\nAdd a Project-level Step.\n\n```bash\npython3 scripts/graph_task.py add-step ./runs/demo \\\n  --id step-1 \\\n  --step-type implementation \\\n  --description \"Implement state handling\"\n```\n\n### add-step-edge\nConnect two Steps.\n\n```bash\npython3 scripts/graph_task.py add-step-edge ./runs/demo \\\n  --id step-edge-1 \\\n  --from-step step-1 \\\n  --to-step step-2\n```\n\n### add-phase\nAdd a Step-level Phase and automatically create its root node.\n\n```bash\npython3 scripts/graph_task.py add-phase ./runs/demo \\\n  --step-id step-1 \\\n  --id phase-diverge-1 \\\n  --phase-type diverge \\\n  --description \"Explore implementation options\"\n```\n\n### add-phase-edge\nConnect two Phases inside a Step.\n\n```bash\npython3 scripts/graph_task.py add-phase-edge ./runs/demo \\\n  --step-id step-1 \\\n  --id phase-edge-1 \\\n  --from-phase phase-diverge-1 \\\n  --to-phase phase-verify-1\n```\n\n### add-node\nAdd a work node to a Phase.\n\n```bash\npython3 scripts/graph_task.py add-node ./runs/demo \\\n  --phase-id phase-diverge-1 \\\n  --id node-1 \\\n  --title \"Compare libraries\" \\\n  --description \"Check Zustand and Redux\"\n```\n\n### add-edge\nConnect two Nodes inside a Phase.\n\n```bash\npython3 scripts/graph_task.py add-edge ./runs/demo \\\n  --phase-id phase-diverge-1 \\\n  --id edge-1 \\\n  --from-node phase-diverge-1-root \\\n  --to-node node-1 \\\n  --edge-type flow\n```\n\n### set-status\nSet the status on a Project, Step, Phase, or Node.\n\n```bash\npython3 scripts/graph_task.py set-status ./runs/demo \\\n  --entity-type node \\\n  --entity-id node-1 \\\n  --status active\n```\n\n### write-result\nAppend an expected-vs-actual record to a work node.\n\n```bash\npython3 scripts/graph_task.py write-result ./runs/demo \\\n  --node-id node-1 \\\n  --expected \"Choose a candidate state library\" \\\n  --actual \"Selected Zustand after comparing complexity\" \\\n  --status done \\\n  --notes \"Simple enough for current scope\"\n```\n\n### validate\nValidate the graph against the current high-level rules.\n\n```bash\npython3 scripts/graph_task.py validate ./runs/demo\n```\n\n### summary\nRegenerate and print `summary.md`.\n\n```bash\npython3 scripts/graph_task.py summary ./runs/demo\n```\n\n### export-obsidian\nExport the current legacy JSON run into an Obsidian-friendly markdown projection.\n\nThis export is **non-canonical**. It is a derived view from `graph.json`, not the md-first source of truth.\n\n```bash\npython3 scripts/graph_task.py export-obsidian ./runs/demo ./tmp/demo-vault\npython3 scripts/graph_task.py export-obsidian ./runs/demo ./tmp/demo-vault --force\n```\n\n### git-status\nShow git sync state for a repo-backed run.\n\n```bash\npython3 scripts/graph_task.py git-status ./tmp/company-vault/graph-task-demo\n```\n\n### git-pull\nFast-forward pull the backing repo for a repo-backed run. This fails if the repo has uncommitted changes.\n\n```bash\npython3 scripts/graph_task.py git-pull ./tmp/company-vault/graph-task-demo\n```\n\n### git-push\nPush the backing repo. If `--message` is provided, stage and commit all pending repo changes first.\n\n```bash\npython3 scripts/graph_task.py git-push ./tmp/company-vault/graph-task-demo \\\n  --message \"Update graph-task project\"\n```\n\n### git-sync\nPull first, then optionally commit all pending changes, then push. This is the main manual sync command for repo-backed runs.\n\n```bash\npython3 scripts/graph_task.py git-sync ./tmp/company-vault/graph-task-demo \\\n  --message \"Sync graph-task project updates\"\n```\n\n## Repo-backed run notes\n\n- `--repo-url` on `init` records repo metadata into `project.repo`.\n- Repo sync commands only work for runs initialized that way.\n- The sync commands operate on the whole backing repo, not only one project folder.\n- `git-pull` / `git-sync` intentionally use `pull --ff-only` to avoid hidden merge commits.\n- If the repo is dirty, pull fails on purpose; resolve or commit local changes first.\n\n## Current simplifications\n\nFor md-first work, prefer editing/validating canonical markdown directly rather than extending this JSON-first CLI unless the task is explicitly about legacy compatibility.\n\n\nThe current CLI intentionally does **not** have:\n- a separate mutation engine\n- hidden transition logic\n- branch/retry/replan commands\n\nIf the structure changes, append new Steps / Phases / Nodes / Edges directly and preserve history in the graph.\n\nFile v0.5.4:references/core-model.md\n\n# TaskOps core model\n\nThis document freezes the shared conceptual contract for TaskOps.\n\n## 1. Layer split\n\nTaskOps has one top-level container and two connected graph layers.\n\n### 1.1 Work\n\nPurpose:\n- hold one objective and its selected decomposition/execution state\n- answer whether the work is still open, waiting, or complete\n\nA `work` replaces the old conceptual `project` wording. Legacy `entityType: project` may still be read for compatibility, but new canonical work should use `entityType: work`.\n\n### 1.2 Task graph\n\nPurpose:\n- represent decomposition truth\n- enforce structural quality\n- preserve version history of decomposition changes\n- make branch closure explicit with EoW nodes\n\n### 1.3 Run graph\n\nPurpose:\n- represent execution truth\n- capture real dependency, overlap, reuse, branching, delegation, and waiting\n- connect work across levels when reality does not stay tree-shaped\n\nEvery run graph is an independent graph under `runs/<run-id>/`. A run graph may reference external tasks or external run nodes, but it should not be merged into another run graph just because it depends on it.\n\n## 2. Main entities\n\n### 2.1 Work\n\nFields:\n- `id`\n- `title`\n- `objective`\n- `activeRootTaskGroupId`\n- `activeSnapshotId?`\n- `createdAt`\n- `status`\n\n### 2.2 TaskGroup\n\nA versioned decomposition unit.\n\nFields:\n- `id`\n- `objective`\n- `parentTaskId?`\n- `activeVersionId?`\n- `createdAt`\n- `status?`\n\n### 2.3 TaskGroupVersion\n\nA concrete decomposition of one task group.\n\nFields:\n- `id`\n- `taskGroupId`\n- `version`\n- `summary`\n- `createdAt`\n- `supersedesVersionId?`\n- `isSelected`\n\nContains:\n- ordered child tasks\n- EoW nodes attached to terminal child tasks\n- decomposition rationale\n- validation metadata\n\n### 2.4 Task\n\nA child responsibility unit in one specific task-group version.\n\nFields:\n- `id`\n- `taskGroupVersionId`\n- `title`\n- `objective`\n- `responsibility`\n- `completionCriteria`\n- `order`\n- `runReadiness?` (`runnable | needs_decomposition | needs_exploration | blocked`)\n- `runReadinessReason?`\n- `understandingLevel?` (`known | partial | unknown`)\n- `unknowns?`\n- `nextLearningGoal?`\n- `decompositionConfidence?`\n- `executionConfidence?`\n- `childTaskGroupId?`\n- `runRefs?` (`[{ runId, runNodeId, role? }]`)\n\nA task may point to a child task group if it is further decomposed.\nIf TaskOps does not understand the domain well enough to split a task, the task should be marked `needs_exploration` rather than forcing a fake decomposition.\n\n`runRefs` is the task-side half of bidirectional task↔run traceability. A matching run node should point back with `sourceTaskId` and, when known, `sourceTaskGroupVersionId`.\n\n### 2.5 EoW\n\nEoW means **End of Work** for one graph branch.\nIt is a first-class node, not just a field, because graph visualization should make terminal branches obvious.\n\nFields:\n- `id`\n- `graphType` (`task | run`)\n- `attachedToType` (`task | runNode`)\n- `attachedToId`\n- `reason`\n- `declaredBy` (`human | ai | system | agent`)\n- `declaredAt`\n- `evidenceRefs?`\n- `createdAt`\n- `status`\n\nRules:\n- A task branch is not structurally closed until a terminal task has an attached task-graph EoW node.\n- A run path is not execution-closed until its terminal run node has an attached run-graph EoW node.\n- EoW does not mean the whole work is complete by itself; it closes one branch/path.\n\n### 2.6 VersionSnapshot\n\nA selected version path across connected task groups.\n\nFields:\n- `id`\n- `rootTaskGroupId`\n- `selectedVersionMap`\n- `createdAt`\n- `label?`\n\nImportant:\n- a snapshot records a chosen path\n- it is not the materialization of all combinatorial version states\n\n### 2.7 Run\n\nAn independent execution graph.\n\nFields:\n- `id`\n- `workId`\n- `createdAt`\n- `status`\n\n### 2.8 RunNode\n\nA unit of execution reality.\n\nFields:\n- `id`\n- `runId`\n- `type`\n- `title`\n- `objective?`\n- `status`\n- `sourceTaskId?`\n- `sourceTaskGroupVersionId?`\n- `createdAt`\n\nSuggested `type` examples:\n- `execute`\n- `explore`\n- `debug`\n- `review`\n- `verify`\n- `delegate`\n\nDelegation/waiting fields for `type: delegate` or `status: waiting`:\n- `delegateeType` (`human | ai | agent | system`)\n- `delegateeRef`\n- `request`\n- `expectedOutput`\n- `requestedAt`\n- `timeoutAt?`\n- `onTimeout?` (`escalate | retry | cancel | create_followup`)\n\nA waiting delegated node blocks downstream execution until it is resolved, cancelled, or timed out into a follow-up decision.\n\n### 2.9 RunEdge\n\nA relation between run graph nodes, including EoW terminal nodes.\n\nFields:\n- `id`\n- `runId`\n- `fromRunNodeId`\n- `toRunNodeId`\n- `edgeType`\n- `note?`\n\nSuggested `edgeType` examples:\n- `depends_on`\n- `informs`\n- `reuses`\n- `blocks`\n- `follows`\n- `tests`\n- `waits_for`\n- `closes_with`\n\n## 3. Task graph invariants\n\n### 3.1 Coverage\n\nThe child tasks in a task-group version must be sufficient to accomplish the parent objective.\n\nOperational test:\n> If every child task completes, can we honestly say the parent objective is accomplished?\n\n### 3.2 Responsibility orthogonality\n\nSibling tasks must not overlap in:\n- primary responsibility\n- primary ownership of the same deliverable\n- completion judgment\n\nAllowed:\n- shared context\n- mutual influence\n- downstream impact on each other\n- overlap in actual execution work inside the run graph\n\nNot allowed:\n- two sibling tasks both being the primary owner of the same thing\n- two sibling tasks requiring the same completion judgment to be considered done\n\n### 3.3 Closure\n\nEach task must have a locally understandable completion boundary, and every terminal selected branch must eventually end with an EoW node.\n\nOperational tests:\n> Can a human say what “done” means for this task without reading the entire project history?\n\n> Does every terminal branch in the active snapshot visibly close with EoW?\n\n## 4. Completion rule\n\nA work is complete when:\n\n```text\nactive snapshot terminal task branches all have task-graph EoW\n+ required terminal run paths have run-graph EoW\n+ there are no unresolved waiting/delegated/blocking run nodes\n```\n\nThis makes completion graph-visible instead of implicit.\n\n## 5. Task graph operations\n\n### 5.1 `decompose`\n\nCreates the first concrete child-task set for a task group.\n\nInput:\n- parent task group objective\n- rationale\n- proposed children\n\nOutput:\n- new `TaskGroupVersion`\n- child `Task` records\n- optional validation report\n\n### 5.2 `refactor`\n\nCreates a new version of an existing task group.\n\nUse when:\n- coverage is weak\n- sibling responsibility is overlapping\n- completion boundaries are unclear\n- learning changed the best decomposition\n\nImportant:\n- refactor does not erase old decomposition history\n- refactor creates a new `TaskGroupVersion`\n- child subtrees become version-dependent under the chosen path\n\n## 6. Run graph rules\n\nThe run graph may be messier than the task graph. That is expected.\n\nAllowed in run graph:\n- overlapping work\n- cross-level work relations\n- one run node helping multiple tasks\n- reused outputs\n- exploratory loops\n- explicit debugging, verification, and review work\n- human/AI/agent delegation and waiting\n- references to external run graphs\n\nExploratory run nodes are valid execution truth when their objective is learning: search, try/error, prototype, debug, or review enough context to improve the next task-graph decision.\n\nThe run graph should tell the truth about how work actually unfolded, even when that truth is not tree-shaped.\n\n## 7. Relation between task and run layers\n\n### 7.1 Bidirectional traceability\n\nA task may list `runRefs`.\nA run node may link back with `sourceTaskId` and `sourceTaskGroupVersionId`.\n\nValidator behavior:\n- task `runRefs` should resolve to real run nodes\n- referenced run nodes should point back to the source task\n- run nodes with `sourceTaskId` should have matching task-side `runRefs`\n\n### 7.2 Non-isomorphism\n\nThe run graph is not required to mirror the task graph one-to-one. That would be a design mistake.\n\nTask graph answers:\n> What is the right decomposition?\n\nRun-readiness classification answers:\n> Should this task run now, decompose next, explore first, or wait on a blocker?\n\nRun graph answers:\n> What actually happened in execution?\n\n### 7.3 Honest divergence\n\nIf real work repeatedly violates a decomposition, that is a signal to consider `refactor`.\nThe solution is not to falsify the run graph.\n\n## 8. Immediate implementation implications\n\nThe implementation should favor:\n- explicit ids\n- visible EoW terminal nodes\n- bidirectional task↔run references\n- independent `runs/<run-id>/` graphs\n- append-preserving history\n- version selection over destructive overwrite\n- validator checks for task-graph closure and run-graph waiting/delegation\n- md-first human inspectability\n\nThe implementation should avoid:\n- hidden closure fields that do not show up in graph views\n- combinatorial snapshot explosion\n- implicit mutation magic\n- overfitting the model to one UI surface\n\nFile v0.5.4:references/decomposition-protocol.md\n\n# TaskOps Decomposition Protocol\n\nTaskOps is not a checklist store. It turns an objective into a task tree, then uses execution feedback to improve the tree over time.\n\n## Core loop\n\n1. State the work objective in one sentence.\n2. Decompose only one requested depth at a time.\n3. Classify each task node by run readiness:\n   - `runnable`\n   - `needs_decomposition`\n   - `needs_exploration`\n   - `blocked`\n4. Send only `runnable` nodes into an independent run graph under `runs/<run-id>/`.\n5. For `needs_decomposition`, create the next task group/version.\n6. For `needs_exploration`, create an exploratory run whose purpose is understanding, not delivery.\n7. If a run needs a human, another AI, an agent, or an external system, create a `type: delegate` / `status: waiting` run node with expected output and timeout metadata.\n8. After every run, feed the result back into the task graph: update unknowns, constraints, decomposition, readiness, or task↔run refs.\n9. When a selected branch is truly terminal, attach an explicit EoW node. A branch without EoW is still open.\n\n## Objective discipline\n\nEvery work root and task group should have a one-line objective. That objective is the root of its decomposition tree.\n\nGood:\n\n```text\nBuild a today-first action app that makes the current actionable surface trusted.\n```\n\nBad:\n\n```text\nResearch tasks, build screens, define states, test, polish, launch.\n```\n\nThe bad example is an activity list. It mixes levels and hides responsibility boundaries.\n\n## Depth discipline\n\nDefault decomposition depth is `1`.\n\nA depth-1 result should contain the largest responsibility units under the parent objective, not every activity the system can imagine.\n\nExample:\n\n```text\nDevelop Today It app\n├─ Define product contract\n├─ Design core action loop\n├─ Build app foundation\n├─ Implement core features\n└─ Verify MVP\n```\n\nOnly decompose a child when the current child is not runnable and the system understands enough to split it honestly.\n\n## Anti-list validator heuristics\n\nA decomposition should be reviewed when:\n\n- sibling tasks mix abstraction levels\n- tasks are activities rather than responsibility units\n- parent-child relationship is weak or merely topical\n- depth expands before the parent objective is stable\n- a task is marked decomposable even though the system cannot explain the child responsibilities\n\n## Negative feedback loop\n\nTaskOps should improve inductively:\n\n```text\nobjective\n→ tree decomposition\n→ run-readiness classification\n→ run / decompose / explore\n→ result + delegation + failure + learned constraints\n→ revised tree\n→ EoW closure when a branch is terminal\n→ better next classification\n```\n\nThe important rule: failed or exploratory execution is not waste. It is feedback that updates the task graph.\n\n## Closure discipline\n\nDo not treat `done` as the same thing as EoW.\n\n- `done` is a status on a task or run node.\n- `EoW` is a visible terminal graph node declaring that this branch/path should not decompose or execute further.\n\nWork completion should be derived from graph closure:\n\n```text\nall active-snapshot terminal task branches have EoW\n+ required terminal run paths have EoW\n+ no unresolved waiting/delegated/blocking nodes remain\n```\n\nFile v0.5.4:references/examples.expected-results.json\n\n{\n  \"examples\": [\n    {\n      \"name\": \"unit-transition-ready-to-done\",\n      \"expected_result\": {\n        \"summary\": \"Marking a ready node as done should advance downstream blocked nodes whose dependencies are now satisfied.\",\n        \"verification\": {\n          \"level\": \"unit\",\n          \"checks\": [\n            {\n              \"id\": \"u1\",\n              \"type\": \"state\",\n              \"prompt\": \"After recording success on node A, node A must be status=done and any node depending only on A must become ready.\"\n            }\n          ]\n        },\n        \"failure_handling\": {\n          \"retry_hint\": \"Check dependency refresh logic.\",\n          \"escalate_when\": \"Dependency semantics are ambiguous or contradictory.\"\n        }\n      }\n    },\n    {\n      \"name\": \"integrated-cli-next-and-result\",\n      \"expected_result\": {\n        \"summary\": \"The CLI should initialize a graph, show the next ready node, accept a structured result, and produce an inspectable updated graph.\",\n        \"verification\": {\n          \"level\": \"integrated\",\n          \"checks\": [\n            {\n              \"id\": \"i1\",\n              \"type\": \"artifact\",\n              \"prompt\": \"The project directory must contain graph state and an updated event/result log after the CLI flow completes.\"\n            },\n            {\n              \"id\": \"i2\",\n              \"type\": \"behavior\",\n              \"prompt\": \"The next-node selection after result ingestion must match the dependency structure declared in the graph.\"\n            }\n          ]\n        },\n        \"failure_handling\": {\n          \"branch_hint\": \"Create a debug branch if the graph state is valid but selection behavior is inconsistent.\",\n          \"escalate_when\": \"State updates cannot be explained by the declared graph contract.\"\n        }\n      }\n    },\n    {\n      \"name\": \"closed-human-guided-review\",\n      \"expected_result\": {\n        \"summary\": \"In a bounded scenario, OpenClaw and Jimmy should be able to inspect the same graph and agree whether execution followed the intended path honestly.\",\n        \"verification\": {\n          \"level\": \"closed\",\n          \"checks\": [\n            {\n              \"id\": \"c1\",\n              \"type\": \"human-review\",\n              \"prompt\": \"A human reviewer can inspect the graph and understand why the current node was chosen and whether its outcome matched the declared expectation.\"\n            }\n          ]\n        },\n        \"failure_handling\": {\n          \"escalate_when\": \"The graph can be traversed mechanically but is not legible or reviewable by the human operator.\"\n        }\n      }\n    }\n  ]\n}\n\nFile v0.5.4:references/expected-result.schema.json\n\n{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"$id\": \"graph-task.expected-result.schema.v0\",\n  \"title\": \"ExpectedResult\",\n  \"type\": \"object\",\n  \"required\": [\"summary\", \"verification\"],\n  \"properties\": {\n    \"summary\": {\n      \"type\": \"string\",\n      \"description\": \"Natural-language statement of what should be true after the work.\"\n    },\n    \"verification\": {\n      \"type\": \"object\",\n      \"required\": [\"level\", \"checks\"],\n      \"properties\": {\n        \"level\": {\n          \"type\": \"string\",\n          \"enum\": [\"unit\", \"integrated\", \"closed\"]\n        },\n        \"checks\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"object\",\n            \"required\": [\"id\", \"type\", \"prompt\"],\n            \"properties\": {\n              \"id\": {\"type\": \"string\"},\n              \"type\": {\n                \"type\": \"string\",\n                \"enum\": [\"state\", \"artifact\", \"behavior\", \"human-review\"]\n              },\n              \"prompt\": {\n                \"type\": \"string\",\n                \"description\": \"Structured natural-language assertion that OpenClaw can review.\"\n              },\n              \"must_pass\": {\"type\": \"boolean\", \"default\": true}\n            }\n          }\n        }\n      }\n    },\n    \"failure_handling\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"retry_hint\": {\"type\": \"string\"},\n        \"branch_hint\": {\"type\": \"string\"},\n        \"escalate_when\": {\"type\": \"string\"}\n      }\n    }\n  }\n}\n\nFile v0.5.4:references/md-first-format.md\n\n# TaskOps md-first format\n\nThis document defines the canonical markdown-first storage direction for TaskOps.\n\n## Goals\n\n- human-readable and human-editable\n- validator-friendly\n- append-preserving where possible\n- suitable for both skill and Obsidian plugin surfaces\n- clear separation between canonical state and derived visualization artifacts\n- graph-visible closure through explicit EoW nodes\n\n## Design stance\n\nTaskOps stores **canonical decomposition state** and **canonical execution state** in markdown-first structures.\nDerived artifacts such as canvas views, summaries, or exports must stay explicitly non-canonical.\n\n## Top-level work shape\n\n```text\n<taskops-work>/\n  index.md\n  work-log.md\n  task-groups/\n    <task-group-id>/\n      index.md\n      versions/\n        <version-id>/\n          index.md\n          decomposition-log.md\n          tasks/\n            <task-id>.md\n          eow/\n            <eow-id>.md\n  snapshots/\n    <snapshot-id>.md\n  runs/\n    <run-id>/\n      index.md\n      nodes/\n        <run-node-id>.md\n        <eow-id>.md\n      edges/\n        <run-edge-id>.md\n      run-log.md\n  derived/\n    canvases/\n    views/\n```\n\nLegacy notes:\n- old `entityType: project` roots may still be read, but new roots should use `entityType: work`\n- old singular `run/` folders may still be read, but new execution graphs should use `runs/<run-id>/`\n\n## Canonical split\n\n### Task graph canonical area\n- `task-groups/`\n- `snapshots/`\n- task-graph EoW nodes under each selected task-group version's `eow/`\n\n### Run graph canonical area\n- `runs/<run-id>/`\n- run-graph EoW nodes inside the run graph's `nodes/`\n\n### Non-canonical derived area\n- `derived/`\n- old generated `canvases/` folders when present\n\n## Canonical entity notes\n\nEvery canonical entity note should use YAML frontmatter.\n\nMinimum common fields:\n- `taskOpsVersion`\n- `entityType`\n- `id`\n- `createdAt`\n- `updatedAt?`\n- `status?`\n\n## Entity notes\n\n### Work\n\nPath:\n- `<work>/index.md`\n\nSuggested fields:\n- `taskOpsVersion`\n- `entityType: work`\n- `id`\n- `title`\n- `objective`\n- `activeRootTaskGroupId`\n- `activeSnapshotId?`\n- `createdAt`\n- `status`\n\n### TaskGroup\n\nPath:\n- `task-groups/<task-group-id>/index.md`\n\nSuggested fields:\n- `entityType: taskGroup`\n- `id`\n- `objective`\n- `parentTaskId?`\n- `activeVersionId?`\n- `createdAt`\n\n### TaskGroupVersion\n\nPath:\n- `task-groups/<task-group-id>/versions/<version-id>/index.md`\n\nSuggested fields:\n- `entityType: taskGroupVersion`\n- `id`\n- `taskGroupId`\n- `version`\n- `summary`\n- `supersedesVersionId?`\n- `selected: true|false`\n- `createdAt`\n\n### Task\n\nPath:\n- `task-groups/<task-group-id>/versions/<version-id>/tasks/<task-id>.md`\n\nSuggested fields:\n- `entityType: task`\n- `id`\n- `taskGroupId`\n- `taskGroupVersionId`\n- `title`\n- `objective`\n- `responsibility`\n- `completionCriteria`\n- `order`\n- `runReadiness?`\n- `runReadinessReason?`\n- `understandingLevel?`\n- `unknowns?`\n- `nextLearningGoal?`\n- `decompositionConfidence?`\n- `executionConfidence?`\n- `childTaskGroupId?`\n- `runRefs?`\n- `createdAt`\n\nExample task↔run reference:\n\n```yaml\nrunRefs:\n  - runId: run-alpha-v1\n    runNodeId: run-node-verify\n    role: verification\n```\n\nExample exploratory task metadata:\n\n```yaml\nrunReadiness: needs_exploration\nrunReadinessReason: The task objective is clear, but the API behavior is not understood well enough to decompose.\nunderstandingLevel: partial\nunknowns:\n  - retry semantics\n  - required permission scope\nnextLearningGoal: Run a minimal API trial and write the constraints needed for the next decomposition.\n```\n\n### EoW for task graph\n\nPath:\n- `task-groups/<task-group-id>/versions/<version-id>/eow/<eow-id>.md`\n\nSuggested fields:\n- `entityType: eow`\n- `id`\n- `graphType: task`\n- `attachedToType: task`\n- `attachedToId`\n- `reason`\n- `declaredBy`\n- `declaredAt`\n- `evidenceRefs?`\n- `createdAt`\n- `status: done`\n\nExample:\n\n```yaml\nentityType: eow\nid: eow-task-verify-example\ngraphType: task\nattachedToType: task\nattachedToId: task-verify-example\nreason: no_further_decomposition\ndeclaredBy: ai\ndeclaredAt: 2026-05-08T04:45:00+09:00\nevidenceRefs:\n  - run:run-alpha-v1/node:run-node-verify\nstatus: done\n```\n\n### VersionSnapshot\n\nPath:\n- `snapshots/<snapshot-id>.md`\n\nSuggested fields:\n- `entityType: versionSnapshot`\n- `id`\n- `rootTaskGroupId`\n- `createdAt`\n- `label?`\n\nBody/frontmatter should include a deterministic selected-version map, for example:\n\n```yaml\nselectedVersions:\n  - taskGroupId: tg-root\n    versionId: tgv-root-v1\n  - taskGroupId: tg-design\n    versionId: tgv-design-v3\n```\n\n### Run index\n\nPath:\n- `runs/<run-id>/index.md`\n\nSuggested fields:\n- `entityType: run`\n- `id`\n- `workId`\n- `createdAt`\n- `status`\n\n### RunNode\n\nPath:\n- `runs/<run-id>/nodes/<run-node-id>.md`\n\nSuggested fields:\n- `entityType: runNode`\n- `id`\n- `runId`\n- `type`\n- `title`\n- `status`\n- `sourceTaskId?`\n- `sourceTaskGroupVersionId?`\n- `createdAt`\n\nSuggested `type` values include `execute`, `explore`, `debug`, `review`, `verify`, and `delegate`.\nUse `explore` when the run objective is learning enough to update task readiness or decomposition.\nUse `delegate` when work is intentionally handed to a human, another AI, an agent, or an external system.\n\nDelegation/waiting example:\n\n```yaml\nentityType: runNode\nid: run-node-human-decision\nrunId: run-alpha-v1\ntype: delegate\ntitle: Ask Jimmy to confirm constraints\nstatus: waiting\nsourceTaskId: task-user-constraints\nsourceTaskGroupVersionId: tgv-root-v1\ndelegateeType: human\ndelegateeRef: jimmy\nrequest: Confirm the constraints needed before downstream execution.\nexpectedOutput: A clear decision and any constraints that update the task graph.\nrequestedAt: 2026-05-08T04:45:00+09:00\ntimeoutAt: 2026-05-10T04:45:00+09:00\n```\n\n### EoW for run graph\n\nPath:\n- `runs/<run-id>/nodes/<eow-id>.md`\n\nSuggested fields:\n- `entityType: eow`\n- `id`\n- `runId`\n- `graphType: run`\n- `attachedToType: runNode`\n- `attachedToId`\n- `reason`\n- `declaredBy`\n- `declaredAt`\n- `createdAt`\n- `status: done`\n\nRun EoW nodes should usually be connected by a `runEdge` with `edgeType: closes_with`.\n\n### RunEdge\n\nPath:\n- `runs/<run-id>/edges/<run-edge-id>.md`\n\nSuggested fields:\n- `entityType: runEdge`\n- `id`\n- `runId`\n- `fromRunNodeId`\n- `toRunNodeId`\n- `edgeType`\n- `createdAt`\n\n`fromRunNodeId` and `toRunNodeId` may point to either a `runNode` or an EoW node inside the same run graph.\n\n## Logging files\n\nAppend-oriented logs should be plain markdown:\n- `work-log.md`\n- `decomposition-log.md`\n- `run-log.md`\n\nPurpose:\n- preserve rationale\n- preserve review/audit trail\n- avoid hiding important structural changes behind silent rewrites\n\n## Validation targets\n\nValidator should check at least:\n\n### Work\n- root `index.md` exists\n- new roots use `entityType: work`\n- legacy `entityType: project` is readable\n- active root task group and active snapshot exist\n\n### Task graph\n- required files/folders exist\n- ids match paths\n- task-group-version ownership is coherent\n- sibling task ids are unique within a version\n- optional invariant warnings for coverage / orthogonality / closure quality\n- only one active version per task group unless explicitly marked otherwise\n- active-snapshot terminal task branches have EoW nodes\n\n### Snapshots\n- selected task groups exist\n- selected versions exist\n- selected path is structurally reachable from root\n\n### Run graph\n- independent `runs/<run-id>/` folders are valid\n- run nodes exist\n- run edges reference real run nodes or EoW nodes\n- referenced source task/task-group-version ids exist if present\n- task `runRefs` and run-node `sourceTaskId` agree bidirectionally\n- delegated/waiting nodes include enough request/delegatee metadata\n- done terminal run paths have EoW nodes\n\n## Selection model\n\nImportant rule:\n- version trees may exist broadly\n- snapshots materialize chosen paths\n- the system should not generate or persist all theoretical combinations\n\n## Derived artifacts\n\nExamples:\n- Obsidian canvas exports\n- tree summaries\n- filtered work views\n- visual layouts\n\nAll should live under `derived/` or a clearly non-canonical generated surface and be labeled non-canonical.\n\n## Reference example\n\nSee `../examples/taskops-canonical-minimal-v1/` for the concrete v1-shaped example using:\n- `entityType: work`\n- versioned task groups\n- a selected snapshot\n- explicit EoW nodes\n- independent `runs/<run-id>/` graph storage\n- bidirectional task↔run references\n- a clearly non-canonical derived area\n\n## Migration note\n\nThis format is a reset from the earlier `graph-task` md-first project/step/phase/node hierarchy.\nThat older shape is still useful as source material, but TaskOps v1 should align storage around:\n- work roots\n- versioned task groups\n- explicit snapshots\n- explicit EoW closure nodes\n- independent run graph separation\n\nFile v0.5.4:references/md-first-vnext-spec.md\n\n# graph-task vNext — md-first collaborative protocol\n\n## Purpose\nThis spec resets `graph-task` from a `graph.json`-canonical workflow into a **structured-markdown collaborative task protocol**.\n\nThe goal is not just prettier visualization.\nThe goal is to create a task substrate that can be shared across:\n- OpenClaw / Linux execution agents\n- GitHub as durable sync + history\n- Obsidian as the primary human inspection and editing surface\n- future human ↔ AI and AI ↔ AI collaboration flows\n\n## Why this reset\nThe earlier direction treated:\n- `graph.json` as canonical state\n- Markdown as a projection / inspection layer\n- Obsidian as primarily read-only visualization\n\nThat split is no longer the best fit.\n\nIf Obsidian is a real working surface, and if multiple humans/agents may read and write the same task data, then:\n- duplicated canonical layers create avoidable sync risk\n- JSON is not the best shared collaboration surface\n- git-friendly, append-friendly, human-readable files become more important than a single machine-shaped document\n\n## New canonical rule\n**Canonical state lives in markdown files.**\n\nJSON is demoted to support roles only:\n- schema references\n- validation fixtures\n- parser test vectors\n- optional export/import or snapshot formats\n- internal plugin/runtime derived state if useful\n\nDo not treat JSON as the durable source of truth in vNext.\n\n## Core design goal\nEnable deterministic task handling without requiring a monolithic machine-owned state file.\n\nWhen the markdown tree lives inside a Git-backed vault, treat that repo as the shared canonical workset.\nLocal edits should be synchronized back into the remote workset rather than allowed to drift as a separate local-only truth.\n\nDeterminism should come from:\n- strict folder and file conventions\n- YAML frontmatter contracts\n- explicit append-only / history-preserving rules\n- limited write semantics\n- git-visible diffs\n- protocol-aware tooling and plugin affordances\n\nNot from hiding everything inside one JSON blob.\n\n## Primary worldview\n`graph-task` is no longer best understood as a generic graph visualizer.\n\nIt is better understood as:\n- a **structured task tree protocol** with explicit semantics\n- where graph relationships may still exist,\n- but tree / containment / execution progression are the first-class interaction model\n\nSo:\n- tree is primary\n- graph is secondary\n- deterministic workflow UI matters more than freeform graph rendering\n\n## High-level hierarchy\nThe conceptual model remains:\n- Project\n- Step\n- Phase\n- Node\n\nBut the persistent representation becomes a filesystem protocol.\n\n## Canonical filesystem layout\nA project run is stored as a folder tree.\n\nExample:\n\n```text\n<project-id>/\n  index.md\n  project-log.md\n  steps/\n    <step-id>/\n      index.md\n      step-log.md\n      phases/\n        <phase-id>/\n          index.md\n          phase-log.md\n          nodes/\n            <node-id>.md\n            <node-id-2>.md\n          results/\n            <result-id>.md\n            <result-id-2>.md\n```\n\nOptional future folders:\n\n```text\n<project-id>/\n  inbox/\n  reviews/\n  decisions/\n  attachments/\n  locks/\n```\n\n## Representation rule\n- Project / Step / Phase are represented as **folders with `index.md`**.\n- Node is represented as a **markdown file**.\n- Result history is represented as **append-only result notes** (preferred) or embedded append-only result sections if the simpler model proves sufficient.\n- Log / narrative surfaces live in dedicated `*-log.md` files or append-only dated notes.\n\n## Why folder + index.md\nFolders express containment.\n`index.md` expresses machine-readable metadata + human-readable summary.\n\nThis gives:\n- intuitive filesystem navigation\n- git-friendly diffs\n- deterministic discovery\n- Obsidian-friendly note handling\n- plugin-friendly parsing\n\n## Frontmatter rule\nEvery canonical entity note must begin with YAML frontmatter.\n\n### Required common fields\nEvery entity note must include at least:\n\n```yaml\ngraphTaskVersion: 2\nentityType: project|step|phase|node|result\nid: <entity-id>\nstatus: pending|active|done|blocked|cancelled\n```\n\n### Project `index.md`\nExample:\n\n```md\n---\ngraphTaskVersion: 2\nentityType: project\nid: project-alpha\nstatus: active\ntitle: Project Alpha\ngoal: Verify md-first collaborative workflow\ncreatedAt: 2026-04-24T13:00:00Z\n---\n```\n\nRecommended extra fields:\n- title\n- goal\n- description\n- createdAt\n- updatedAt\n- owners\n- repo\n- tags\n\n### Step `index.md`\n\n```md\n---\ngraphTaskVersion: 2\nentityType: step\nid: step-1\nprojectId: project-alpha\nstepType: implementation\nstatus: active\ncreatedAt: 2026-04-24T13:10:00Z\n---\n```\n\n### Phase `index.md`\n\n```md\n---\ngraphTaskVersion: 2\nentityType: phase\nid: phase-diverge-1\nprojectId: project-alpha\nstepId: step-1\nphaseType: diverge\nstatus: active\nsequence: 1\ncreatedAt: 2026-04-24T13:20:00Z\n---\n```\n\n### Node `<node-id>.md`\n\n```md\n---\ngraphTaskVersion: 2\nentityType: node\nid: node-compare-options\nprojectId: project-alpha\nstepId: step-1\nphaseId: phase-diverge-1\nnodeType: work\nstatus: active\ncreatedAt: 2026-04-24T13:25:00Z\n---\n```\n\n### Result `<result-id>.md`\n\n```md\n---\ngraphTaskVersion: 2\nentityType: result\nid: result-0001\nprojectId: project-alpha\nstepId: step-1\nphaseId: phase-diverge-1\nnodeId: node-compare-options\nstatus: done\nrecordedAt: 2026-04-24T14:00:00Z\nexpected: Compare candidate options honestly\nactual: Chose option B after verifying lower complexity\nartifacts:\n  - references/eval.md\n---\n```\n\n## Body content rule\nFrontmatter is for structured parsing.\nBody markdown is for human-readable context.\n\nRecommended sections:\n- Summary\n- Description\n- Current state\n- Links / related entities\n- Notes\n- Decision / rationale\n- Next questions\n\nThe body may evolve more freely than frontmatter, but frontmatter must remain schema-valid.\n\n## Links rule\nWiki links are for navigation and context, not for canonical discovery.\n\nMeaning:\n- the plugin / parser should discover entities from the folder structure + frontmatter\n- wiki links are helpful but not the only source of truth\n\nThis reduces fragility if links are temporarily missing.\n\nStill, entity notes should include useful links for human navigation.\n\n## Deterministic discovery rule\nCanonical entity discovery must work even if note bodies are minimal.\n\nA parser should be able to reconstruct the task tree from:\n- folder location\n- file name\n- frontmatter\n\nwithout depending on freeform prose.\n\n## Primary semantics\n### Project\nTop-level unit of work.\nContains Steps.\n\n### Step\nMajor work partition inside a Project.\nContains Phases.\n\n### Phase\nExecution mode unit inside a Step.\nCurrent phase types remain:\n- diverge\n- converge\n- verify\n- commit\n\nA Step may repeat:\n- diverge\n- converge\n- verify\n\nA Step should contain at most one commit phase unless a future spec deliberately expands that rule.\n\n### Node\nConcrete work item / observation / check / execution unit inside a Phase.\n\n### Result\nExpected-vs-actual record attached to a Node.\nResults are append-only.\n\n## Append-only bias\nThis protocol is history-preserving by default.\n\nPreferred operations:\n- add a new Step\n- add a new Phase\n- add a new Node\n- append a new Result\n- append a new log entry\n- mark status forward\n\nDiscouraged operations:\n- deleting entities\n- rewriting history to hide prior states\n- mutating older result records\n- repurposing old phases to mean something new\n\nIf understanding changes, prefer adding a new Phase / Node / Result instead of erasing the old one.\n\n## Sync philosophy\nThe system is built assuming git-based sync.\n\nThis means the persistent shape should optimize for:\n- readable diffs\n- small conflict surfaces\n- append-only updates\n- human review of changes\n- explicit history\n\nThis is one reason md-first is preferred over a single canonical JSON file.\n\n## Concurrency philosophy\nIf Obsidian becomes a writable working surface, sync semantics matter.\n\nRead-only consumption is easy.\nWriteable collaboration is the real design problem.\n\nSo vNext must define allowed write patterns early.\n\n## Write-safety rule\nDo **not** assume every actor can safely edit every file at any time.\n\nDefault design principle:\n- many readers\n- constrained writers\n- append-first mutations\n\n## Conflict minimization strategy\n### 1. Split files by entity\nDo not keep the whole project state in one document.\n\n### 2. Prefer append-only notes\nAppending a new result or log entry is safer than rewriting old content.\n\n### 3. Keep high-contention files small\n`index.md` files should hold metadata + concise summary, not giant rolling logs.\n\n### 4. Separate narrative logs from structural metadata\nThis reduces collisions between state updates and commentary.\n\n## Default write model (recommended)\n### Read path\n- humans may browse/edit notes in Obsidian\n- OpenClaw may read/update via repo checkout\n- other agents may read/write through the same protocol\n\n### Safe default write path\n- structural mutations happen through protocol-aware tooling or plugin commands\n- freeform note edits are allowed in designated log / notes sections\n- result creation is append-only\n- status changes update frontmatter only in the owning entity note\n\n## Suggested edit permissions by file type\n### `index.md` files\nHigh importance.\nShould preferably be edited by plugin/tooling rather than casual manual edits.\n\n### `*-log.md` files\nLow-risk narrative surface.\nHumans and AIs may append more freely.\n\n### `results/*.md`\nAppend-only creation is preferred.\nExisting result files should rarely be edited beyond typo fixes.\n\n### `nodes/*.md`\nModerate risk.\nMetadata is structured; body can be richer.\n\n## Locking / ownership options\nvNext should not hard-require one locking scheme yet, but should leave room for it.\n\nCandidate models:\n\n### Option A — social protocol only\nRely on git + human discipline.\nBest for early experimentation.\nWeakest safety.\n\n### Option B — project lease file\nA project has a lightweight lock / lease note showing current active editor.\nGood for reducing accidental simultaneous structural edits.\n\n### Option C — branch-per-actor\nEach actor works on a branch.\nSafer, but heavier operationally.\n\n### Option D — entity-level claims\nSpecific Step or Phase claims rather than project-wide lock.\nMore scalable, but more complex.\n\n## Recommended near-term concurrency rule\nStart simple:\n- no hard lock yet\n- but treat **structural edits as single-writer at a time per project**\n- allow broader multi-reader behavior\n- allow append-only logs/results with more flexibility\n\nThis is honest and much safer than pretending arbitrary concurrent editing is already solved.\n\n## Obsidian role\nObsidian is not just a passive visualizer anymore.\nIt becomes a primary human working surface.\n\nBut it should not become an unrestricted freeform editor for critical structure.\n\n## Plugin role\nThe custom Obsidian plugin should become a **protocol-aware deterministic task client**.\n\nNot just a graph renderer.\n\nIts MVP job is to:\n- parse the md-first task tree\n- render Project / Step / Phase / Node as a structured tree UI\n- show statuses, phase types, result counts, and active blockers clearly\n- open the underlying notes for human inspection\n- provide safe commands for permitted structural operations\n\n## Plugin is preferable because\nOur task model is not a generic Obsidian note graph.\nIt has execution semantics.\n\nWhat matters most is:\n- containment\n- execution mode\n- status\n- result history\n- deterministic task navigation\n\nThat is better served by a dedicated plugin than by trying to force everything into generic graph view behavior.\n\n## Plugin MVP\nMinimum useful plugin behavior:\n- detect graph-task projects in the vault\n- show tree view:\n  - Project\n  - Step list\n  - Phase list\n  - Node list\n- show metadata badges:\n  - status\n  - phase type\n  - result count\n  - blocked / done state\n- open underlying markdown notes on click\n- reload / refresh parsed state\n- optionally create safe new Step / Phase / Node / Result stubs through controlled commands\n\n## Graph visualization in vNext\nGraph visualization is secondary.\n\nPossible later support:\n- local subgraph for one Step\n- phase transition view\n- node dependency mini-map\n\nBut the default interaction should be tree-first, not graph-first.\n\n## Validation approach\nBecause canonical state is markdown, validation should focus on:\n- required files exist\n- folder containment is valid\n- frontmatter schema is valid\n- ids match file locations\n- cross-references are coherent\n- phase rules are respected\n- append-only assumptions are not silently violated\n\n## Canonical parser contract\nA parser should be able to build an internal model from the md tree and detect:\n- Project identity\n- Step list and order\n- Phase list and order\n- Node ownership\n- Result ownership\n- statuses and timestamps\n\nThis derived internal model may be represented as JSON in memory, but that does not make JSON canonical on disk.\n\n## Migration implication\nThe current Phase 1 / Phase 2 implementation can still be useful as a prototype,\nbut vNext likely requires a redesign:\n- from `graph.json` write-first\n- to `index.md` / structured note write-first\n\nSo treat earlier JSON-canonical work as learning, not final architecture.\n\n## Immediate next questions\n1. Exact folder naming rules: ids only, or numeric sequence prefixes too?\n2. Should result history live in separate files by default, or inline until volume proves it painful?\n3. What is the smallest safe plugin mutation set for MVP?\n4. Do we want a lightweight project lease / lock note in MVP, or only document the single-writer rule first?\n5. Which fields are mandatory in frontmatter vs optional in body text?\n\n## Recommended next implementation order\n1. freeze md-first filesystem contract\n2. freeze frontmatter schema by entity type\n3. define validation rules for markdown canonical state\n4. define plugin MVP tree UI + safe mutation commands\n5. build sample md-first example project\n6. build parser + validator\n7. build Obsidian plugin MVP\n8. only later consider richer graph views or multi-actor lock automation\n\nFile v0.5.4:references/obsidian-plugin-mvp-spec.md\n\n# graph-task Obsidian plugin — MVP spec\n\n## Purpose\nThe plugin is the deterministic Obsidian client for the md-first `graph-task` protocol.\n\nIt is **not** primarily a generic graph visualizer.\nIts job is to make the canonical markdown task tree:\n- discoverable\n- inspectable\n- safely editable within constrained rules\n- usable by humans working alongside AI agents\n\n## Product stance\nPrimary interaction model:\n- tree-first\n- protocol-aware\n- read-heavy, write-constrained\n\nSecondary interaction model:\n- local graph/subgraph views later if they prove useful\n\nDo not optimize the MVP around fancy global graph rendering.\nOptimize around reliable task handling.\n\n## Canonical data source\nThe plugin reads canonical markdown files from the vault.\n\nDiscovery depends on:\n- folder structure\n- `index.md` presence for Project / Step / Phase\n- YAML frontmatter\n\nThe plugin may build an internal in-memory JSON model for rendering, but markdown remains canonical on disk.\n\n## Detected project layout\nA graph-task project root looks like:\n\n```text\n<project-id>/\n  index.md\n  project-log.md\n  steps/\n    <step-id>/\n      index.md\n      step-log.md\n      phases/\n        <phase-id>/\n          index.md\n          phase-log.md\n          nodes/\n            <node-id>.md\n          results/\n            <result-id>.md\n```\n\n## MVP user stories\n1. As a human, I can open Obsidian and immediately see all graph-task projects in the vault.\n2. As a human, I can expand a project into Steps, Phases, Nodes, and Results without manually traversing folders.\n3. As a human, I can see status, phase type, and result counts at a glance.\n4. As a human, I can click an item and open the canonical markdown note.\n5. As a human, I can perform a few safe structural operations from the plugin without hand-editing critical frontmatter.\n6. As an AI-assisted operator, I can rely on the plugin to preserve required file structure and frontmatter when creating new entities.\n\n## Core UI surfaces\n### 1. Project explorer view\nA dedicated side panel showing:\n- Project\n  - Step\n    - Phase\n      - Nodes\n      - Results\n\nEach row should show compact badges:\n- status\n- phase type (for phase rows)\n- result count (for node or phase rows)\n- blocked indicator\n- done indicator\n\n### 2. Detail pane / inspector\nWhen an entity is selected, show a structured detail view:\n- identity\n- status\n- ownership fields (`projectId`, `stepId`, `phaseId`, etc.)\n- timestamps\n- summary fields\n- quick links to related canonical notes\n- latest results for a node or phase\n\nThe detail pane should also include an “Open note” action.\n\n### 3. Validation / refresh controls\nThe plugin should provide:\n- Refresh parsed state\n- Re-scan vault for graph-task projects\n- Show validation issues for the selected project\n\n## Safe write semantics for MVP\nThe plugin must not behave like an unrestricted freeform editor for canonical structure.\n\n### Allowed writes in MVP\n- Create Project scaffold\n- Create Step scaffold under a Project\n- Create Phase scaffold under a Step\n- Create Node scaffold under a Phase\n- Create Result note under a Phase for a Node\n- Update status field in frontmatter\n- Append timestamped log entries to `project-log.md`, `step-log.md`, or `phase-log.md`\n\n### Disallowed writes in MVP\n- Delete Project / Step / Phase / Node from UI\n- Rename ids from UI after creation\n- Move entities between parents from UI\n- Rewrite older result files in bulk\n- Auto-merge conflicting concurrent edits\n- Freeform frontmatter mutation without validation\n\n### Rationale\nThese constraints keep the plugin aligned with append-only, history-preserving behavior.\n\n## Concurrency assumptions in MVP\nConcurrency is not fully solved yet.\n\nThe MVP should assume:\n- many readers\n- effectively one structural writer per project at a time\n- append-friendly logs/results may be less risky than structural edits\n\nThe plugin should surface this honestly.\n\n### Optional MVP warning\nIf a future lightweight project lease file exists, show it.\nIf not, at minimum show a warning banner like:\n- “Structural edits are safest with one active editor per project.”\n\n## Validation rules the plugin should enforce\nOn load or refresh, detect and surface:\n- missing `index.md`\n- missing required frontmatter fields\n- invalid `entityType`\n- mismatched ids vs folder/file names\n- Step outside a Project\n- Phase outside a Step\n- Node outside a Phase\n- Result missing a valid `nodeId`\n- duplicate sibling ids\n- multiple commit phases inside one Step\n\nValidation errors should not silently rewrite files.\nThey should be shown to the user.\n\n## Suggested row labels\n### Project row\n- title or id\n- status badge\n- Step count\n\n### Step row\n- id\n- step type\n- status badge\n- Phase count\n\n### Phase row\n- id\n- phase type badge\n- status badge\n- Node count\n- Result count\n\n### Node row\n- title or id\n- status badge\n- latest result badge if any\n\n### Result row\n- result id\n- status badge\n- recordedAt\n\n## Minimal commands\n- `graph-task: Refresh projects`\n- `graph-task: Open project explorer`\n- `graph-task: Create project`\n- `graph-task: Create step`\n- `graph-task: Create phase`\n- `graph-task: Create node`\n- `graph-task: Record result`\n- `graph-task: Set status`\n- `graph-task: Append project log`\n- `graph-task: Append step log`\n- `graph-task: Append phase log`\n\n## File-writing behavior\nWhen the plugin creates a new entity, it should:\n1. create the correct folder or file path\n2. write required YAML frontmatter\n3. write a small canonical body template\n4. refresh the project explorer\n\nThe plugin should prefer creating small, deterministic templates instead of rich prose.\n\n## Body templates\n### Project template\nSections:\n- Summary\n- Goal\n- Steps\n- Notes\n\n### Step template\nSections:\n- Summary\n- Description\n- Current Phases\n- Notes\n\n### Phase template\nSections:\n- Summary\n- Description\n- Nodes\n- Notes\n\n### Node template\nSections:\n- Summary\n- Description\n- Work Notes\n- Related Results\n\n### Result template\nSections:\n- Expected\n- Actual\n- Notes\n- Artifacts\n\n## Out of scope for MVP\n- rich graph canvas\n- drag-and-drop reparenting\n- real-time collaboration protocol\n- automatic conflict resolution\n- AI orchestration inside the plugin\n- advanced diff/review surfaces\n- semantic merge engine\n- schema migration tooling beyond simple warnings\n\n## Recommended implementation order\n1. parser for md-first project structure\n2. validation layer\n3. project explorer tree UI\n4. note opening / detail pane\n5. safe scaffold creation commands\n6. status update commands\n7. log append commands\n8. result creation command\n\n## Success criteria\nThe MVP is successful if:\n- a human can browse a project tree faster than by raw file navigation\n- the plugin creates valid canonical file structures for the safe commands\n- structural edits stay constrained and predictable\n- the plugin makes the md-first protocol easier to use without hiding how the files actually work\n\nArchive v0.5.3: 62 files, 88168 bytes\n\nFiles: examples/md-first-minimal/project-alpha/index.md (621b), examples/md-first-minimal/project-alpha/project-log.md (251b), examples/md-first-minimal/project-alpha/steps/step-1/index.md (444b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/index.md (566b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/nodes/node-compare-layout.md (655b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/phase-log.md (150b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/results/result-0001.md (864b), examples/md-first-minimal/project-alpha/steps/step-1/step-log.md (109b), examples/md-first-minimal/project-alpha/summary.md (270b), examples/md-first-minimal/README.md (403b), examples/minimal-project/graph.json (3183b), examples/minimal-project/summary.md (1176b), examples/self-dogfood-obsidian-vault/index.md (250b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-commit-findings-1__node-choose-next-improvement.md (940b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-commit-findings-1__phase-commit-findings-1-root.md (603b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-converge-findings-1__node-summarize-findings.md (1042b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-converge-findings-1__phase-converge-findings-1-root.md (615b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-commit-execution-1__node-lock-execution-findings.md (982b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-commit-execution-1__phase-commit-execution-1-root.md (621b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-execution-2__node-build-self-dogfood-example.md (1113b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-execution-2__phase-diverge-execution-2-root.md (627b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__node-read-cli-surface.md (940b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__node-read-phase1-spec.md (976b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__phase-diverge-surface-1-root.md (615b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-execution-2__node-validate-self-dogfood.md (960b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-execution-2__phase-verify-execution-2-root.md (621b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-surface-1__node-verify-phase1-usable.md (1046b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-surface-1__phase-verify-surface-1-root.md (609b), examples/self-dogfood-obsidian-vault/phases/step-followups__phase-commit-findings-1.md (1190b), examples/self-dogfood-obsidian-vault/phases/step-followups__phase-converge-findings-1.md (1177b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-commit-execution-1.md (1197b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-diverge-execution-2.md (1220b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-diverge-surface-1.md (1507b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-verify-execution-2.md (1191b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-verify-surface-1.md (1177b), examples/self-dogfood-obsidian-vault/projects/dogfood-phase1-project.md (654b), examples/self-dogfood-obsidian-vault/steps/step-followups.md (743b), examples/self-dogfood-obsidian-vault/steps/step-self-dogfood.md (1568b), examples/self-dogfood-project/graph.json (17884b), examples/self-dogfood-project/summary.md (6489b), README.md (2500b), references/cli.graph-task.md (5797b), references/core-model.md (8835b), references/decomposition-protocol.md (3247b), references/examples.expected-results.json (2590b), references/expected-result.schema.json (1450b), references/md-first-format.md (8709b), references/md-first-vnext-spec.md (13964b), references/obsidian-plugin-mvp-spec.md (6869b), references/phase1-graph-task-spec.md (4454b), references/phase2-obsidian-spec.md (2524b), references/phases.json (4196b), references/result-record.schema.json (790b), references/rules.graph-task.md (6274b), references/run-readiness.md (8930b), references/schema.graph-task.json (5881b), references/test-levels.json (1264b), scripts/graph_task.py (63616b), skill-card.md (2550b), SKILL.md (15831b), tests/test_graph_task_cli.py (18944b), _meta.json (126b)\n\nFile v0.5.3:SKILL.md\n\n---\nname: taskops\ndescription: \"Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution logs, exploration, delegation/waiting, EoW closure, validation, summaries, and runner-driven progress.\"\n---\n\n# TaskOps\n\nTaskOps is a **work-truth protocol**, not just a task manager. It exists so that AI agents can be trusted with hours/days/weeks of work without pretending tasks are done, silently stopping, asking \"what next?\", or executing a wrong plan. Plans lie, logs drift, and TODO lists make agent work look simpler than it is; TaskOps separates task decomposition from execution reality and forces explicit, file-backed closure.\n\nUse it when the user needs to know what should happen, what actually happened, what is blocked or delegated, and whether work is truly closed.\n\n## Canonical rule\n\nTaskOps v1 is **md-first**.\n\nCanonical state lives in markdown files arranged around:\n- `task-groups/`\n- `snapshots/`\n- `runs/<run-id>/`\n- non-canonical `derived/`\n\nDo **not** treat `.taskops/queue.sqlite`, `graph.json`, or generated canvases as durable semantic truth. SQLite is an execution projection/ledger, not the task graph source of truth.\n\n## Read these first\n\n- `references/core-model.md`\n- `references/md-first-format.md`\n- `references/decomposition-protocol.md`\n- `references/run-readiness.md`\n- `../examples/taskops-canonical-minimal-v1/`\n\n## Current operating model\n\n- Task graph = decomposition truth\n- Run graph = execution truth\n- Work = top-level objective container (`entityType: work`; legacy `project` can still be read)\n- Task groups are versioned\n- Snapshots materialize selected version paths\n- EoW (End of Work) is an explicit terminal node, not just a status field\n- Run graphs are independent under `runs/<run-id>/` and may reference external runs/tasks without being merged\n- Task↔run traceability is bidirectional: task `runRefs` plus run-node `sourceTaskId` / `sourceTaskGroupVersionId`\n- Delegation/waiting belongs in the run graph as `type: delegate` / `status: waiting` with delegatee, request, expected output, and optional timeout metadata\n- Markdown is canonical; canvas/views are derived\n- SQLite queue state is a rebuildable execution projection plus lease/report ledger\n- Shared status vocabulary: `pending | active | done | blocked | waiting | cancelled`\n- Before execution, classify task run readiness as `runnable | needs_decomposition | needs_exploration | blocked`\n- Use `needs_exploration` when the objective is meaningful but the system does not yet know enough to decompose honestly; exploratory runs may search, try, debug, prototype, and reflect to learn constraints for the next graph update\n\n## Decomposition discipline\n\n- Start with a one-line objective.\n- Decompose depth 1 by default.\n- Do not turn decomposition into an activity checklist.\n- A task can be large but not decomposable yet; if the missing knowledge blocks honest decomposition, create an exploratory run and feed the result back into the task graph.\n- A terminal selected branch is not closed until an EoW node is attached.\n- Do not continue past a delegated/waiting run node until it resolves, is cancelled, or times out into an explicit follow-up.\n\n## Preferred CLI\n\nUse the npm CLI first:\n\n```bash\ntaskops validate <path>\ntaskops summary <path>\ntaskops show <path> --json\ntaskops classify-runnable <work-dir> <task-id> --json\ntaskops next <work-dir> --json\ntaskops explain <work-dir> --json\ntaskops close <work-dir> <run-node-id|task-id> [--reason <reason>] [--json]\ntaskops init <dir> --id <id> --title <title> --objective <objective>\ntaskops vault-init <vault-dir> --repo-url <url> --branch <branch> --auto-sync true\ntaskops git-status <vault-dir>\ntaskops git-sync <vault-dir> --message <message>\ntaskops watch-sync <vault-dir> --debounce-ms 5000\ntaskops decompose <work-dir> --task-group-id <id> --spec <spec.json>\ntaskops refactor <work-dir> --task-group-id <id> --spec <spec.json> --supersedes <version-id>\ntaskops run <work-dir> [--run-id <id>] [--agent <agent-id>] [--executor dry-run|openclaw-agent] [--max-steps <n>] [--until <iso-timestamp>] [--timeout <seconds>] [--loopback none|self] [--max-loopbacks <n>] [--json]\ntaskops queue sync <work-dir> [--json]\ntaskops queue list <work-dir> [--json]\ntaskops queue claim <work-dir> [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--json]\ntaskops queue heartbeat <work-dir> <lease-id> [--ttl-seconds <n>] [--json]\ntaskops queue release <work-dir> <lease-id> [--status done|failed|cancelled] [--json]\ntaskops queue reports <work-dir> [--json]\ntaskops runner once <work-dir> [--runtime dry-run|openclaw-cli] [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--timeout <seconds>] [--report-sink none|ledger|openclaw-chat-inject] [--master-session-key <key>] [--json]\ntaskops runner watch <work-dir> [--runtime dry-run|openclaw-cli] [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--timeout <seconds>] [--report-sink none|ledger|openclaw-chat-inject] [--master-session-key <key>] [--poll-interval-ms <n>] [--max-waves <n>] [--max-idle-cycles <n>] [--idle-exit-after-seconds <n>] [--until <iso-timestamp>] [--continue-on-failure] [--json]\ntaskops restart <work-dir> --from <task-id> [--instruction <text>] [--instruction-file <path>] [--reason <text>] [--json]\n```\n\n## Honest-loop commands\n\nThese three commands are the small surface area that keeps long-running agents honest. They never silently mutate progress:\n\n- `taskops next <work-dir> --json` — returns the one next honest action: `execute`, `decompose`, `explore`, `wait`, `delegation_pending`, `blocked`, `done`, or `no_runnable`. Use it instead of guessing what to do next.\n- `taskops explain <work-dir> --json` — explains why work is or is not closed: closure summary, next honest action, and concrete open reasons (missing EoW, blockers, waiting delegations, runnable/decompose/explore tasks, validation errors).\n- `taskops close <work-dir> <run-node-id|task-id> [--reason <reason>] [--json]` — make EoW closure explicit and guarded. It refuses to close a task that already has an EoW, has open child branches, or is not yet `done` unless `--reason manual_verified` is supplied. It refuses to close a run node unless its status is `done`/`cancelled` or an explicit reason (`failure`, `superseded`, `cancelled`, `manual_verified`) is supplied. Use this rather than editing EoW files by hand.\n\n## Running TaskOps work\n\n`taskops run <work-dir>` is the canonical way to advance a TaskOps work graph. The skill is passive guidance; the runner is the layer that actually mutates state.\n\n- Use `taskops run <work-dir>` instead of editing run nodes / EoW / runRefs / child task groups by hand. The runner deterministically picks the next task (active snapshot order, then `task.order`, then `id`), classifies it, and dispatches the matching action.\n- The runner handles three task readiness states each as one bounded step:\n  - `runnable` — creates the run node, executes via the executor, marks the task done, writes the task and run EoW nodes, and creates the `closes_with` edge.\n  - `needs_decomposition` — creates a `type: decomposition` run node, expands the task graph with a child task group and a v1 version (dry-run synthesizes a deterministic placeholder; `openclaw-agent` delegates authoring to the agent and verifies the result), sets the parent task's `childTaskGroupId`, closes the parent task with EoW reason `decomposed_by_runner`, and extends the active snapshot's `selectedVersions` so the new child task group/version becomes visible to later steps of the same runner invocation.\n  - `needs_exploration` — creates a `type: exploration` run node, writes a reflection artifact at `runs/<run-id>/artifacts/<run-node-id>.md`, then marks the parent done with EoW reason `exploration_recorded_by_runner` and sets its `runReadiness` to `needs_decomposition` so the next pass can author informed children.\n- `blocked` tasks are excluded from execution. If only blocked tasks remain the runner stops with `blocked_only`.\n- Before each selection pass, the runner rechecks blocked tasks with `blockedBy` references. If every referenced task/run node blocker is `done` or `cancelled`, it reopens the task (`status: pending`) and clears `runReadiness: blocked` unless `unblockRunReadiness` is set. Use `taskops unblock-check <work-dir> --dry-run --json` to inspect this without mutation.\n- `status: waiting` tasks and non-delegate run nodes, and `type: delegate` run nodes that are not yet `done`/`cancelled`, pause the runner with stop reason `waiting` or `delegation_pending`. Delegate type wins over generic waiting, so `type: delegate` + `status: waiting` reports `delegation_pending`. Surface the pause to the user; do not auto-skip.\n- Prefer `--executor openclaw-agent --agent <agent-id>` for real execution, decomposition, and exploration. Default `--agent` is `main`. Only use `--executor dry-run` for smoke tests, reviews, or to demonstrate the graph mutations without touching an external agent — it produces synthetic success and never performs real work. The synthetic decomposition placeholders are explicitly `runReadiness: blocked` so they cannot be mistaken for real progress.\n- `--max-steps <n>` bounds the total number of actions (execute + decompose + explore). `--until <iso-timestamp>` bounds wall-clock work. Both are optional and **combine with OR semantics**: stop before a new step if either limit is reached.\n- If neither `--max-steps` nor `--until` is supplied, the runner defaults to `--max-steps 1` — exactly one step, then stop.\n- When the user says something like \"before tomorrow 9am\" or \"by EOD\", convert the requested deadline to an explicit ISO-8601 timestamp **with timezone** before passing it as `--until`. Do not pass natural-language deadlines.\n- Stop reasons reported back: `all_closed`, `no_runnable`, `blocked_only`, `waiting`, `delegation_pending`, `max_steps`, `deadline_reached`, `max_loopbacks`, `task_failed`, `validation_failed`. `all_closed` means the selected work is fully closed by task + run EoW with no waiting/delegated/blocked work; `no_runnable` means nothing actionable but the work is not yet closed. Always surface the reason to the user.\n- The runner appends to `runs/<run-id>/events.jsonl` and `runs/<run-id>/run-log.md`, and holds a `.taskops-runner.lock` directory inside the work root while running. Do not launch a second runner against the same work until the lock is gone.\n- Do **not** instruct the executing agent to call `taskops run` again — it runs one task. Recursion is the orchestrator's job, not the worker's.\n- `--loopback none` (default) keeps the cautious behaviour: every pending `type: delegate` stops the runner. Pass `--loopback self` to let the runner auto-resolve *self-delegates* (`delegateeType: self`, `delegateeRef: self`, or `delegateeRef: <work-id>`) by opening a `type: loopback` resolution node, executing the loopback once, writing a `loopback` edge, and closing both the loopback and the original delegate (`reason: self_loopback_resolved`, `resolvedBy: self_loopback`). Non-self delegates are still surfaced as `delegation_pending`. Each loopback counts against `--max-steps` and a separate `--max-loopbacks` budget (default `3`); exceeding it stops with `max_loopbacks` and leaves the delegate open. The executing agent inside a loopback must still not call `taskops run` recursively — orchestration stays at the runner.\n- `taskops restart <work-dir> --from <task-id> --instruction \"<text>\" [--reason <text>] [--instruction-file <path>] [--json]` rolls the active version of the containing task group forward to a new version, marks the prior version `selected: false` and `supersededByVersionId`, points the active snapshot at the new version, and updates the task group's `activeVersionId`. Upstream tasks (`order < target.order`) keep their status and gain `preservedUpstream: true` with a fresh `preserved_upstream_after_restart` EoW when they were done leaves. The target task is reset to `pending` with `restartInstruction`, optional `restartReason`, `restartedFromVersionId`, and `restartedAt`. Downstream tasks (`order >= target.order`, excluding the target) are reset to `pending`. Historical runs/run nodes/EoWs are not modified — they remain as evidence. Use this instead of editing tasks by hand when an upstream change invalidates a task and its downstream.\n\n## Queue projection and watch runner\n\n`taskops queue sync <work-dir>` creates or refreshes `.taskops/queue.sqlite` from the canonical markdown state. The database is rebuildable projection state for queue items, leases, attempts, and progress reports. Deleting it and syncing again must not destroy semantic truth.\n\n`taskops runner once <work-dir>` claims one executable queue item, runs exactly that claimed task through a runtime adapter, releases the lease, refreshes the queue projection, and optionally writes a progress report ledger row.\n\n`taskops runner watch <work-dir>` is the local always-on primitive. It loops over `runner once`, waits when no queue item is currently claimable, and exits with `all_closed` when TaskOps closure says the work is complete. Bounds such as `--max-waves`, `--max-idle-cycles`, `--idle-exit-after-seconds`, and `--until` are for tests, controlled sessions, and supervised deployments. Watch mode defaults to `--max-attempts 3`; pass `--max-attempts 0` only when an external supervisor owns retry safety.\n\nImportant boundary:\n\n- SQLite does not call OpenClaw and does not execute triggers by itself.\n- The watch runner is the process that stays alive and invokes the runtime adapter.\n- `--runtime openclaw-cli` maps to same-host `openclaw agent --json`.\n- Use `--timeout <seconds>` with `--runtime openclaw-cli` for unattended waves. Internal timeout finalizes the attempt as failed and releases the lease; external shell `timeout` should be a supervisor last resort, not the normal control path.\n- If a runner process is externally killed after claiming a lease, the next queue sync/list/claim operation marks the expired lease stale, finalizes any linked running attempt as failed, and lets the fingerprint retry cap decide whether to reclaim it.\n- `--max-attempts <n>` skips queue items whose current markdown fingerprint already has `n` failed runner attempts. Editing the task markdown changes the fingerprint and resets the retry budget.\n- Watch mode stops on the first failed wave by default to avoid retry loops. Use `--continue-on-failure` only with `--max-attempts` or a separate retry/attempt guard.\n- `--report-sink ledger` records progress in `.taskops/queue.sqlite`.\n- `--report-sink openclaw-chat-inject` delivers progress to `--master-session-key` with `openclaw gateway call chat.inject` and records delivery success/failure in the same SQLite report ledger.\n- Future dashboard/webhook sinks should not change TaskOps graph truth.\n\n## Git-backed vault rule\n\nIf the user is working in an Obsidian vault that should stay aligned with a GitHub repo, prefer:\n\n1. `taskops vault-init ... --repo-url ... --auto-sync true`\n2. keep `.taskops/taskops-sync.json` in the vault root\n3. use the desktop Obsidian plugin or `taskops watch-sync`/`taskops git-sync` so local vault edits are pushed back to GitHub instead of drifting\n\n## Legacy note\n\n`python3 scripts/graph_task.py ...` still exists as a migration aid for the earlier graph-task prototype.\nOnly use it when the task is explicitly about legacy behavior or migration.\n\n## Minimum validation before claiming success\n\nRun:\n\n```bash\ntaskops validate <work-dir>\ntaskops summary <work-dir>\n```\n\nIf you changed the skill itself, also run:\n\n```bash\npython3 /home/jimmy/.npm-global/lib/node_modules/openclaw/skills/skill-creator/scripts/package_skill.py <skill-dir> <output-dir>\n```\n\nFile v0.5.3:examples/md-first-minimal/README.md\n\n# md-first minimal example\n\nThis example demonstrates the proposed vNext canonical layout where markdown files are the source of truth.\n\nIt intentionally stays tiny:\n- 1 Project\n- 1 Step\n- 1 Phase\n- 1 Node\n- 1 Result\n- log files at each structural level\n\nUse it to pressure-test:\n- folder naming rules\n- YAML frontmatter shape\n- append-only result handling\n- Obsidian navigation\n- future plugin parsing\n\nFile v0.5.3:README.md\n\n# TaskOps skill\n\n**AI agent work cannot be managed as a flat TODO list.**\n\nTaskOps is a markdown-canonical execution control protocol for keeping human + AI work honest: separate the decomposition truth from execution reality, record blockers and delegation explicitly, and only close work when there is visible evidence.\n\n## Canonical shape\n\nTaskOps v1 separates:\n- **work root** at `index.md` with `entityType: work`\n- **task graph** under `task-groups/`\n- **snapshot selection** under `snapshots/`\n- **execution truth** under independent `runs/<run-id>/` graphs\n- **EoW terminal nodes** under task-version `eow/` folders and run `nodes/`\n- **derived views** under `derived/`\n\nMarkdown is canonical.\nDerived canvas/views are not.\n\n## Current surfaces\n\n- `../cli/` — installable `taskops` CLI for `init / validate / summary / show / decompose / refactor / run` plus git-backed vault setup/sync\n- `../obsidian-plugin/` — Obsidian explorer + derived canvas export for TaskOps v1 projects, with desktop git auto-sync support when configured\n- `scripts/graph_task.py` — legacy graph-task prototype kept only as migration/source material\n\n## Main working references\n\n- `../docs/CORE_MODEL.md`\n- `../docs/MD_FIRST_FORMAT.md`\n- `../examples/taskops-canonical-minimal-v1/`\n- `SKILL.md`\n\n## Core operating loop\n\n```bash\ntaskops init <work-dir> --id <id> --title <title> --objective <objective>\ntaskops validate <work-dir>\ntaskops summary <work-dir>\ntaskops classify-runnable <work-dir> <task-id> --json\ntaskops run <work-dir> --executor dry-run --max-steps 1 --json\n```\n\nUse `dry-run` for smoke tests and graph rehearsals. Use `--executor openclaw-agent --agent <agent-id>` when the user wants real agent execution.\n\n## Good fit\n\nTaskOps is strongest for complex agentic work such as refactors, migrations, research-to-implementation loops, and multi-step investigations where the user needs to know:\n\n- what the goal is\n- how it was decomposed\n- what actually ran\n- what got blocked, delegated, or explored\n- why a branch is truly closed\n\n## Validation stance\n\nPrefer the CLI for current validation and summaries:\n\n```bash\ntaskops validate <work-dir>\ntaskops summary <work-dir>\n```\n\nFor a git-backed Obsidian vault workflow:\n\n```bash\ntaskops vault-init <vault-dir> --repo-url <github-repo-url> --branch main --auto-sync true\ntaskops git-sync <vault-dir> --message \"Sync vault changes\"\n```\n\nOnly use the legacy Python script when the work is explicitly about old graph-task compatibility or migration.\n\nFile v0.5.3:_meta.json\n\n{\n  \"ownerId\": \"kn73mypx9fx9qehs8agyh3drs183bb1y\",\n  \"slug\": \"taskops\",\n  \"version\": \"0.5.3\",\n  \"publishedAt\": 1781608063678\n}\n\nFile v0.5.3:references/cli.graph-task.md\n\n# graph-task CLI surface\n\n> Legacy prototype note: this CLI currently operates on `graph.json` runs.\n> In the md-first direction, treat its outputs as legacy behavior, migration help, or derived snapshots/exports — not canonical markdown state.\n\nUse the bundled CLI with:\n\n```bash\npython3 scripts/graph_task.py <command> ...\n```\n\nAll commands accept either:\n- a run directory (the CLI will use `graph.json` inside it), or\n- a direct path to `graph.json`\n\n## Shared status vocabulary\n\nUse the same minimal status set everywhere:\n- `pending`\n- `active`\n- `done`\n- `blocked`\n- `cancelled`\n\n## Commands\n\n### init\nCreate a new run directory with `graph.json` and `summary.md`.\n\n```bash\npython3 scripts/graph_task.py init ./runs/demo \\\n  --id demo-project \\\n  --title \"Demo project\" \\\n  --description \"Test graph\" \\\n  --goal \"Reach a validated state\"\n```\n\nTo initialize inside a git-backed vault/work repo, point `path` at the desired local checkout directory and pass a repo URL. The CLI will clone or refresh the checkout, then create the run under `<checkout>/<project-id-slug>/`.\n\n```bash\npython3 scripts/graph_task.py init ./tmp/company-vault \\\n  --repo-url https://github.company.com/ORG/obsidian-vault.git \\\n  --repo-branch main \\\n  --id graph-task-demo \\\n  --title \"Graph task demo\" \\\n  --description \"Repo-backed run\" \\\n  --goal \"Write into a project-specific folder\"\n```\n\n### show\nRender the current graph as a summary or raw JSON.\n\n```bash\npython3 scripts/graph_task.py show ./runs/demo\npython3 scripts/graph_task.py show ./runs/demo --format json\n```\n\n### add-step\nAdd a Project-level Step.\n\n```bash\npython3 scripts/graph_task.py add-step ./runs/demo \\\n  --id step-1 \\\n  --step-type implementation \\\n  --description \"Implement state handling\"\n```\n\n### add-step-edge\nConnect two Steps.\n\n```bash\npython3 scripts/graph_task.py add-step-edge ./runs/demo \\\n  --id step-edge-1 \\\n  --from-step step-1 \\\n  --to-step step-2\n```\n\n### add-phase\nAdd a Step-level Phase and automatically create its root node.\n\n```bash\npython3 scripts/graph_task.py add-phase ./runs/demo \\\n  --step-id step-1 \\\n  --id phase-diverge-1 \\\n  --phase-type diverge \\\n  --description \"Explore implementation options\"\n```\n\n### add-phase-edge\nConnect two Phases inside a Step.\n\n```bash\npython3 scripts/graph_task.py add-phase-edge ./runs/demo \\\n  --step-id step-1 \\\n  --id phase-edge-1 \\\n  --from-phase phase-diverge-1 \\\n  --to-phase phase-verify-1\n```\n\n### add-node\nAdd a work node to a Phase.\n\n```bash\npython3 scripts/graph_task.py add-node ./runs/demo \\\n  --phase-id phase-diverge-1 \\\n  --id node-1 \\\n  --title \"Compare libraries\" \\\n  --description \"Check Zustand and Redux\"\n```\n\n### add-edge\nConnect two Nodes inside a Phase.\n\n```bash\npython3 scripts/graph_task.py add-edge ./runs/demo \\\n  --phase-id phase-diverge-1 \\\n  --id edge-1 \\\n  --from-node phase-diverge-1-root \\\n  --to-node node-1 \\\n  --edge-type flow\n```\n\n### set-status\nSet the status on a Project, Step, Phase, or Node.\n\n```bash\npython3 scripts/graph_task.py set-status ./runs/demo \\\n  --entity-type node \\\n  --entity-id node-1 \\\n  --status active\n```\n\n### write-result\nAppend an expected-vs-actual record to a work node.\n\n```bash\npython3 scripts/graph_task.py write-result ./runs/demo \\\n  --node-id node-1 \\\n  --expected \"Choose a candidate state library\" \\\n  --actual \"Selected Zustand after comparing complexity\" \\\n  --status done \\\n  --notes \"Simple enough for current scope\"\n```\n\n### validate\nValidate the graph against the current high-level rules.\n\n```bash\npython3 scripts/graph_task.py validate ./runs/demo\n```\n\n### summary\nRegenerate and print `summary.md`.\n\n```bash\npython3 scripts/graph_task.py summary ./runs/demo\n```\n\n### export-obsidian\nExport the current legacy JSON run into an Obsidian-friendly markdown projection.\n\nThis export is **non-canonical**. It is a derived view from `graph.json`, not the md-first source of truth.\n\n```bash\npython3 scripts/graph_task.py export-obsidian ./runs/demo ./tmp/demo-vault\npython3 scripts/graph_task.py export-obsidian ./runs/demo ./tmp/demo-vault --force\n```\n\n### git-status\nShow git sync state for a repo-backed run.\n\n```bash\npython3 scripts/graph_task.py git-status ./tmp/company-vault/graph-task-demo\n```\n\n### git-pull\nFast-forward pull the backing repo for a repo-backed run. This fails if the repo has uncommitted changes.\n\n```bash\npython3 scripts/graph_task.py git-pull ./tmp/company-vault/graph-task-demo\n```\n\n### git-push\nPush the backing repo. If `--message` is provided, stage and commit all pending repo changes first.\n\n```bash\npython3 scripts/graph_task.py git-push ./tmp/company-vault/graph-task-demo \\\n  --message \"Update graph-task project\"\n```\n\n### git-sync\nPull first, then optionally commit all pending changes, then push. This is the main manual sync command for repo-backed runs.\n\n```bash\npython3 scripts/graph_task.py git-sync ./tmp/company-vault/graph-task-demo \\\n  --message \"Sync graph-task project updates\"\n```\n\n## Repo-backed run notes\n\n- `--repo-url` on `init` records repo metadata into `project.repo`.\n- Repo sync commands only work for runs initialized that way.\n- The sync commands operate on the whole backing repo, not only one project folder.\n- `git-pull` / `git-sync` intentionally use `pull --ff-only` to avoid hidden merge commits.\n- If the repo is dirty, pull fails on purpose; resolve or commit local changes first.\n\n## Current simplifications\n\nFor md-first work, prefer editing/validating canonical markdown directly rather than extending this JSON-first CLI unless the task is explicitly about legacy compatibility.\n\n\nThe current CLI intentionally does **not** have:\n- a separate mutation engine\n- hidden transition logic\n- branch/retry/replan commands\n\nIf the structure changes, append new Steps / Phases / Nodes / Edges directly and preserve history in the graph.\n\nFile v0.5.3:references/core-model.md\n\n# TaskOps core model\n\nThis document freezes the shared conceptual contract for TaskOps.\n\n## 1. Layer split\n\nTaskOps has one top-level container and two connected graph layers.\n\n### 1.1 Work\n\nPurpose:\n- hold one objective and its selected decomposition/execution state\n- answer whether the work is still open, waiting, or complete\n\nA `work` replaces the old conceptual `project` wording. Legacy `entityType: project` may still be read for compatibility, but new canonical work should use `entityType: work`.\n\n### 1.2 Task graph\n\nPurpose:\n- represent decomposition truth\n- enforce structural quality\n- preserve version history of decomposition changes\n- make branch closure explicit with EoW nodes\n\n### 1.3 Run graph\n\nPurpose:\n- represent execution truth\n- capture real dependency, overlap, reuse, branching, delegation, and waiting\n- connect work across levels when reality does not stay tree-shaped\n\nEvery run graph is an independent graph under `runs/<run-id>/`. A run graph may reference external tasks or external run nodes, but it should not be merged into another run graph just because it depends on it.\n\n## 2. Main entities\n\n### 2.1 Work\n\nFields:\n- `id`\n- `title`\n- `objective`\n- `activeRootTaskGroupId`\n- `activeSnapshotId?`\n- `createdAt`\n- `status`\n\n### 2.2 TaskGroup\n\nA versioned decomposition unit.\n\nFields:\n- `id`\n- `objective`\n- `parentTaskId?`\n- `activeVersionId?`\n- `createdAt`\n- `status?`\n\n### 2.3 TaskGroupVersion\n\nA concrete decomposition of one task group.\n\nFields:\n- `id`\n- `taskGroupId`\n- `version`\n- `summary`\n- `createdAt`\n- `supersedesVersionId?`\n- `isSelected`\n\nContains:\n- ordered child tasks\n- EoW nodes attached to terminal child tasks\n- decomposition rationale\n- validation metadata\n\n### 2.4 Task\n\nA child responsibility unit in one specific task-group version.\n\nFields:\n- `id`\n- `taskGroupVersionId`\n- `title`\n- `objective`\n- `responsibility`\n- `completionCriteria`\n- `order`\n- `runReadiness?` (`runnable | needs_decomposition | needs_exploration | blocked`)\n- `runReadinessReason?`\n- `understandingLevel?` (`known | partial | unknown`)\n- `unknowns?`\n- `nextLearningGoal?`\n- `decompositionConfidence?`\n- `executionConfidence?`\n- `childTaskGroupId?`\n- `runRefs?` (`[{ runId, runNodeId, role? }]`)\n\nA task may point to a child task group if it is further decomposed.\nIf TaskOps does not understand the domain well enough to split a task, the task should be marked `needs_exploration` rather than forcing a fake decomposition.\n\n`runRefs` is the task-side half of bidirectional task↔run traceability. A matching run node should point back with `sourceTaskId` and, when known, `sourceTaskGroupVersionId`.\n\n### 2.5 EoW\n\nEoW means **End of Work** for one graph branch.\nIt is a first-class node, not just a field, because graph visualization should make terminal branches obvious.\n\nFields:\n- `id`\n- `graphType` (`task | run`)\n- `attachedToType` (`task | runNode`)\n- `attachedToId`\n- `reason`\n- `declaredBy` (`human | ai | system | agent`)\n- `declaredAt`\n- `evidenceRefs?`\n- `createdAt`\n- `status`\n\nRules:\n- A task branch is not structurally closed until a terminal task has an attached task-graph EoW node.\n- A run path is not execution-closed until its terminal run node has an attached run-graph EoW node.\n- EoW does not mean the whole work is complete by itself; it closes one branch/path.\n\n### 2.6 VersionSnapshot\n\nA selected version path across connected task groups.\n\nFields:\n- `id`\n- `rootTaskGroupId`\n- `selectedVersionMap`\n- `createdAt`\n- `label?`\n\nImportant:\n- a snapshot records a chosen path\n- it is not the materialization of all combinatorial version states\n\n### 2.7 Run\n\nAn independent execution graph.\n\nFields:\n- `id`\n- `workId`\n- `createdAt`\n- `status`\n\n### 2.8 RunNode\n\nA unit of execution reality.\n\nFields:\n- `id`\n- `runId`\n- `type`\n- `title`\n- `objective?`\n- `status`\n- `sourceTaskId?`\n- `sourceTaskGroupVersionId?`\n- `createdAt`\n\nSuggested `type` examples:\n- `execute`\n- `explore`\n- `debug`\n- `review`\n- `verify`\n- `delegate`\n\nDelegation/waiting fields for `type: delegate` or `status: waiting`:\n- `delegateeType` (`human | ai | agent | system`)\n- `delegateeRef`\n- `request`\n- `expectedOutput`\n- `requestedAt`\n- `timeoutAt?`\n- `onTimeout?` (`escalate | retry | cancel | create_followup`)\n\nA waiting delegated node blocks downstream execution until it is resolved, cancelled, or timed out into a follow-up decision.\n\n### 2.9 RunEdge\n\nA relation between run graph nodes, including EoW terminal nodes.\n\nFields:\n- `id`\n- `runId`\n- `fromRunNodeId`\n- `toRunNodeId`\n- `edgeType`\n- `note?`\n\nSuggested `edgeType` examples:\n- `depends_on`\n- `informs`\n- `reuses`\n- `blocks`\n- `follows`\n- `tests`\n- `waits_for`\n- `closes_with`\n\n## 3. Task graph invariants\n\n### 3.1 Coverage\n\nThe child tasks in a task-group version must be sufficient to accomplish the parent objective.\n\nOperational test:\n> If every child task completes, can we honestly say the parent objective is accomplished?\n\n### 3.2 Responsibility orthogonality\n\nSibling tasks must not overlap in:\n- primary responsibility\n- primary ownership of the same deliverable\n- completion judgment\n\nAllowed:\n- shared context\n- mutual influence\n- downstream impact on each other\n- overlap in actual execution work inside the run graph\n\nNot allowed:\n- two sibling tasks both being the primary owner of the same thing\n- two sibling tasks requiring the same completion judgment to be considered done\n\n### 3.3 Closure\n\nEach task must have a locally understandable completion boundary, and every terminal selected branch must eventually end with an EoW node.\n\nOperational tests:\n> Can a human say what “done” means for this task without reading the entire project history?\n\n> Does every terminal branch in the active snapshot visibly close with EoW?\n\n## 4. Completion rule\n\nA work is complete when:\n\n```text\nactive snapshot terminal task branches all have task-graph EoW\n+ required terminal run paths have run-graph EoW\n+ there are no unresolved waiting/delegated/blocking run nodes\n```\n\nThis makes completion graph-visible instead of implicit.\n\n## 5. Task graph operations\n\n### 5.1 `decompose`\n\nCreates the first concrete child-task set for a task group.\n\nInput:\n- parent task group objective\n- rationale\n- proposed children\n\nOutput:\n- new `TaskGroupVersion`\n- child `Task` records\n- optional validation report\n\n### 5.2 `refactor`\n\nCreates a new version of an existing task group.\n\nUse when:\n- coverage is weak\n- sibling responsibility is overlapping\n- completion boundaries are unclear\n- learning changed the best decomposition\n\nImportant:\n- refactor does not erase old decomposition history\n- refactor creates a new `TaskGroupVersion`\n- child subtrees become version-dependent under the chosen path\n\n## 6. Run graph rules\n\nThe run graph may be messier than the task graph. That is expected.\n\nAllowed in run graph:\n- overlapping work\n- cross-level work relations\n- one run node helping multiple tasks\n- reused outputs\n- exploratory loops\n- explicit debugging, verification, and review work\n- human/AI/agent delegation and waiting\n- references to external run graphs\n\nExploratory run nodes are valid execution truth when their objective is learning: search, try/error, prototype, debug, or review enough context to improve the next task-graph decision.\n\nThe run graph should tell the truth about how work actually unfolded, even when that truth is not tree-shaped.\n\n## 7. Relation between task and run layers\n\n### 7.1 Bidirectional traceability\n\nA task may list `runRefs`.\nA run node may link back with `sourceTaskId` and `sourceTaskGroupVersionId`.\n\nValidator behavior:\n- task `runRefs` should resolve to real run nodes\n- referenced run nodes should point back to the source task\n- run nodes with `sourceTaskId` should have matching task-side `runRefs`\n\n### 7.2 Non-isomorphism\n\nThe run graph is not required to mirror the task graph one-to-one. That would be a design mistake.\n\nTask graph answers:\n> What is the right decomposition?\n\nRun-readiness classification answers:\n> Should this task run now, decompose next, explore first, or wait on a blocker?\n\nRun graph answers:\n> What actually happened in execution?\n\n### 7.3 Honest divergence\n\nIf real work repeatedly violates a decomposition, that is a signal to consider `refactor`.\nThe solution is not to falsify the run graph.\n\n## 8. Immediate implementation implications\n\nThe implementation should favor:\n- explicit ids\n- visible EoW terminal nodes\n- bidirectional task↔run references\n- independent `runs/<run-id>/` graphs\n- append-preserving history\n- version selection over destructive overwrite\n- validator checks for task-graph closure and run-graph waiting/delegation\n- md-first human inspectability\n\nThe implementation should avoid:\n- hidden closure fields that do not show up in graph views\n- combinatorial snapshot explosion\n- implicit mutation magic\n- overfitting the model to one UI surface\n\nFile v0.5.3:references/decomposition-protocol.md\n\n# TaskOps Decomposition Protocol\n\nTaskOps is not a checklist store. It turns an objective into a task tree, then uses execution feedback to improve the tree over time.\n\n## Core loop\n\n1. State the work objective in one sentence.\n2. Decompose only one requested depth at a time.\n3. Classify each task node by run readiness:\n   - `runnable`\n   - `needs_decomposition`\n   - `needs_exploration`\n   - `blocked`\n4. Send only `runnable` nodes into an independent run graph under `runs/<run-id>/`.\n5. For `needs_decomposition`, create the next task group/version.\n6. For `needs_exploration`, create an exploratory run whose purpose is understanding, not delivery.\n7. If a run needs a human, another AI, an agent, or an external system, create a `type: delegate` / `status: waiting` run node with expected output and timeout metadata.\n8. After every run, feed the result back into the task graph: update unknowns, constraints, decomposition, readiness, or task↔run refs.\n9. When a selected branch is truly terminal, attach an explicit EoW node. A branch without EoW is still open.\n\n## Objective discipline\n\nEvery work root and task group should have a one-line objective. That objective is the root of its decomposition tree.\n\nGood:\n\n```text\nBuild a today-first action app that makes the current actionable surface trusted.\n```\n\nBad:\n\n```text\nResearch tasks, build screens, define states, test, polish, launch.\n```\n\nThe bad example is an activity list. It mixes levels and hides responsibility boundaries.\n\n## Depth discipline\n\nDefault decomposition depth is `1`.\n\nA depth-1 result should contain the largest responsibility units under the parent objective, not every activity the system can imagine.\n\nExample:\n\n```text\nDevelop Today It app\n├─ Define product contract\n├─ Design core action loop\n├─ Build app foundation\n├─ Implement core features\n└─ Verify MVP\n```\n\nOnly decompose a child when the current child is not runnable and the system understands enough to split it honestly.\n\n## Anti-list validator heuristics\n\nA decomposition should be reviewed when:\n\n- sibling tasks mix abstraction levels\n- tasks are activities rather than responsibility units\n- parent-child relationship is weak or merely topical\n- depth expands before the parent objective is stable\n- a task is marked decomposable even though the system cannot explain the child responsibilities\n\n## Negative feedback loop\n\nTaskOps should improve inductively:\n\n```text\nobjective\n→ tree decomposition\n→ run-readiness classification\n→ run / decompose / explore\n→ result + delegation + failure + learned constraints\n→ revised tree\n→ EoW closure when a branch is terminal\n→ better next classification\n```\n\nThe important rule: failed or exploratory execution is not waste. It is feedback that updates the task graph.\n\n## Closure discipline\n\nDo not treat `done` as the same thing as EoW.\n\n- `done` is a status on a task or run node.\n- `EoW` is a visible terminal graph node declaring that this branch/path should not decompose or execute further.\n\nWork completion should be derived from graph closure:\n\n```text\nall active-snapshot terminal task branches have EoW\n+ required terminal run paths have EoW\n+ no unresolved waiting/delegated/blocking nodes remain\n```\n\nFile v0.5.3:references/examples.expected-results.json\n\n{\n  \"examples\": [\n    {\n      \"name\": \"unit-transition-ready-to-done\",\n      \"expected_result\": {\n        \"summary\": \"Marking a ready node as done should advance downstream blocked nodes whose dependencies are now satisfied.\",\n        \"verification\": {\n          \"level\": \"unit\",\n          \"checks\": [\n            {\n              \"id\": \"u1\",\n              \"type\": \"state\",\n              \"prompt\": \"After recording success on node A, node A must be status=done and any node depending only on A must become ready.\"\n            }\n          ]\n        },\n        \"failure_handling\": {\n          \"retry_hint\": \"Check dependency refresh logic.\",\n          \"escalate_when\": \"Dependency semantics are ambiguous or contradictory.\"\n        }\n      }\n    },\n    {\n      \"name\": \"integrated-cli-next-and-result\",\n      \"expected_result\": {\n        \"summary\": \"The CLI should initialize a graph, show the next ready node, accept a structured result, and produce an inspectable updated graph.\",\n        \"verification\": {\n          \"level\": \"integrated\",\n          \"checks\": [\n            {\n              \"id\": \"i1\",\n              \"type\": \"artifact\",\n              \"prompt\": \"The project directory must contain graph state and an updated event/result log after the CLI flow completes.\"\n            },\n            {\n              \"id\": \"i2\",\n              \"type\": \"behavior\",\n              \"prompt\": \"The next-node selection after result ingestion must match the dependency structure declared in the graph.\"\n            }\n          ]\n        },\n        \"failure_handling\": {\n          \"branch_hint\": \"Create a debug branch if the graph state is valid but selection behavior is inconsistent.\",\n          \"escalate_when\": \"State updates cannot be explained by the declared graph contract.\"\n        }\n      }\n    },\n    {\n      \"name\": \"closed-human-guided-review\",\n      \"expected_result\": {\n        \"summary\": \"In a bounded scenario, OpenClaw and Jimmy should be able to inspect the same graph and agree whether execution followed the intended path honestly.\",\n        \"verification\": {\n          \"level\": \"closed\",\n          \"checks\": [\n            {\n              \"id\": \"c1\",\n              \"type\": \"human-review\",\n              \"prompt\": \"A human reviewer can inspect the graph and understand why the current node was chosen and whether its outcome matched the declared expectation.\"\n            }\n          ]\n        },\n        \"failure_handling\": {\n          \"escalate_when\": \"The graph can be traversed mechanically but is not legible or reviewable by the human operator.\"\n        }\n      }\n    }\n  ]\n}\n\nFile v0.5.3:references/expected-result.schema.json\n\n{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"$id\": \"graph-task.expected-result.schema.v0\",\n  \"title\": \"ExpectedResult\",\n  \"type\": \"object\",\n  \"required\": [\"summary\", \"verification\"],\n  \"properties\": {\n    \"summary\": {\n      \"type\": \"string\",\n      \"description\": \"Natural-language statement of what should be true after the work.\"\n    },\n    \"verification\": {\n      \"type\": \"object\",\n      \"required\": [\"level\", \"checks\"],\n      \"properties\": {\n        \"level\": {\n          \"type\": \"string\",\n          \"enum\": [\"unit\", \"integrated\", \"closed\"]\n        },\n        \"checks\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"object\",\n            \"required\": [\"id\", \"type\", \"prompt\"],\n            \"properties\": {\n              \"id\": {\"type\": \"string\"},\n              \"type\": {\n                \"type\": \"string\",\n                \"enum\": [\"state\", \"artifact\", \"behavior\", \"human-review\"]\n              },\n              \"prompt\": {\n                \"type\": \"string\",\n                \"description\": \"Structured natural-language assertion that OpenClaw can review.\"\n              },\n              \"must_pass\": {\"type\": \"boolean\", \"default\": true}\n            }\n          }\n        }\n      }\n    },\n    \"failure_handling\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"retry_hint\": {\"type\": \"string\"},\n        \"branch_hint\": {\"type\": \"string\"},\n        \"escalate_when\": {\"type\": \"string\"}\n      }\n    }\n  }\n}\n\nFile v0.5.3:references/md-first-format.md\n\n# TaskOps md-first format\n\nThis document defines the canonical markdown-first storage direction for TaskOps.\n\n## Goals\n\n- human-readable and human-editable\n- validator-friendly\n- append-preserving where possible\n- suitable for both skill and Obsidian plugin surfaces\n- clear separation between canonical state and derived visualization artifacts\n- graph-visible closure through explicit EoW nodes\n\n## Design stance\n\nTaskOps stores **canonical decomposition state** and **canonical execution state** in markdown-first structures.\nDerived artifacts such as canvas views, summaries, or exports must stay explicitly non-canonical.\n\n## Top-level work shape\n\n```text\n<taskops-work>/\n  index.md\n  work-log.md\n  task-groups/\n    <task-group-id>/\n      index.md\n      versions/\n        <version-id>/\n          index.md\n          decomposition-log.md\n          tasks/\n            <task-id>.md\n          eow/\n            <eow-id>.md\n  snapshots/\n    <snapshot-id>.md\n  runs/\n    <run-id>/\n      index.md\n      nodes/\n        <run-node-id>.md\n        <eow-id>.md\n      edges/\n        <run-edge-id>.md\n      run-log.md\n  derived/\n    canvases/\n    views/\n```\n\nLegacy notes:\n- old `entityType: project` roots may still be read, but new roots should use `entityType: work`\n- old singular `run/` folders may still be read, but new execution graphs should use `runs/<run-id>/`\n\n## Canonical split\n\n### Task graph canonical area\n- `task-groups/`\n- `snapshots/`\n- task-graph EoW nodes under each selected task-group version's `eow/`\n\n### Run graph canonical area\n- `runs/<run-id>/`\n- run-graph EoW nodes inside the run graph's `nodes/`\n\n### Non-canonical derived area\n- `derived/`\n- old generated `canvases/` folders when present\n\n## Canonical entity notes\n\nEvery canonical entity note should use YAML frontmatter.\n\nMinimum common fields:\n- `taskOpsVersion`\n- `entityType`\n- `id`\n- `createdAt`\n- `updatedAt?`\n- `status?`\n\n## Entity notes\n\n### Work\n\nPath:\n- `<work>/index.md`\n\nSuggested fields:\n- `taskOpsVersion`\n- `entityType: work`\n- `id`\n- `title`\n- `objective`\n- `activeRootTaskGroupId`\n- `activeSnapshotId?`\n- `createdAt`\n- `status`\n\n### TaskGroup\n\nPath:\n- `task-groups/<task-group-id>/index.md`\n\nSuggested fields:\n- `entityType: taskGroup`\n- `id`\n- `objective`\n- `parentTaskId?`\n- `activeVersionId?`\n- `createdAt`\n\n### TaskGroupVersion\n\nPath:\n- `task-groups/<task-group-id>/versions/<version-id>/index.md`\n\nSuggested fields:\n- `entityType: taskGroupVersion`\n- `id`\n- `taskGroupId`\n- `version`\n- `summary`\n- `supersedesVersionId?`\n- `selected: true|false`\n- `createdAt`\n\n### Task\n\nPath:\n- `task-groups/<task-group-id>/versions/<version-id>/tasks/<task-id>.md`\n\nSuggested fields:\n- `entityType: task`\n- `id`\n- `taskGroupId`\n- `taskGroupVersionId`\n- `title`\n- `objective`\n- `responsibility`\n- `completionCriteria`\n- `order`\n- `runReadiness?`\n- `runReadinessReason?`\n- `understandingLevel?`\n- `unknowns?`\n- `nextLearningGoal?`\n- `decompositionConfidence?`\n- `executionConfidence?`\n- `childTaskGroupId?`\n- `runRefs?`\n- `createdAt`\n\nExample task↔run reference:\n\n```yaml\nrunRefs:\n  - runId: run-alpha-v1\n    runNodeId: run-node-verify\n    role: verification\n```\n\nExample exploratory task metadata:\n\n```yaml\nrunReadiness: needs_exploration\nrunReadinessReason: The task objective is clear, but the API behavior is not understood well enough to decompose.\nunderstandingLevel: partial\nunknowns:\n  - retry semantics\n  - required permission scope\nnextLearningGoal: Run a minimal API trial and write the constraints needed for the next decomposition.\n```\n\n### EoW for task graph\n\nPath:\n- `task-groups/<task-group-id>/versions/<version-id>/eow/<eow-id>.md`\n\nSuggested fields:\n- `entityType: eow`\n- `id`\n- `graphType: task`\n- `attachedToType: task`\n- `attachedToId`\n- `reason`\n- `declaredBy`\n- `declaredAt`\n- `evidenceRefs?`\n- `createdAt`\n- `status: done`\n\nExample:\n\n```yaml\nentityType: eow\nid: eow-task-verify-example\ngraphType: task\nattachedToType: task\nattachedToId: task-verify-example\nreason: no_further_decomposition\ndeclaredBy: ai\ndeclaredAt: 2026-05-08T04:45:00+09:00\nevidenceRefs:\n  - run:run-alpha-v1/node:run-node-verify\nstatus: done\n```\n\n### VersionSnapshot\n\nPath:\n- `snapshots/<snapshot-id>.md`\n\nSuggested fields:\n- `entityType: versionSnapshot`\n- `id`\n- `rootTaskGroupId`\n- `createdAt`\n- `label?`\n\nBody/frontmatter should include a deterministic selected-version map, for example:\n\n```yaml\nselectedVersions:\n  - taskGroupId: tg-root\n    versionId: tgv-root-v1\n  - taskGroupId: tg-design\n    versionId: tgv-design-v3\n```\n\n### Run index\n\nPath:\n- `runs/<run-id>/index.md`\n\nSuggested fields:\n- `entityType: run`\n- `id`\n- `workId`\n- `createdAt`\n- `status`\n\n### RunNode\n\nPath:\n- `runs/<run-id>/nodes/<run-node-id>.md`\n\nSuggested fields:\n- `entityType: runNode`\n- `id`\n- `runId`\n- `type`\n- `title`\n- `status`\n- `sourceTaskId?`\n- `sourceTaskGroupVersionId?`\n- `createdAt`\n\nSuggested `type` values include `execute`, `explore`, `debug`, `review`, `verify`, and `delegate`.\nUse `explore` when the run objective is learning enough to update task readiness or decomposition.\nUse `delegate` when work is intentionally handed to a human, another AI, an agent, or an external system.\n\nDelegation/waiting example:\n\n```yaml\nentityType: runNode\nid: run-node-human-decision\nrunId: run-alpha-v1\ntype: delegate\ntitle: Ask Jimmy to confirm constraints\nstatus: waiting\nsourceTaskId: task-user-constraints\nsourceTaskGroupVersionId: tgv-root-v1\ndelegateeType: human\ndelegateeRef: jimmy\nrequest: Confirm the constraints needed before downstream execution.\nexpectedOutput: A clear decision and any constraints that update the task graph.\nrequestedAt: 2026-05-08T04:45:00+09:00\ntimeoutAt: 2026-05-10T04:45:00+09:00\n```\n\n### EoW for run graph\n\nPath:\n- `runs/<run-id>/nodes/<eow-id>.md`\n\nSuggested fields:\n- `entityType: eow`\n- `id`\n- `runId`\n- `graphType: run`\n- `attachedToType: runNode`\n- `attachedToId`\n- `reason`\n- `declaredBy`\n- `declaredAt`\n- `createdAt`\n- `status: done`\n\nRun EoW nodes should usually be connected by a `runEdge` with `edgeType: closes_with`.\n\n### RunEdge\n\nPath:\n- `runs/<run-id>/edges/<run-edge-id>.md`\n\nSuggested fields:\n- `entityType: runEdge`\n- `id`\n- `runId`\n- `fromRunNodeId`\n- `toRunNodeId`\n- `edgeType`\n- `createdAt`\n\n`fromRunNodeId` and `toRunNodeId` may point to either a `runNode` or an EoW node inside the same run graph.\n\n## Logging files\n\nAppend-oriented logs should be plain markdown:\n- `work-log.md`\n- `decomposition-log.md`\n- `run-log.md`\n\nPurpose:\n- preserve rationale\n- preserve review/audit trail\n- avoid hiding important structural changes behind silent rewrites\n\n## Validation targets\n\nValidator should check at least:\n\n### Work\n- root `index.md` exists\n- new roots use `entityType: work`\n- legacy `entityType: project` is readable\n- active root task group and active snapshot exist\n\n### Task graph\n- required files/folders exist\n- ids match paths\n- task-group-version ownership is coherent\n- sibling task ids are unique within a version\n- optional invariant warnings for coverage / orthogonality / closure quality\n- only one active version per task group unless explicitly marked otherwise\n- active-snapshot terminal task branches have EoW nodes\n\n### Snapshots\n- selected task groups exist\n- selected versions exist\n- selected path is structurally reachable from root\n\n### Run graph\n- independent `runs/<run-id>/` folders are valid\n- run nodes exist\n- run edges reference real run nodes or EoW nodes\n- referenced source task/task-group-version ids exist if present\n- task `runRefs` and run-node `sourceTaskId` agree bidirectionally\n- delegated/waiting nodes include enough request/delegatee metadata\n- done terminal run paths have EoW nodes\n\n## Selection model\n\nImportant rule:\n- version trees may exist broadly\n- snapshots materialize chosen paths\n- the system should not generate or persist all theoretical combinations\n\n## Derived artifacts\n\nExamples:\n- Obsidian canvas exports\n- tree summaries\n- filtered work views\n- visual layouts\n\nAll should live under `derived/` or a clearly non-canonical generated surface and be labeled non-canonical.\n\n## Reference example\n\nSee `../examples/taskops-canonical-minimal-v1/` for the concrete v1-shaped example using:\n- `entityType: work`\n- versioned task groups\n- a selected snapshot\n- explicit EoW nodes\n- independent `runs/<run-id>/` graph storage\n- bidirectional task↔run references\n- a clearly non-canonical derived area\n\n## Migration note\n\nThis format is a reset from the earlier `graph-task` md-first project/step/phase/node hierarchy.\nThat older shape is still useful as source material, but TaskOps v1 should align storage around:\n- work roots\n- versioned task groups\n- explicit snapshots\n- explicit EoW closure nodes\n- independent run graph separation\n\nFile v0.5.3:references/md-first-vnext-spec.md\n\n# graph-task vNext — md-first collaborative protocol\n\n## Purpose\nThis spec resets `graph-task` from a `graph.json`-canonical workflow into a **structured-markdown collaborative task protocol**.\n\nThe goal is not just prettier visualization.\nThe goal is to create a task substrate that can be shared across:\n- OpenClaw / Linux execution agents\n- GitHub as durable sync + history\n- Obsidian as the primary human inspection and editing surface\n- future human ↔ AI and AI ↔ AI collaboration flows\n\n## Why this reset\nThe earlier direction treated:\n- `graph.json` as canonical state\n- Markdown as a projection / inspection layer\n- Obsidian as primarily read-only visualization\n\nThat split is no longer the best fit.\n\nIf Obsidian is a real working surface, and if multiple humans/agents may read and write the same task data, then:\n- duplicated canonical layers create avoidable sync risk\n- JSON is not the best shared collaboration surface\n- git-friendly, append-friendly, human-readable files become more important than a single machine-shaped document\n\n## New canonical rule\n**Canonical state lives in markdown files.**\n\nJSON is demoted to support roles only:\n- schema references\n- validation fixtures\n- parser test vectors\n- optional export/import or snapshot formats\n- internal plugin/runtime derived state if useful\n\nDo not treat JSON as the durable source of truth in vNext.\n\n## Core design goal\nEnable deterministic task handling without requiring a monolithic machine-owned state file.\n\nWhen the markdown tree lives inside a Git-backed vault, treat that repo as the shared canonical workset.\nLocal edits should be synchronized back into the remote workset rather than allowed to drift as a separate local-only truth.\n\nDeterminism should come from:\n- strict folder and file conventions\n- YAML frontmatter contracts\n- explicit append-only / history-preserving rules\n- limited write semantics\n- git-visible diffs\n- protocol-aware tooling and plugin affordances\n\nNot from hiding everything inside one JSON blob.\n\n## Primary worldview\n`graph-task` is no longer best understood as a generic graph visualizer.\n\nIt is better understood as:\n- a **structured task tree protocol** with explicit semantics\n- where graph relationships may still exist,\n- but tree / containment / execution progression are the first-class interaction model\n\nSo:\n- tree is primary\n- graph is secondary\n- deterministic workflow UI matters more than freeform graph rendering\n\n## High-level hierarchy\nThe conceptual model remains:\n- Project\n- Step\n- Phase\n- Node\n\nBut the persistent representation becomes a filesystem protocol.\n\n## Canonical filesystem layout\nA project run is stored as a folder tree.\n\nExample:\n\n```text\n<project-id>/\n  index.md\n  project-log.md\n  steps/\n    <step-id>/\n      index.md\n      step-log.md\n      phases/\n        <phase-id>/\n          index.md\n          phase-log.md\n          nodes/\n            <node-id>.md\n            <node-id-2>.md\n          results/\n            <result-id>.md\n            <result-id-2>.md\n```\n\nOptional future folders:\n\n```text\n<project-id>/\n  inbox/\n  reviews/\n  decisions/\n  attachments/\n  locks/\n```\n\n## Representation rule\n- Project / Step / Phase are represented as **folders with `index.md`**.\n- Node is represented as a **markdown file**.\n- Result history is represented as **append-only result notes** (preferred) or embedded append-only result sections if the simpler model proves sufficient.\n- Log / narrative surfaces live in dedicated `*-log.md` files or append-only dated notes.\n\n## Why folder + index.md\nFolders express containment.\n`index.md` expresses machine-readable metadata + human-readable summary.\n\nThis gives:\n- intuitive filesystem navigation\n- git-friendly diffs\n- deterministic discovery\n- Obsidian-friendly note handling\n- plugin-friendly parsing\n\n## Frontmatter rule\nEvery canonical entity note must begin with YAML frontmatter.\n\n### Required common fields\nEvery entity note must include at least:\n\n```yaml\ngraphTaskVersion: 2\nentityType: project|step|phase|node|result\nid: <entity-id>\nstatus: pending|active|done|blocked|cancelled\n```\n\n### Project `index.md`\nExample:\n\n```md\n---\ngraphTaskVersion: 2\nentityType: project\nid: project-alpha\nstatus: active\ntitle: Project Alpha\ngoal: Verify md-first collaborative workflow\ncreatedAt: 2026-04-24T13:00:00Z\n---\n```\n\nRecommended extra fields:\n- title\n- goal\n- description\n- createdAt\n- updatedAt\n- owners\n- repo\n- tags\n\n### Step `index.md`\n\n```md\n---\ngraphTaskVersion: 2\nentityType: step\nid: step-1\nprojectId: project-alpha\nstepType: implementation\nstatus: active\ncreatedAt: 2026-04-24T13:10:00Z\n---\n```\n\n### Phase `index.md`\n\n```md\n---\ngraphTaskVersion: 2\nentityType: phase\nid: phase-diverge-1\nprojectId: project-alpha\nstepId: step-1\nphaseType: diverge\nstatus: active\nsequence: 1\ncreatedAt: 2026-04-24T13:20:00Z\n---\n```\n\n### Node `<node-id>.md`\n\n```md\n---\ngraphTaskVersion: 2\nentityType: node\nid: node-compare-options\nprojectId: project-alpha\nstepId: step-1\nphaseId: phase-diverge-1\nnodeType: work\nstatus: active\ncreatedAt: 2026-04-24T13:25:00Z\n---\n```\n\n### Result `<result-id>.md`\n\n```md\n---\ngraphTaskVersion: 2\nentityType: result\nid: result-0001\nprojectId: project-alpha\nstepId: step-1\nphaseId: phase-diverge-1\nnodeId: node-compare-options\nstatus: done\nrecordedAt: 2026-04-24T14:00:00Z\nexpected: Compare candidate options honestly\nactual: Chose option B after verifying lower complexity\nartifacts:\n  - references/eval.md\n---\n```\n\n## Body content rule\nFrontmatter is for structured parsing.\nBody markdown is for human-readable context.\n\nRecommended sections:\n- Summary\n- Description\n- Current state\n- Links / related entities\n- Notes\n- Decision / rationale\n- Next questions\n\nThe body may evolve more freely than frontmatter, but frontmatter must remain schema-valid.\n\n## Links rule\nWiki links are for navigation and context, not for canonical discovery.\n\nMeaning:\n- the plugin / parser should discover entities from the folder structure + frontmatter\n- wiki links are helpful but not the only source of truth\n\nThis reduces fragility if links are temporarily missing.\n\nStill, entity notes should include useful links for human navigation.\n\n## Deterministic discovery rule\nCanonical entity discovery must work even if note bodies are minimal.\n\nA parser should be able to reconstruct the task tree from:\n- folder location\n- file name\n- frontmatter\n\nwithout depending on freeform prose.\n\n## Primary semantics\n### Project\nTop-level unit of work.\nContains Steps.\n\n### Step\nMajor work partition inside a Project.\nContains Phases.\n\n### Phase\nExecution mode unit inside a Step.\nCurrent phase types remain:\n- diverge\n- converge\n- verify\n- commit\n\nA Step may repeat:\n- diverge\n- converge\n- verify\n\nA Step should contain at most one commit phase unless a future spec deliberately expands that rule.\n\n### Node\nConcrete work item / observation / check / execution unit inside a Phase.\n\n### Result\nExpected-vs-actual record attached to a Node.\nResults are append-only.\n\n## Append-only bias\nThis protocol is history-preserving by default.\n\nPreferred operations:\n- add a new Step\n- add a new Phase\n- add a new Node\n- append a new Result\n- append a new log entry\n- mark status forward\n\nDiscouraged operations:\n- deleting entities\n- rewriting history to hide prior states\n- mutating older result records\n- repurposing old phases to mean something new\n\nIf understanding changes, prefer adding a new Phase / Node / Result instead of erasing the old one.\n\n## Sync philosophy\nThe system is built assuming git-based sync.\n\nThis means the persistent shape should optimize for:\n- readable diffs\n- small conflict surfaces\n- append-only updates\n- human review of changes\n- explicit history\n\nThis is one reason md-first is preferred over a single canonical JSON file.\n\n## Concurrency philosophy\nIf Obsidian becomes a writable working surface, sync semantics matter.\n\nRead-only consumption is easy.\nWriteable collaboration is the real design problem.\n\nSo vNext must define allowed write patterns early.\n\n## Write-safety rule\nDo **not** assume every actor can safely edit every file at any time.\n\nDefault design principle:\n- many readers\n- constrained writers\n- append-first mutations\n\n## Conflict minimization strategy\n### 1. Split files by entity\nDo not keep the whole project state in one document.\n\n### 2. Prefer append-only notes\nAppending a new result or log entry is safer than rewriting old content.\n\n### 3. Keep high-contention files small\n`index.md` files should hold metadata + concise summary, not giant rolling logs.\n\n### 4. Separate narrative logs from structural metadata\nThis reduces collisions between state updates and commentary.\n\n## Default write model (recommended)\n### Read path\n- humans may browse/edit notes in Obsidian\n- OpenClaw may read/update via repo checkout\n- other agents may read/write through the same protocol\n\n### Safe default write path\n- structural mutations happen through protocol-aware tooling or plugin commands\n- freeform note edits are allowed in designated log / notes sections\n- result creation is append-only\n- status changes update frontmatter only in the owning entity note\n\n## Suggested edit permissions by file type\n### `index.md` files\nHigh importance.\nShould preferably be edited by plugin/tooling rather than casual manual edits.\n\n### `*-log.md` files\nLow-risk narrative surface.\nHumans and AIs may append more freely.\n\n### `results/*.md`\nAppend-only creation is preferred.\nExisting result files should rarely be edited beyond typo fixes.\n\n### `nodes/*.md`\nModerate risk.\nMetadata is structured; body can be richer.\n\n## Locking / ownership options\nvNext should not hard-require one locking scheme yet, but should leave room for it.\n\nCandidate models:\n\n### Option A — social protocol only\nRely on git + human discipline.\nBest for early experimentation.\nWeakest safety.\n\n### Option B — project lease file\nA project has a lightweight lock / lease note showing current active editor.\nGood for reducing accidental simultaneous structural edits.\n\n### Option C — branch-per-actor\nEach actor works on a branch.\nSafer, but heavier operationally.\n\n### Option D — entity-level claims\nSpecific Step or Phase claims rather than project-wide lock.\nMore scalable, but more complex.\n\n## Recommended near-term concurrency rule\nStart simple:\n- no hard lock yet\n- but treat **structural edits as single-writer at a time per project**\n- allow broader multi-reader behavior\n- allow append-only logs/results with more flexibility\n\nThis is honest and much safer than pretending arbitrary concurrent editing is already solved.\n\n## Obsidian role\nObsidian is not just a passive visualizer anymore.\nIt becomes a primary human working surface.\n\nBut it should not become an unrestricted freeform editor for critical structure.\n\n## Plugin role\nThe custom Obsidian plugin should become a **protocol-aware deterministic task client**.\n\nNot just a graph renderer.\n\nIts MVP job is to:\n- parse the md-first task tree\n- render Project / Step / Phase / Node as a structured tree UI\n- show statuses, phase types, result counts, and active blockers clearly\n- open the underlying notes for human inspection\n- provide safe commands for permitted structural operations\n\n## Plugin is preferable because\nOur task model is not a generic Obsidian note graph.\nIt has execution semantics.\n\nWhat matters most is:\n- containment\n- execution mode\n- status\n- result history\n- deterministic task navigation\n\nThat is better served by a dedicated plugin than by trying to force everything into generic graph view behavior.\n\n## Plugin MVP\nMinimum useful plugin behavior:\n- detect graph-task projects in the vault\n- show tree view:\n  - Project\n  - Step list\n  - Phase list\n  - Node list\n- show metadata badges:\n  - status\n  - phase type\n  - result count\n  - blocked / done state\n- open underlying markdown notes on click\n- reload / refresh parsed state\n- optionally create safe new Step / Phase / Node / Result stubs through controlled commands\n\n## Graph visualization in vNext\nGraph visualization is secondary.\n\nPossible later support:\n- local subgraph for one Step\n- phase transition view\n- node dependency mini-map\n\nBut the default interaction should be tree-first, not graph-first.\n\n## Validation approach\nBecause canonical state is markdown, validation should focus on:\n- required files exist\n- folder containment is valid\n- frontmatter schema is valid\n- ids match file locations\n- cross-references are coherent\n- phase rules are respected\n- append-only assumptions are not silently violated\n\n## Canonical parser contract\nA parser should be able to build an internal model from the md tree and detect:\n- Project identity\n- Step list and order\n- Phase list and order\n- Node ownership\n- Result ownership\n- statuses and timestamps\n\nThis derived internal model may be represented as JSON in memory, but that does not make JSON canonical on disk.\n\n## Migration implication\nThe current Phase 1 / Phase 2 implementation can still be useful as a prototype,\nbut vNext likely requires a redesign:\n- from `graph.json` write-first\n- to `index.md` / structured note write-first\n\nSo treat earlier JSON-canonical work as learning, not final architecture.\n\n## Immediate next questions\n1. Exact folder naming rules: ids only, or numeric sequence prefixes too?\n2. Should result history live in separate files by default, or inline until volume proves it painful?\n3. What is the smallest safe plugin mutation set for MVP?\n4. Do we want a lightweight project lease / lock note in MVP, or only document the single-writer rule first?\n5. Which fields are mandatory in frontmatter vs optional in body text?\n\n## Recommended next implementation order\n1. freeze md-first filesystem contract\n2. freeze frontmatter schema by entity type\n3. define validation rules for markdown canonical state\n4. define plugin MVP tree UI + safe mutation commands\n5. build sample md-first example project\n6. build parser + validator\n7. build Obsidian plugin MVP\n8. only later consider richer graph views or multi-actor lock automation\n\nFile v0.5.3:references/obsidian-plugin-mvp-spec.md\n\n# graph-task Obsidian plugin — MVP spec\n\n## Purpose\nThe plugin is the deterministic Obsidian client for the md-first `graph-task` protocol.\n\nIt is **not** primarily a generic graph visualizer.\nIts job is to make the canonical markdown task tree:\n- discoverable\n- inspectable\n- safely editable within constrained rules\n- usable by humans working alongside AI agents\n\n## Product stance\nPrimary interaction model:\n- tree-first\n- protocol-aware\n- read-heavy, write-constrained\n\nSecondary interaction model:\n- local graph/subgraph views later if they prove useful\n\nDo not optimize the MVP around fancy global graph rendering.\nOptimize around reliable task handling.\n\n## Canonical data source\nThe plugin reads canonical markdown files from the vault.\n\nDiscovery depends on:\n- folder structure\n- `index.md` presence for Project / Step / Phase\n- YAML frontmatter\n\nThe plugin may build an internal in-memory JSON model for rendering, but markdown remains canonical on disk.\n\n## Detected project layout\nA graph-task project root looks like:\n\n```text\n<project-id>/\n  index.md\n  project-log.md\n  steps/\n    <step-id>/\n      index.md\n      step-log.md\n      phases/\n        <phase-id>/\n          index.md\n          phase-log.md\n          nodes/\n            <node-id>.md\n          results/\n            <result-id>.md\n```\n\n## MVP user stories\n1. As a human, I can open Obsidian and immediately see all graph-task projects in the vault.\n2. As a human, I can expand a project into Steps, Phases, Nodes, and Results without manually traversing folders.\n3. As a human, I can see status, phase type, and result counts at a glance.\n4. As a human, I can click an item and open the canonical markdown note.\n5. As a human, I can perform a few safe structural operations from the plugin without hand-editing critical frontmatter.\n6. As an AI-assisted operator, I can rely on the plugin to preserve required file structure and frontmatter when creating new entities.\n\n## Core UI surfaces\n### 1. Project explorer view\nA dedicated side panel showing:\n- Project\n  - Step\n    - Phase\n      - Nodes\n      - Results\n\nEach row should show compact badges:\n- status\n- phase type (for phase rows)\n- result count (for node or phase rows)\n- blocked indicator\n- done indicator\n\n### 2. Detail pane / inspector\nWhen an entity is selected, show a structured detail view:\n- identity\n- status\n- ownership fields (`projectId`, `stepId`, `phaseId`, etc.)\n- timestamps\n- summary fields\n- quick links to related canonical notes\n- latest results for a node or phase\n\nThe detail pane should also include an “Open note” action.\n\n### 3. Validation / refresh controls\nThe plugin should provide:\n- Refresh parsed state\n- Re-scan vault for graph-task projects\n- Show validation issues for the selected project\n\n## Safe write semantics for MVP\nThe plugin must not behave like an unrestricted freeform editor for canonical structure.\n\n### Allowed writes in MVP\n- Create Project scaffold\n- Create Step scaffold under a Project\n- Create Phase scaffold under a Step\n- Create Node scaffold under a Phase\n- Create Result note under a Phase for a Node\n- Update status field in frontmatter\n- Append timestamped log entries to `project-log.md`, `step-log.md`, or `phase-log.md`\n\n### Disallowed writes in MVP\n- Delete Project / Step / Phase / Node from UI\n- Rename ids from UI after creation\n- Move entities between parents from UI\n- Rewrite older result files in bulk\n- Auto-merge conflicting concurrent edits\n- Freeform frontmatter mutation without validation\n\n### Rationale\nThese constraints keep the plugin aligned with append-only, history-preserving behavior.\n\n## Concurrency assumptions in MVP\nConcurrency is not fully solved yet.\n\nThe MVP should assume:\n- many readers\n- effectively one structural writer per project at a time\n- append-friendly logs/results may be less risky than structural edits\n\nThe plugin should surface this honestly.\n\n### Optional MVP warning\nIf a future lightweight project lease file exists, show it.\nIf not, at minimum show a warning banner like:\n- “Structural edits are safest with one active editor per project.”\n\n## Validation rules the plugin should enforce\nOn load or refresh, detect and surface:\n- missing `index.md`\n- missing required frontmatter fields\n- invalid `entityType`\n- mismatched ids vs folder/file names\n- Step outside a Project\n- Phase outside a Step\n- Node outside a Phase\n- Result missing a valid `nodeId`\n- duplicate sibling ids\n- multiple commit phases inside one Step\n\nValidation errors should not silently rewrite files.\nThey should be shown to the user.\n\n## Suggested row labels\n### Project row\n- title or id\n- status badge\n- Step count\n\n### Step row\n- id\n- step type\n- status badge\n- Phase count\n\n### Phase row\n- id\n- phase type badge\n- status badge\n- Node count\n- Result count\n\n### Node row\n- title or id\n- status badge\n- latest result badge if any\n\n### Result row\n- result id\n- status badge\n- recordedAt\n\n## Minimal commands\n- `graph-task: Refresh projects`\n- `graph-task: Open project explorer`\n- `graph-task: Create project`\n- `graph-task: Create step`\n- `graph-task: Create phase`\n- `graph-task: Create node`\n- `graph-task: Record result`\n- `graph-task: Set status`\n- `graph-task: Append project log`\n- `graph-task: Append step log`\n- `graph-task: Append phase log`\n\n## File-writing behavior\nWhen the plugin creates a new entity, it should:\n1. create the correct folder o\n\nArchive v0.5.2: 62 files, 88111 bytes\n\nFiles: examples/md-first-minimal/project-alpha/index.md (621b), examples/md-first-minimal/project-alpha/project-log.md (251b), examples/md-first-minimal/project-alpha/steps/step-1/index.md (444b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/index.md (566b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/nodes/node-compare-layout.md (655b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/phase-log.md (150b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/results/result-0001.md (864b), examples/md-first-minimal/project-alpha/steps/step-1/step-log.md (109b), examples/md-first-minimal/project-alpha/summary.md (270b), examples/md-first-minimal/README.md (403b), examples/minimal-project/graph.json (3183b), examples/minimal-project/summary.md (1176b), examples/self-dogfood-obsidian-vault/index.md (250b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-commit-findings-1__node-choose-next-improvement.md (940b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-commit-findings-1__phase-commit-findings-1-root.md (603b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-converge-findings-1__node-summarize-findings.md (1042b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-converge-findings-1__phase-converge-findings-1-root.md (615b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-commit-execution-1__node-lock-execution-findings.md (982b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-commit-execution-1__phase-commit-execution-1-root.md (621b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-execution-2__node-build-self-dogfood-example.md (1113b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-execution-2__phase-diverge-execution-2-root.md (627b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__node-read-cli-surface.md (940b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__node-read-phase1-spec.md (976b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__phase-diverge-surface-1-root.md (615b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-execution-2__node-validate-self-dogfood.md (960b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-execution-2__phase-verify-execution-2-root.md (621b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-surface-1__node-verify-phase1-usable.md (1046b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-surface-1__phase-verify-surface-1-root.md (609b), examples/self-dogfood-obsidian-vault/phases/step-followups__phase-commit-findings-1.md (1190b), examples/self-dogfood-obsidian-vault/phases/step-followups__phase-converge-findings-1.md (1177b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-commit-execution-1.md (1197b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-diverge-execution-2.md (1220b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-diverge-surface-1.md (1507b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-verify-execution-2.md (1191b), examples/self-dogfood-obsidian-vault/phases/step-self-dogfood__phase-verify-surface-1.md (1177b), examples/self-dogfood-obsidian-vault/projects/dogfood-phase1-project.md (654b), examples/self-dogfood-obsidian-vault/steps/step-followups.md (743b), examples/self-dogfood-obsidian-vault/steps/step-self-dogfood.md (1568b), examples/self-dogfood-project/graph.json (17884b), examples/self-dogfood-project/summary.md (6489b), README.md (2500b), references/cli.graph-task.md (5797b), references/core-model.md (8835b), references/decomposition-protocol.md (3247b), references/examples.expected-results.json (2590b), references/expected-result.schema.json (1450b), references/md-first-format.md (8709b), references/md-first-vnext-spec.md (13964b), references/obsidian-plugin-mvp-spec.md (6869b), references/phase1-graph-task-spec.md (4454b), references/phase2-obsidian-spec.md (2524b), references/phases.json (4196b), references/result-record.schema.json (790b), references/rules.graph-task.md (6274b), references/run-readiness.md (8930b), references/schema.graph-task.json (5881b), references/test-levels.json (1264b), scripts/graph_task.py (63616b), skill-card.md (2811b), SKILL.md (15292b), tests/test_graph_task_cli.py (18944b), _meta.json (126b)\n\nArchive v0.5.1: 63 files, 87006 bytes\n\nFiles: .gitignore (39b), examples/md-first-minimal/project-alpha/index.md (621b), examples/md-first-minimal/project-alpha/project-log.md (251b), examples/md-first-minimal/project-alpha/steps/step-1/index.md (444b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/index.md (566b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/nodes/node-compare-layout.md (655b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/phase-log.md (150b), examples/md-first-minimal/project-alpha/steps/step-1/phases/phase-diverge-1/results/result-0001.md (864b), examples/md-first-minimal/project-alpha/steps/step-1/step-log.md (109b), examples/md-first-minimal/project-alpha/summary.md (270b), examples/md-first-minimal/README.md (403b), examples/minimal-project/graph.json (3183b), examples/minimal-project/summary.md (1176b), examples/self-dogfood-obsidian-vault/index.md (250b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-commit-findings-1__node-choose-next-improvement.md (940b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-commit-findings-1__phase-commit-findings-1-root.md (603b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-converge-findings-1__node-summarize-findings.md (1042b), examples/self-dogfood-obsidian-vault/nodes/step-followups__phase-converge-findings-1__phase-converge-findings-1-root.md (615b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-commit-execution-1__node-lock-execution-findings.md (982b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-commit-execution-1__phase-commit-execution-1-root.md (621b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-execution-2__node-build-self-dogfood-example.md (1113b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-execution-2__phase-diverge-execution-2-root.md (627b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__node-read-cli-surface.md (940b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__node-read-phase1-spec.md (976b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-diverge-surface-1__phase-diverge-surface-1-root.md (615b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-execution-2__node-validate-self-dogfood.md (960b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-execution-2__phase-verify-execution-2-root.md (621b), examples/self-dogfood-obsidian-vault/nodes/step-self-dogfood__phase-verify-surface-1__node-verify-phase1-usable.md (1046b), examples/self...","readmeExcerpt":"Skill: TaskOps Owner: jimmylegendary Summary: Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution log... Tags: latest:0.5.4 Version history: v0.5.4 | 2026-06-16T11:48:56.544Z | user Add taskops daemon supervisor with user-systemd install/start/status/logs/uninstall lifecycle. v0.5.3 | 2026-06-16T11:07:43.678Z | user ","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"taskops validate <path>\ntaskops summary <path>\ntaskops show <path> --json\ntaskops classify-runnable <work-dir> <task-id> --json\ntaskops next <work-dir> --json\ntaskops explain <work-dir> --json\ntaskops close <work-dir> <run-node-id|task-id> [--reason <reason>] [--json]\ntaskops init <dir> --id <id> --title <title> --objective <objective>\ntaskops vault-init <vault-dir> --repo-url <url> --branch <branch> --auto-sync true\ntaskops git-status <vault-dir>\ntaskops git-sync <vault-dir> --message <message>\ntaskops watch-sync <vault-dir> --debounce-ms 5000\ntaskops decompose <work-dir> --task-group-id <id> --spec <spec.json>\ntaskops refactor <work-dir> --task-group-id <id> --spec <spec.json> --supersedes <version-id>\ntaskops run <work-dir> [--run-id <id>] [--agent <agent-id>] [--executor dry-run|openclaw-agent] [--max-steps <n>] [--until <iso-timestamp>] [--timeout <seconds>] [--loopback none|self] [--max-loopbacks <n>] [--json]\ntaskops queue sync <work-dir> [--json]\ntaskops queue list <work-dir> [--json]\ntaskops queue claim <work-dir> [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--json]\ntaskops queue heartbeat <work-dir> <lease-id> [--ttl-seconds <n>] [--json]\ntaskops queue release <work-dir> <lease-id> [--status done|failed|cancelled] [--json]\ntaskops queue reports <work-dir> [--json]\ntaskops runner once <work-dir> [--runtime dry-run|openclaw-cli] [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--timeout <seconds>] [--report-sink none|ledger|openclaw-chat-inject] [--master-session-key <key>] [--json]\ntaskops runner watch <work-dir> [--runtime dry-run|openclaw-cli] [--runner-id <id>] [--ttl-seconds <n>] [--max-attempts <n>] [--timeout <seconds>] [--report-sink none|ledger|openclaw-chat-inject] [--master-session-key <key>] [--poll-interval-ms <n>] [--max-waves <n>] [--max-idle-cycles <n>] [--idle-exit-after-seconds <n>] [--until <iso-timestamp>] [--continue-on-failure] [--json]\ntaskops daemon run <work-dir> [--name <name>] [--runtime dry-run|openclaw"},{"language":"bash","snippet":"taskops validate <work-dir>\ntaskops summary <work-dir>"},{"language":"bash","snippet":"python3 /home/jimmy/.npm-global/lib/node_modules/openclaw/skills/skill-creator/scripts/package_skill.py <skill-dir> <output-dir>"},{"language":"bash","snippet":"taskops init <work-dir> --id <id> --title <title> --objective <objective>\ntaskops validate <work-dir>\ntaskops summary <work-dir>\ntaskops classify-runnable <work-dir> <task-id> --json\ntaskops run <work-dir> --executor dry-run --max-steps 1 --json"},{"language":"bash","snippet":"taskops validate <work-dir>\ntaskops summary <work-dir>"},{"language":"bash","snippet":"taskops vault-init <vault-dir> --repo-url <github-repo-url> --branch main --auto-sync true\ntaskops git-sync <vault-dir> --message \"Sync vault changes\""}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: taskops\ndescription: \"Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution logs, exploration, delegation/waiting, EoW closure, validation, summaries, and runner-driven progress.\"\n---\n\n# TaskOps\n\nTaskOps is a **work-truth protocol**, not just a task manager. It exists so that AI agents can be trusted with hours/days/weeks of work without pretending tasks are done, silently stopping, asking \"what next?\", or executing a wrong plan. Plans lie, logs drift, and TODO lists make agent work look simpler than it is; TaskOps separates task decomposition from execution reality and forces explicit, file-backed closure.\n\nUse it when the user needs to know what should happen, what actually happened, what is blocked or delegated, and whether work is truly closed.\n\n## Canonical rule\n\nTaskOps v1 is **md-first**.\n\nCanonical state lives in markdown files arranged around:\n- `task-groups/`\n- `snapshots/`\n- `runs/<run-id>/`\n- non-canonical `derived/`\n\nDo **not** treat `.taskops/queue.sqlite`, `graph.json`, or generated canvases as durable semantic truth. SQLite is an execution projection/ledger, not the task graph source of truth.\n\n## Read these first\n\n- `references/core-model.md`\n- `references/md-first-format.md`\n- `references/decomposition-protocol.md`\n- `references/run-readiness.md`\n- `../examples/taskops-canonical-minimal-v1/`\n\n## Current operating model\n\n- Task graph = decomposition truth\n- Run graph = execution truth\n- Work = top-level objective container (`entityType: work`; legacy `project` can still be read)\n- Task groups are versioned\n- Snapshots materialize selected version paths\n- EoW (End of Work) is an explicit terminal node, not just a status field\n- Run graphs are independent under `runs/<run-id>/` and may reference external runs/tasks without being merged\n- Task↔run traceability is bidirectional: task `runRefs` plus run-node `sourceTaskId` / `sourceTaskGroupVersionId`\n- Delegation/waiting belongs in the run graph as `type: delegate` / `status: waiting` with delegatee, request, expected output, and optional timeout metadata\n- Markdown is canonical; canvas/views are derived\n- SQLite queue state is a rebuildable execution projection plus lease/report ledger\n- Shared status vocabulary: `pending | active | done | blocked | waiting | cancelled`\n- Before execution, classify task run readiness as `runnable | needs_decomposition | needs_exploration | blocked`\n- Use `needs_exploration` when the objective is meaningful but the system does not yet know enough to decompose honestly; exploratory runs may search, try, debug, prototype, and reflect to learn constraints for the next graph update\n\n## Decomposition discipline\n\n- Start with a one-line objective.\n- Decompose depth 1 by default.\n- Do not turn decomposition into an activity checklist.\n- A task can be large but not decomposable yet; if the missing knowledge blocks honest decomposition, create an expl"},{"path":"examples/md-first-minimal/README.md","content":"# md-first minimal example\n\nThis example demonstrates the proposed vNext canonical layout where markdown files are the source of truth.\n\nIt intentionally stays tiny:\n- 1 Project\n- 1 Step\n- 1 Phase\n- 1 Node\n- 1 Result\n- log files at each structural level\n\nUse it to pressure-test:\n- folder naming rules\n- YAML frontmatter shape\n- append-only result handling\n- Obsidian navigation\n- future plugin parsing"},{"path":"README.md","content":"# TaskOps skill\n\n**AI agent work cannot be managed as a flat TODO list.**\n\nTaskOps is a markdown-canonical execution control protocol for keeping human + AI work honest: separate the decomposition truth from execution reality, record blockers and delegation explicitly, and only close work when there is visible evidence.\n\n## Canonical shape\n\nTaskOps v1 separates:\n- **work root** at `index.md` with `entityType: work`\n- **task graph** under `task-groups/`\n- **snapshot selection** under `snapshots/`\n- **execution truth** under independent `runs/<run-id>/` graphs\n- **EoW terminal nodes** under task-version `eow/` folders and run `nodes/`\n- **derived views** under `derived/`\n\nMarkdown is canonical.\nDerived canvas/views are not.\n\n## Current surfaces\n\n- `../cli/` — installable `taskops` CLI for `init / validate / summary / show / decompose / refactor / run` plus git-backed vault setup/sync\n- `../obsidian-plugin/` — Obsidian explorer + derived canvas export for TaskOps v1 projects, with desktop git auto-sync support when configured\n- `scripts/graph_task.py` — legacy graph-task prototype kept only as migration/source material\n\n## Main working references\n\n- `../docs/CORE_MODEL.md`\n- `../docs/MD_FIRST_FORMAT.md`\n- `../examples/taskops-canonical-minimal-v1/`\n- `SKILL.md`\n\n## Core operating loop\n\n```bash\ntaskops init <work-dir> --id <id> --title <title> --objective <objective>\ntaskops validate <work-dir>\ntaskops summary <work-dir>\ntaskops classify-runnable <work-dir> <task-id> --json\ntaskops run <work-dir> --executor dry-run --max-steps 1 --json\n```\n\nUse `dry-run` for smoke tests and graph rehearsals. Use `--executor openclaw-agent --agent <agent-id>` when the user wants real agent execution.\n\n## Good fit\n\nTaskOps is strongest for complex agentic work such as refactors, migrations, research-to-implementation loops, and multi-step investigations where the user needs to know:\n\n- what the goal is\n- how it was decomposed\n- what actually ran\n- what got blocked, delegated, or explored\n- why a branch is truly closed\n\n## Validation stance\n\nPrefer the CLI for current validation and summaries:\n\n```bash\ntaskops validate <work-dir>\ntaskops summary <work-dir>\n```\n\nFor a git-backed Obsidian vault workflow:\n\n```bash\ntaskops vault-init <vault-dir> --repo-url <github-repo-url> --branch main --auto-sync true\ntaskops git-sync <vault-dir> --message \"Sync vault changes\"\n```\n\nOnly use the legacy Python script when the work is explicitly about old graph-task compatibility or migration."},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn73mypx9fx9qehs8agyh3drs183bb1y\",\n  \"slug\": \"taskops\",\n  \"version\": \"0.5.4\",\n  \"publishedAt\": 1781610536544\n}"},{"path":"references/cli.graph-task.md","content":"# graph-task CLI surface\n\n> Legacy prototype note: this CLI currently operates on `graph.json` runs.\n> In the md-first direction, treat its outputs as legacy behavior, migration help, or derived snapshots/exports — not canonical markdown state.\n\nUse the bundled CLI with:\n\n```bash\npython3 scripts/graph_task.py <command> ...\n```\n\nAll commands accept either:\n- a run directory (the CLI will use `graph.json` inside it), or\n- a direct path to `graph.json`\n\n## Shared status vocabulary\n\nUse the same minimal status set everywhere:\n- `pending`\n- `active`\n- `done`\n- `blocked`\n- `cancelled`\n\n## Commands\n\n### init\nCreate a new run directory with `graph.json` and `summary.md`.\n\n```bash\npython3 scripts/graph_task.py init ./runs/demo \\\n  --id demo-project \\\n  --title \"Demo project\" \\\n  --description \"Test graph\" \\\n  --goal \"Reach a validated state\"\n```\n\nTo initialize inside a git-backed vault/work repo, point `path` at the desired local checkout directory and pass a repo URL. The CLI will clone or refresh the checkout, then create the run under `<checkout>/<project-id-slug>/`.\n\n```bash\npython3 scripts/graph_task.py init ./tmp/company-vault \\\n  --repo-url https://github.company.com/ORG/obsidian-vault.git \\\n  --repo-branch main \\\n  --id graph-task-demo \\\n  --title \"Graph task demo\" \\\n  --description \"Repo-backed run\" \\\n  --goal \"Write into a project-specific folder\"\n```\n\n### show\nRender the current graph as a summary or raw JSON.\n\n```bash\npython3 scripts/graph_task.py show ./runs/demo\npython3 scripts/graph_task.py show ./runs/demo --format json\n```\n\n### add-step\nAdd a Project-level Step.\n\n```bash\npython3 scripts/graph_task.py add-step ./runs/demo \\\n  --id step-1 \\\n  --step-type implementation \\\n  --description \"Implement state handling\"\n```\n\n### add-step-edge\nConnect two Steps.\n\n```bash\npython3 scripts/graph_task.py add-step-edge ./runs/demo \\\n  --id step-edge-1 \\\n  --from-step step-1 \\\n  --to-step step-2\n```\n\n### add-phase\nAdd a Step-level Phase and automatically create its root node.\n\n```bash\npython3 scripts/graph_task.py add-phase ./runs/demo \\\n  --step-id step-1 \\\n  --id phase-diverge-1 \\\n  --phase-type diverge \\\n  --description \"Explore implementation options\"\n```\n\n### add-phase-edge\nConnect two Phases inside a Step.\n\n```bash\npython3 scripts/graph_task.py add-phase-edge ./runs/demo \\\n  --step-id step-1 \\\n  --id phase-edge-1 \\\n  --from-phase phase-diverge-1 \\\n  --to-phase phase-verify-1\n```\n\n### add-node\nAdd a work node to a Phase.\n\n```bash\npython3 scripts/graph_task.py add-node ./runs/demo \\\n  --phase-id phase-diverge-1 \\\n  --id node-1 \\\n  --title \"Compare libraries\" \\\n  --description \"Check Zustand and Redux\"\n```\n\n### add-edge\nConnect two Nodes inside a Phase.\n\n```bash\npython3 scripts/graph_task.py add-edge ./runs/demo \\\n  --phase-id phase-diverge-1 \\\n  --id edge-1 \\\n  --from-node phase-diverge-1-root \\\n  --to-node node-1 \\\n  --edge-type flow\n```\n\n### set-status\nSet the status on a Project, Step, Phase, or Node.\n\n```bash\npython3 scripts/graph_task.py set-sta"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution log... Skill: TaskOps Owner: jimmylegendary Summary: Manage AI-agent work as an execution graph instead of a flat TODO list. Use TaskOps to structure objectives, task decomposition, run readiness, execution log... Tags: latest:0.5.4 Version history: v0.5.4 | 2026-06-16T11:48:56.544Z | user Add taskops daemon supervisor with user-systemd install/start/status/logs/uninstall lifecycle. v0.5.3 | 2026-06-16T11:07:43.678Z | user","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1490,"uniquenessScore":48,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T07:09:25.773Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T07:09:25.773Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:50:20.118Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}