| name | mxOrchestrate |
| description | Persistent session orchestrator for mxLore. This skill should be used when the user says "park", "resume", "continue", "keep going", "where were we", "pick up where we left off" (non-English phrasing with the same meaning maps to these triggers), "what's my workflow status", "/mxOrchestrate start/track/park/resume/status/suggest", "start a new feature/bugfix workflow", "track this as ad-hoc", "spawn a team agent", or when a session begins and workflow state must be loaded. Always-on via SessionStart/UserPromptSubmit hooks. Manages workflow stack (LIFO), ad-hoc tasks, team agents, and skill chains. |
| user-invocable | true |
| allowed-tools | Read, Write, Edit, Grep, Glob, Skill |
| argument-hint | start <type> | track <note> | park [reason] | resume [id] | status | suggest |
/mxOrchestrate — Persistent Session Orchestrator (AI-Steno: !=forbidden →=use ⚡=critical ?=ask)
Context ⚡ (split by mode weight): HEAVY modes (init, resume with a non-empty stack, status, suggest — briefing, reconciliation, multi-doc enrichment) → subagent (Agent-Tool, model per Model Tiering). MINI modes (start, track, park, resume with an empty stack, Auto-Invoke step-updates, Workflow Completion — 1-3 MCP calls + 1 state edit) → Main-inline, NO spawn: a spawn re-reads SKILL.md + references + the full state file (~70-100k subagent tokens measured live 2026-07-10) for 2-3 calls; the same calls inline cost ~2k. Context-hygiene argument does not apply at that size. Subagent result: max 20 lines.
⚡ Init Pre-Routing runs in Main, NEVER inside a HEAVY subagent: the session-ensure + context_cleared_at/context_cleared_source clear (Init step 3) is a reliability-critical 1-field state edit. A HEAVY subagent that owns it can silently drop it and still report success (observed live 2026-07-14: the flag survived a resume → re-briefing fires on every later call). Main runs Init (ping / mx_session_start + flag-clear + verify the clear landed in the file), THEN dispatches only enrichment/reconciliation to the subagent, passing session_id + the cleared state.
⚡ Empty-stack resume = MINI (Main-inline, NO spawn): workflow_stack == [] has no WF to reconcile — Mode 5 collapses to mx_detail(last_save_session_note_doc_id) + one mx_search + a resume event (2-3 calls). A HEAVY subagent for that cost ~142k tokens live 2026-07-14 to return 20 lines. Only stack-pop / ID resume (real reconciliation) stays HEAVY.
Tokens ⚡: mx_create_doc/mx_update_doc body >300 words → assemble in subagent, !echo to parent. mx_detail server default = 600 tokens.
Central session manager. Manages workflow stack, ad-hoc tasks, team agents.
Skills auto-execute fully. Only ask user for optional steps.
Trigger phrases
This skill fires on:
/mxOrchestrate start <type>, /mxOrchestrate track <note>, /mxOrchestrate park, /mxOrchestrate resume [id], /mxOrchestrate status, /mxOrchestrate suggest
- Natural language: "park this", "resume my workflow", "what's my workflow status", "start a new feature/bugfix", "track this as ad-hoc", "spawn a team agent for X"
- Automatic: SessionStart, UserPromptSubmit (every prompt, 3-line context), [DORMANT] PreCompact/PostCompact (see
references/hooks.md for reactivation path)
Init (Pre-Routing, EVERY call)
- CLAUDE.md parse: if file missing OR no
**Slug:** line is present → ?user. If **Slug:** line is present → use that value as project slug.
- Load state:
.claude/orchestrate-state.json→parse. ∅file or corrupt→mode init
- Ensure session:
- ⚡ Context-reset FACT (primary signal):
state.context_cleared_at is set by the SessionStart hook (orchestrate-reconcile.js) whenever source ∈ {startup, clear, compact} — the three cases where the model has no prior conversation. source=resume restores context and does NOT set it. Field present → context is empty → mx_session_start unconditionally, then delete context_cleared_at + context_cleared_source in the same state write (the briefing has now happened; leaving it set re-briefs on every later call). ⚡ Main-owned + verify-after-write: this clear runs in Main (see Context header), and after the state write Main MUST re-read the field from the file to confirm it is gone — a subagent's report of "cleared" is NOT proof (observed dropped live 2026-07-14, flag survived). Still present → re-issue the Edit, re-verify.
- Staleness check (ADR-0016) — FALLBACK ONLY, for installs whose hook predates the fact:
age = now_utc - max(state.last_save, state.last_reconciliation) — ⚡ all three in true UTC (date -u), see references/state-schema.md → Timestamp base; mixing a local now with a UTC field (or the reverse) shifts age by the UTC offset and can make it negative. Both fields missing → treat as stale. Threshold: 12h. ⚡ This heuristic answers "is my STATE old", never "is my CONTEXT empty" — a save one minute before /clear leaves a fresh state and an empty context, and any same-day restart falls under 12h. Use it only when context_cleared_at is absent.
- ⚡ Explicit-trigger fail-OPEN: input contains
<command-name> OR <command-message> tag OR detection ambiguous → mx_session_start regardless of age (slash invocations need fresh briefing in fresh Claude process; live-confirmed tag injection at prompt position 0). Fresh briefing > stale ping.
- hook-triggered (no command-tag) AND ∅
context_cleared_at AND state.session_id present AND mode≠init AND age < 12h → mx_ping()→OK=MCP-mode | Error=Local
context_cleared_at present OR ∅session_id OR mode=init OR age ≥ 12h (STALE) → Setup version: ~/.claude/setup-version.json→parse→version. ∅file→''
→ mx_session_start(project, include_briefing=true, setup_version=<version>)→session_id (overwrite cached)+Response into state, state.last_reconciliation ← now_utc (date -u +%Y-%m-%dT%H:%MZ, Timestamp base), clear context_cleared_at/context_cleared_source
→ Error=Local(docs/ops/workflow-log.md+warning)
- ⚡ The hook must NEVER stamp
last_reconciliation — that field means "reconciled against MCP", and JS hooks cannot reach MCP. Stamping it there resets the very signal the fallback reads.
- Auto-Detect: Project Setup (see below)
- → Mode routing by argument
Auto-Detect: Project Setup
Runs in pre-routing after session setup. 0 extra MCP calls — uses mx_session_start response + up to 2 Globs. Checks CLAUDE.md presence, MCP project registration, local migration candidates. Full decision tree → references/auto-detect.md. ⚡ Only suggests, never auto-executes.
Modes
| Argument | Mode |
|---|
init | 1: Initialize state from MCP |
start <type> (new-feature, bugfix, decision, <custom>) | 2: Start workflow (stack push) |
track <note> | 3: Log ad-hoc task |
park [reason] | 4: Park active WF (stack push-down) |
resume [id] / --resume | 5: Resume WF (stack pop / ID select) |
status | 6: Full overview |
suggest | 7: Suggest next step |
Tool Budget per Mode
⚡ Stay surgical: 0-2 MCP calls per mode, 1 Edit per state write, NEVER full-rewrite state from main ctx.
Model Tiering ⚡ (Cost Discipline)
Main loop on premium model (Fable/Opus) → every subagent spawn (Agent-Tool, team agents, checker runs) sets the model param to the cheapest tier that satisfies the task. Match model to task floor, !ceiling:
| Tier | model | Task profile |
|---|
| haiku | haiku | mechanical: state-file rewrites, file copy/sync, log tails, doc-body assembly from given content, simple greps |
| sonnet | sonnet | DEFAULT for subagents: mxOrchestrate HEAVY modes (init/resume/status/suggest), MCP CRUD flows, mxBugChecker/mxDesignChecker standard scope, Explore/codebase-search, standard implementation steps. MINI modes spawn nothing (see Context header) — the cheapest spawn is no spawn |
| inherit | omit param | top-tier reasoning genuinely required: architecture decisions, security-critical analysis, cross-cutting refactors, ambiguous specs |
- ⚡ Orchestration intelligence (skill routing, escalation judgment, interpreting results) lives in the MAIN loop (premium model) — the /mxOrchestrate subagent executes a fully specified procedure (state CRUD, fixed decision trees), so
sonnet suffices. Ambiguity safety net: diverged state / code-vs-doc conflict → STOP + ?user regardless of model.
- Main model ∈ {fable, opus*} → subagent default =
sonnet. Omitting model (inherit=premium) requires 1-line justification in the spawn rationale (written into the Agent-tool prompt or the caller's status text).
- Main model already sonnet/haiku → omit
model (inherit, no tiering gain).
- !premium subagents for mechanical work — token+cost efficiency over convenience.
State File (.claude/orchestrate-state.json)
Schema v2, stack rules, and internal operations → references/state-schema.md. Key invariant: last_save_deltas is owned by mxSave Step 4 (SSoT, the single-writer rule). All state writes follow Edit-vs-Write discipline (see Tool Budget table above + Rules section).
Mode 1: Init
Forces mx_session_start ignoring cached session_id (see Init pre-routing step 3); loads workflows from the response into workflow_stack; resets events_log. Multi-Agent Auto-Listener: response contains active_peers -> /mxAgentListen background agent.
Mode 2: Start (Create workflow)
- Search workflow template:
docs/workflows.md(project) then ~/.claude/skills/mxOrchestrate/workflows.md(global). ∅template→?user→ad-hoc
- ID:
WF-YYYY-MM-DD-NNN
mx_create_doc(project, doc_type='workflow_log', title='WF-...: <Title>', content)
- Push WF object onto stack (becomes [0] = active). Previous [0]→parked (if present). ⚡ Event
ts = true UTC via date -u +%Y-%m-%dT%H:%MZ — NEVER the chat clock (local-time-with-Z observed live 2026-07-10 despite the state-schema rule; inline reminder because spawn prompts skip references)
- ⚡ Canonical keys (
references/state-schema.md): id, name, doc_id, doc_revision, status, current_step, total_steps, started, unsynced. NOT wf_id / title. The SessionStart hook normalizes those two, but a workflow missing id after normalization is DROPPED from the stack — writers must not rely on the repair.
- Save state + log event (type='start')
- Output:
Workflow "<Name>" started (WF-xxx, doc_id=<id>). Stack: <N> WFs.
- Auto-invoke first step
WF Markdown (MCP):
**Template:** <name> | **Started:** YYYY-MM-DD HH:MM | **Status:** active
| # | Step | Skill | Status | Result | Timestamp |
|---|------|-------|--------|--------|-----------|
| 1 | <Description> | <Skill> | pending | | |
Mode 3: Track (Ad-hoc Task)
- Push
{note, created, origin_workflow: stack[0].id, mcp_note_id} to adhoc_tasks[] + mx_create_doc(doc_type='todo', title=note, content='Origin: <WF-ID>'). Log event (type='track_adhoc').
- Escalation (Claude decides): note (default) | park+start (Mode 4 + Mode 2) | spawn (see
references/team-agents.md).
- Full step list ->
references/adhoc.md.
Mode 4: Park
- Stack[0].status = 'parked', Stack[0].parked_reason = reason
- ⚡ Check stack depth: >3 parked→warning + suggest completing oldest
- Log event (type='park')
- Save state
- Output:
WF "<Name>" parked. Reason: <reason>. Stack: <N> WFs.
- ∅new WF started→invoke suggest mode
Mode 5: Resume
⚡ Weight routing (see Context header): empty-stack resume (workflow_stack == []) runs Main-inline, NO spawn — step 5's reconciliation is a no-op (nothing to reconcile), leaving only Step 6 enrichment + the resume event (2-3 MCP calls = MINI weight). Stack-pop / ID resume keeps the HEAVY subagent (real WF reconciliation). Init Pre-Routing (session-ensure + flag-clear + verify) already ran in Main before this point either way.
- Without ID: Stack LIFO — bring top parked WF (stack[1]) to [0]
- With ID: Find WF by ID in stack→move to [0], shift rest down
- WF.status = 'active'
- Log event (type='resume')
- ⚡ Reconciliation (Session-Boundary Sync):
mx_detail + compare local vs MCP, push/pull whichever is ahead, handle archived; diverged → STOP + ask user which version to keep (NEVER silently overwrite); clamp; then the ⚡ FS-Anchor Post-Check — verify any pending step against the real filesystem (structured target paths → Glob, Grep only on a named symbol); code contradicts doc → STOP + ?user; ∅ structured paths → mark result unverified against code. Set state.last_reconciliation = now_utc (date -u +%Y-%m-%dT%H:%MZ, Timestamp base). Full decision tree + FS-anchor algorithm → references/reconciliation.md.
- ⚡ Context-Note Enrichment (the context-note enrichment rule) — MANDATORY, NEVER SKIP, BOTH PATHS:
- Stack-pop path (stack >= 1):
mx_search(project, doc_type='session_note', query='<WF-ID> OR <primary_artifact_IDs> OR <outcome-keywords>', limit=4) — ALWAYS runs, recency-ordered (updated_at DESC). Hit -> mx_detail(note_id, max_content_tokens=1500). 0-hit is valid, NOT a reason to skip. Outcome-keywords + limit rationale → references/resume-enrichment.md.
- Empty-stack path (stack = []): unconditional
mx_detail(state.last_save_session_note_doc_id) if set + mx_search(doc_type='session_note', limit=4) fallback. Both paths run Step 6.
- ⚡ independent enrichment calls (mx_search + mx_detail on last_save_session_note_doc_id / primary_artifact) → parallel in one message !sequential
- Event-log marker (mandatory both paths): resume event MUST include
context-note=<note_id> or context-note=none in detail. Missing = rule violation. wf=null for empty-stack path, wf=<WF-ID> for stack-pop.
- unbacked-decision tag detect: after primary_artifact
mx_detail, inspect tags for unbacked-decision; if present, regex-scan body via shared regex (Read ~/.claude/skills/_shared/decision-marker.md). Store {tag_present, marker_count, spec_id} for Step 8 rendering.
- Full prose / rationale / unbacked-decision render-rules ->
references/resume-enrichment.md.
- Identify next pending step from reconciled state
- Output assembly:
- Line 1:
WF "<Name>" resumed. Progress: <X>/<Y>. Next step: <Description>.
- unbacked-decision warning (rendered between Line 1 and bullet-summary when
tag_present AND marker_count > 0; full render-rules incl. stale-tag guard -> references/resume-enrichment.md).
- 2-3 bullet summary of any session-note enrichment from step 6.
- see Rules: state_deltas band
- Auto-invoke next step
Empty-Stack Resume invariant (the context-note enrichment rule): --resume without active stack still loads the open-items list, AND Step 6 + events_log resume-event are STACK-INDEPENDENT and STILL RUN (unconditional mx_detail on last_save_session_note_doc_id + mx_search fallback + wf=null resume-event with context-note=<id|none>). Full detail -> references/resume-enrichment.md.
Load context (on --resume without stack)
MCP: (Session+Briefing already available from pre-routing)
- Open items:
mx_search(project, doc_type='note,bugreport,feature_request', status='active')
- Filter: Tags
todo,bug,feature-request,optimization,next,later or without session_note/e2e/test
- ⚡ NO _global search (_global only for env variables, not for open items)
- ⚡
status='active' — DO NOT show archived/completed docs
- Open plans/specs:
mx_search(project, doc_type='plan,spec', status='active', limit=10)
- Show only title+doc_id, not full content
- status.md: "Known open items"→all bullets. "Next steps"→only
- [ ]
- ⚡ Deduplicate against MCP: item in status.md already archived in MCP→remove from display
- Result: Open-items list (deduplicated, Bug→TODO→Feature→Opt→Other, max 30)
- ⚡ FR-aging marker: items older 7d (per
days_since_content_change from the mx_search row — the updated_at staleness defect; NOT updated_at, which any touch incl. access_count-on-read rejuvenates) get suffix (>7d — re-audit claims before build) — apply BEFORE the max-30 truncation so low-ranked stale items stay visible; stale FRs frequently describe already-shipped work. Older server without the field → fall back silently (no marker rather than a false-fresh one)
Mode 6: Status
Full overview:
- Workflow Stack: ID|Name|Step|Status for each entry
- Ad-hoc Tasks: Note|Origin|Created
- Team Agents: Task|Status|Origin
- Events (last 10): Timestamp|Type|Detail
- Active MCP Docs:
mx_search(project, doc_type='workflow_log,plan,spec', status='active')→show only open
- Recently archived:
mx_search(project, doc_type='workflow_log,plan,spec', status='archived', limit=5)→last 5 completed
- Open items: MCP-Notes(status='active') + status.md (deduplicated against MCP)
- Save signal: see Rules: state_deltas band
Mode 7: Suggest
- Active WF→next step
- Parked WFs→suggest oldest
- Ad-hoc tasks→prioritized: Bug→TODO→Feature→Next/Later
- ∅stack→open-items list + chat heuristic: ADR→/mxPlan | Plan→Impl | Code→/mxDesignChecker | long session→/mxSave
Team Agents (Ad-hoc Escalation: spawn)
TeamCreate is deferred (load via ToolSearch select:TeamCreate before first spawn). Isolation: team agents have MCP-only access, never orchestrate-state.json. Full spawn flow + return-flow -> references/team-agents.md.
Auto-Invoke (all workflow modes)
- Non-optional auto-execute -> step
done + state update + log event. Optional -> ?user (skip -> skipped). Conditional -> check, no match -> skipped.
- Analysis skills (mxDesignChecker, mxBugChecker) -> Agent-Tool (
model per Model Tiering ⚡). Other mx*/superpowers:*/frontend-design -> Skill-Tool. Independent steps -> parallel via Agent-Tool.
- ⚡ MCP-First Step-Update (the MCP-first step-update spec):
mx_update_doc(doc_id, content with Step=done+Timestamp+Result, change_reason='Step N→done') → MCP first
- Derive state file from MCP response: current_step++, push event to events_log (synced=true)
- state_deltas++
- MCP error→ Write state file directly + set
unsynced=true on WF + event (synced=false)
- ⚡ NEVER mark state file as done without MCP update or unsynced flag
Workflow Completion
Runs Main-inline (MINI mode — see Context header). All steps done/skipped:
- Update content:
**Status:** completed + **Completed:** YYYY-MM-DD HH:MM — ⚡ all timestamps (content + event ts + archive completed) in true UTC via date -u, never the chat clock
- ⚡
mx_update_doc(doc_id, content, status='archived', change_reason='Workflow completed') — content AND status synchronously in ONE call
- Remove WF from stack + log event (synced=true)
- Ad-hoc back-link: Show all adhoc_tasks with origin_workflow==WF-ID:
N ad-hoc tasks created during <WF-ID>: [list]. Start new workflow?
- Log event (type='completed')
- Activate next stack WF if present
- Output: Artifacts list + ad-hoc back-link + recommend
/mxSave
Auto-Tracking
- Rule 1 (NO_WORKFLOW + substantive work): auto-create ad-hoc WF (template
ad-hoc, title Ad-hoc: <50char>). Ignore for questions/smalltalk/mxSave/mxOrchestrate.
- Rule 2 (WF active + topic deviation): small deviation -> auto
track as ad-hoc task; large deviation (>1 step) -> suggest park.
- Rule 3 (JUST_COMPLETED + continued work, <5min): create new ad-hoc WF.
- ⚡ Precedence: Rule 3 wins over Rule 1 (continuation under new ad-hoc WF, not double-tracked). Rule 2 is mutually exclusive with Rules 1+3 (only fires when a WF is already active).
Rules
- Auto-invoke skills via Skill/Agent-Tool. !manually by user
- Optional→?user. Non-optional→without confirmation
- ⚡ Max 5 stack entries. State-deltas>=8→recommend save
- ⚡ Team agents: MCP access only, never local state file
- UTF-8 without BOM. Prefer MCP, local=fallback
- Workflow templates:
docs/workflows.md(project, priority) then ~/.claude/skills/mxOrchestrate/workflows.md(global)
- ⚡ Token Discipline (state-file): orchestrate-state.json writes: Edit for incremental changes (1-5 fields), background subagent for full rewrites — keep token cost low in main context
- ⚡ Output discipline: structured timestamps only (
YYYY-MM-DD HH:MM or <N>h ago from now_utc - event.ts, both UTC per Timestamp base — ⚡ events_log entries predating the UTC rule are local-time-with-Z and render <N>h ago off by the UTC offset; they are indistinguishable from correct ones, so print the raw ts whenever the exact age carries weight); events_log[*].detail = factual fragment (doc_ids/WF-IDs/short summaries), max ~50 words — the long narrative belongs in the MCP session note, NOT in the state file that every subagent spawn reads in full (300-word details measured as the top token driver 2026-07-10); no relative natural language (gestern/heute/vorhin/yesterday/today/earlier/just now); numeric claims (N open, X/Y done) MUST come from a structured tool call (mx_detail / mx_search data array length), never prose-snippet inference — prefix estimated, unverified if budget forbids verification. Per-finding rationale -> references/output-discipline-findings.md.
- ⚡ events_log dedupe-guard: before appending an event, compare with the current LAST entry — identical (type+wf+detail) → skip the append (consecutive-duplicate guard)
- ⚡ Decision-Marker shared regex: Read
~/.claude/skills/_shared/decision-marker.md for the canonical regex + fence-exclusion algorithm.
- ⚡
state_deltas band (canonical, the live-counter correction + the single-writer rule (SSoT)): every Mode 5 (Resume), Mode 6 (Status), and Auto-Invoke step-done output MUST emit a deltas-band line based on state.state_deltas (live counter since the last /mxSave reset — NOT state.last_save_deltas, which is a pre-reset snapshot owned by mxSave Step 4 per the single-writer rule and MUST NOT be written from here). Bands: == 0 silent; >= 1 AND < 10 marketing mxLore knows - /mxSave keeps context alive across /compact + /clear; >= 10 AND < 15 tip <N> deltas since save - consider /mxSave soon; >= 15 compact-question <N> deltas since save - /mxSave + /compact cycle recommended. mxOrchestrate reads state_deltas + last_save_deltas (informational); NEVER writes either — mxSave is the sole writer per the single-writer rule.
- ⚡ Tracker-gap guard: Mode 5 (Resume) with
state_deltas == 0 AND MCP available → mx_session_delta(project, since=state.last_save, limit=50); total_changes > 0 → emit <N> MCP writes since last save (tracker gap — subagent writes bypass the counter) - /mxSave recommended instead of the silent band. Counter-blind MCP writes must not produce a false "all saved" signal. ⚡ limit=50, NOT 1: <N> is printed as a MAGNITUDE. Servers before the COUNT(*) fix cap total_changes at limit, so limit=1 would always print "1 MCP writes" regardless of the real count.
- ⚡
since must be true UTC (references/state-schema.md → Timestamp base). The server reads the Z as UTC and converts into DB-local time; a local timestamp labelled Z pushes the cutoff UTC_OFFSET hours into the future and the guard returns a false total_changes=0. mx_session_delta echoes the cutoff it actually used — when the echoed since disagrees with what was sent, the timestamp base is wrong, not the data.
- ⚡ Never report
0 from a future cutoff. Before trusting a 0, compare state.last_save against date -u +%Y-%m-%dT%H:%MZ. last_save in the future → it is mislabelled local time: emit last_save is not UTC (state file corrupt) - tracker-gap guard cannot verify; /mxSave recommended instead of the silent band. A broken guard must fail loud, not report "all saved".