Move task-manager claim and start state out of task frontmatter into manager registry
Problem
Stop relying on task frontmatter mutations like started_at and in_progress claims for manager-driven dispatch. Keep task files as planning and durable completion records, but store pickup/claim/start runtime state in the task-manager registry/snapshot so dispatch does not create merge conflicts. Define the exact semantics for not_started vs ready vs claimed vs completed, update heartbeat/serve UI, and preserve compatibility during migration.
Context
- We already proved that
started_at,in_progress, and mid-flight PR metadata churn on root task markdown files creates merge conflicts when: - the task branch also updates its own task file
- manager-side operators edit the same task on
main - task text evolves after work already started
- The intended model is:
- task frontmatter keeps durable planning intent (
ready) and final durable records (completed, completion metadata) - manager registry/register/snapshot files keep ephemeral runtime execution
state (
claimed,worker_running,started_at, retry state) - This task should make that model explicit enough that operators stop treating root task files as the live runtime ledger for active work.
Possible Solutions
- Recommended: keep
readyin task frontmatter as queue intent, but move claim/start/runtime state into manager registry files keyed by task slug and owner. Do not require root task markdown rewrites during dispatch. Only write final durable completion metadata back when the task actually lands. - Keep all status fields in task files and just “be more careful.”
- Rejected: this is exactly what has been creating merge conflicts on active tasks and does not scale with multiple concurrent branches.
Plan
- Define explicit state semantics for:
-
not_started-ready- runtime claimed/started state in registry -completed - Update heartbeat/dispatch/register code so manager-owned dispatch reads/writes runtime state in registry files rather than task frontmatter.
- Update tasks server / status UI so active runtime state comes from snapshot / register data and is not inferred from root markdown alone.
- Keep compatibility for existing task files during migration, but bias new
manager flows away from
started_atmutation. - Document the operator rule: if a task is already running, do not keep editing
that root task file on
main; update the active worktree or create a follow-up task instead.
Implementation Progress
- 2026-03-24: Clarified the target model after repeated merge conflicts on active task markdown files. This task now explicitly treats root task files as durable planning/final-record documents and manager registry files as the live runtime source of truth.
- 2026-03-24: Implementation complete.
task_manager_lib.py:collect_tasks()now readsstarted_atfrom the register entry (started_atfield, falling back tolaunched_at) instead of task frontmatter.snapshot_payload()includesstarted_atin each task record.task_cli.py:task_update()no longer writesstarted_atto frontmatter when transitioning toin_progress.task-manager-heartbeat: Removed--mark-started-on-dispatchflag and associatedTASK_MANAGER_MARK_STARTED_ON_DISPATCHenv var. Register entries now includestarted_atalongsidelaunched_atandregistered_at.SKILL.md: Updated to reflect that heartbeat never mutates task frontmatter.- Tests: 6 new tests covering registry-sourced
started_at, snapshot inclusion, dispatch register entry, and flag removal. Replaced 2 existing tests.
QA Exploration
N/A — pure infra/task-system change with no UI surface.
- [x] QA exploration completed (or N/A for non-UI tasks)
Review Feedback
- [ ] Review cleared