state-sync
Persist in-progress task state so it survives laptop close, model swap, coworker handoff, and parallel sessions β and so the state is mirrored in both trackers at once. This is the write side of State Management; the read/reconcile side lives in /continue steps 2β3.
The tracker split (from architecture Β§6 / ProductβR&D handoff):
- ClickUp = the product board. Product tasks, priorities, statuses, business context. The unit PMs/sales/support/management see and report on in the daily. (May move to Jira later β keep the mirror logic tracker-agnostic.)
- GitHub Issues = the software breakdown R&D does on a product task β one Issue per PR-sized chunk, holding the implementation plan + working state. The stuff Product doesn't need to see.
The two must stay linked both ways so Claude (and humans) can always answer "which ClickUp task does this GitHub Issue belong to, and vice versa."
The mirror is conditional, not 1:1. A GitHub Issue exists only when a task had real software decomposition (ProductβR&D handoff β "when NOT to create an Issue"). For a small ClickUp-only task with no Issue, there is nothing to mirror to β ClickUp is the whole record; state-sync simply updates the ClickUp
ai_context(no GitHub side). Only run the GitHub-side steps below when an Issue actually exists; never create an Issue just to have a mirror.
When this runsβ
state-sync is always silent β persisting state is never gated (state_sync_update β never_ask, autonomy-model.md). Trigger it at every checkpoint:
- Phase change in the autonomous loop (e.g. planning β implementing β PR open).
- Every ~3 commits, or when meaningful work has accumulated.
- Before likely context-window pressure (long session), so nothing is lost on compaction.
- On pause / handoff /
/doneβ flush a final state.
The state-management spec targets a background flush every 30 min / 3 commits. Until a true background runner exists, state-sync fires at the checkpoints above (invoked from
/continuesteps 8 and 12). It degrades to "flush now at this checkpoint" β never a skipped write, never a placeholder.
Stepsβ
1. Build the AI Context block (authoritative β GitHub Issue)β
Assemble the structured block defined in state-management.md. Required fields: Active actor, Phase, Last updated (ISO 8601, UTC), Plan (with done/in-progress/pending), Files touched, Decisions, Blockers, Next step. Half a block is worse than none β fill every field or mark it explicitly (Blockers: none), never a placeholder.
2. Write it to the GitHub Issue bodyβ
Update the Issue body's ## AI Context (updated by Claude β do not edit manually) section (replace the existing block, preserve the rest of the body). /breakdown seeds this heading empty when it opens the Issue β but if the section is absent (Issue not created by /breakdown, or pre-dates the seeding convention), append it rather than failing; never assume it already exists. This is the source of truth. Use the GitHub MCP issue-update tool (issue_write). The Issue carries the parent CU-id (label + body) β confirm it's present; if missing, add it so the GitHubβClickUp link holds.
3. Mirror a condensed version to ClickUp (the management view)β
Write a condensed ai_context to the linked ClickUp task's custom field so PM/management dashboards see progress without GitHub Issue access:
- Resolve the field by NAME, never a hardcoded id. Call
clickup_get_custom_fields(scoped to the task's list/folder/space) and find the field whosenameis exactlyai_context. Resolving by name is what makes this portable across workspaces/repos β no per-environment field id baked into the skill. - If found, write a 3β5 line gist via
clickup_update_taskwithcustom_fields: [{ id: <resolved-id>, value: "<gist>" }]β phase, next step, blockers, PR link if open. - If no
ai_contextfield exists on the task's scope (a workspace that hasn't been set up with it), skip the mirror and say so in one line ("ClickUpai_contextfield not found β skipped the management mirror; GitHub Issue remains source of truth"). Do not create the field (no MCP tool does so) and do not fail the sync. Setup: an admin creates oneai_contextText field at the R&D space scope; see state-management.md. - This mirror is never the source of truth β it is derived from step 1 every time. ClickUp writes are slower/rate-limited; if it fails, the GitHub write still stands and the mirror retries on the next checkpoint.
Gist format (English; it is an artifact):
Phase: <phase> β <n/m subtasks done>
Next: <one-line next step>
Blockers: <none | description>
PR: <owner/repo#NN (draft|open)> | none
Updated: <ISO 8601 UTC> (by Claude)
4. Maintain the bidirectional linkβ
Ensure the link is resolvable from both sides β establish whichever is missing (idempotent; don't duplicate):
- GitHub Issue β ClickUp: the CU-id on the Issue (label/body) names the ClickUp task.
- ClickUp β GitHub Issue: the Issue URL is on the ClickUp task β as a comment (
clickup_create_commentwithentity_type: "task",entity_id: <task-id>) the first time, and/or theai_contextmirror's PR/issue link./breakdownseeds this when it creates the Issues; state-sync repairs it if absent.
5. Update the local cache (when present)β
If .claude/session/active-context.json exists in the cwd repo, write the same state with its Last updated timestamp, so same-session resume is sub-second. The cache is convenience only and never wins a tie (see the reconciliation algorithm in state-management.md).
The
active-context.jsoncache is optional infra. If it isn't present, skip this step and rely on the GitHub Issue body as authoritative β state the cache step was skipped.
Boundariesβ
- Never gated, never noisy. Silent background-class write; do not pause for approval.
- GitHub Issue body is authoritative. ClickUp
ai_contextand the local cache are derived mirrors β recomputed from the block each run, never read back as truth. - Never invents state. A field with no real value is
none, not a guess. - Does not reconcile β that's
/continue(read side). state-sync only writes the current session's state outward to both trackers.
Cross-referencesβ
- State Management β the spec this implements (block format, layers, reconciliation).
/continueβ invokes state-sync at steps 8 (checkpoints) and 12 (final flush); owns the read/reconcile side at steps 2β3./daily-summaryβ consumes the mirrored state across tasks to produce the standup / progress digest./breakdownβ seeds the GitHub Issue β ClickUp link state-sync then maintains.- autonomy-model.md β
state_sync_updateβnever_ask.