跳到正文
cccskills
免费在 GitHub 公开

dispatcher

Use when you want the orchestrator to pick the next repo to work on across your whole portfolio — it enumerates candidate repos below the confinement root, resolves free/busy from each repo's session.lock lease, ranks the FREE ones by backlog priority × staleness × readiness, recommends the single most worthwhile one via AskUserQuestion, atomically claims it, and routes you to the chosen entry command. Triggers: "what should I work on next", "dispatch me to a repo", "pick the next project", "run /dispatcher". <example>Context: operator finished a session and wants the next-best repo across the portfolio. user: "/dispatcher" assistant: "Ranked 18 free repos — top recommendation: Pencil-Designs (score 4.50, 90d stale). Confirm via the picker, I'll claim its lease atomically, then route you to /session deep."</example>

中文简介正在准备中。当前显示原文说明。

Kanevry/session-orchestrator星标 52(GitHub 52 + cccskills 0)
集成工具GitLab

实测评分 未实测

查看安装方法

包含的文件(1)

  • SKILL.md22.2 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Dispatcher Skill

Cross-repo autopilot front-door — enumerate → rank → owner-AUQ → atomic claim → route. Read-only until the operator confirms; the only mutating step is the atomic session.lock claim, and it happens BEFORE any launch.

Invocation

Invoked as /dispatcher [--dry-run] [--repo <name>] with arguments: $ARGUMENTS.

Parse $ARGUMENTS before doing anything else. The recognized flags are exactly those of the CLI table below and are passed straight through to scripts/lib/dispatcher/cli.mjs:

  • --dry-run — run the non-mutating rank only; print the recommendation and the free-candidate table; do NOT claim any lease (skip Phase 3).
  • --repo <name> — limit the human-readable output to a single repoName (informational; does not change ranking).
  • --start-dir <path> — override the scan root (defaults to the confinement root).
  • --json — emit the full { candidates, free, ranked, warnings, recommended } object to stdout.

If $ARGUMENTS contains an unrecognized flag (starts with -- but is not one of the above), inform the user:

Unknown flag '<flag>'. Recognized flags: --dry-run, --repo <name>, --start-dir <path>, --json.

Then continue with the remaining valid arguments.

Soul

The dispatcher answers one question: "of all my repos, which is the most worthwhile to work on right now, and is it free?" It scans the confinement-root children, resolves each repo's free/busy status from its session.lock v2 lease (same lease semantics as the vault-status board), ranks only the FREE ones by priority × staleness × readiness, and recommends the single best one. You confirm via a picker, it claims the lease atomically (winning the race or excluding-and-re-ranking on a loss), then routes you to the entry command for that repo. Busy repos are listed-as-such, never selected.

When to use

  • You just finished a session and want the orchestrator to pick the next-best repo across your whole portfolio.
  • You want a ranked, free/busy-aware view of every candidate repo before committing to one.
  • You want the atomic claim handled for you so two parallel sessions never both grab the same repo.

When NOT to use

  • Single-repo work where you already know the target — just run /session, /plan, or /discovery directly in that repo.
  • A cross-repo read-only health dashboard (open issues/MRs/CI per repo) — that is /portfolio (gitlab-portfolio), not the dispatcher.
  • Writing issues/MRs back to GitLab/GitHub — use gitlab-ops.
  • Inside a subagent — the dispatcher is coordinator-only because Phase 2 uses AskUserQuestion (unavailable in dispatched agents; see .claude/rules/ask-via-tool.md AUQ-004).

Phase 1: Enumerate + Rank

Run the read path (non-mutating). Either invoke the CLI directly or call runDispatch from the module:

node scripts/lib/dispatcher/cli.mjs --json

The JSON object has keys { candidates, free, ranked, warnings, recommended }:

  • candidates — every repo found below the confinement root (busy ones LISTED, not dropped).
  • free — the subset with no live lease (free === true).
  • ranked — the free candidates sorted DESC by score; ranked[0] is the recommendation.
  • recommended — ranked[0] or null (no free candidates).
  • warnings — human-readable degradation notes (glab/gh missing, host probe failed). Surface every warning to the operator — they explain why a repo was ranked on partial signals.

Ranking combines three signals per repo (implementation: scripts/lib/dispatcher/rank.mjs): backlog priority (critical/high counts), staleness (days since the last completed session — older = more worthwhile, capped at 90d), and readiness (CI status × host resource verdict — only ever dampens). A null priority (glab/gh missing) is ranked on staleness × readiness alone with a warning; the dispatcher NEVER blocks on a missing CLI.

Phase 1.5: Verdict gate (autonomy-gated launch) — #682

Decides ONE thing for the recommended repo R (ranked[0]): may the dispatcher launch WITHOUT per-selection confirmation, or must it inform-and-ask? This sits BETWEEN ranking (Phase 1) and the Owner-AUQ (Phase 2). It is a pre-launch decision, NOT a per-iteration kill-switch — the autopilot loop's 10 kill-switches are reused unchanged once a session is running (see skills/autopilot/SKILL.md § Pre-Loop Verdict Gate).

Compute the suitability verdict for R via the pure four-gate engine computeSuitabilityVerdict(deps) from scripts/lib/autonomy/suitability.mjs. The engine is pure + DI: the dispatcher gathers every signal and passes it in.

Source each verdict input as follows (the dispatcher already has most in hand from Phase 1):

deps fieldSourceNotes
autonomyresolveDispatcherAutonomy({ committed, env, ownerConfig }) from scripts/lib/config/dispatcher-autonomy.mjsThe effective dial. Defaults to 'off' when unset (fail-closed).
confidenceFloorthe confidence-floor from the parsed dispatcher-autonomy: block (default 0.5)Same source object as autonomy.
confidencemode-selector selectMode(signals).confidence (0..1 float) for the recommended session-typeThe same mode-selector the Phase-2 heuristic and autopilot use.
cicheckCiStatus({ repoRoot: R }) → { status } | nullCRITICAL (NICE-b): Phase-1 rank.mjs exposes only the BARE status string (readiness.ciStatus). The engine's G3 gate expects an OBJECT { status } — wrap it as { status: ciStatus } when you HAVE a status; on a genuine ABSENCE (no CI configured) pass ci = null. Since #1031 checkCiStatus no longer returns null on failure — an unreadable state comes back as {severity:'warn', ok:false, degraded:<reason>}, and Phase-1 rank.mjs surfaces exactly that as readiness.ciDegraded with readiness.ciStatus === 'unknown'. Wrap that state as { status: 'unknown' } (the engine warns 'CI signal unknown — treated as absent' and G3 still passes) rather than flattening it to null — null claims a measured absence the probe never established. Do NOT synthesize { status: undefined } (or {}): that present-but-unusable object hits the engine's MALFORMED branch ('CI signal malformed — treated as absent') instead of the clean ABSENT branch ('CI signal absent'). Both pass G3 + warn, but null is the honest "no signal" — reserve the malformed branch for a genuinely unexpected shape. A bare string ALSO hits the malformed branch — always wrap or null.
resourceVerdictthe host resource verdict string ('green'|'warn'|'degraded'|'critical') from rank.mjs (readiness.resourceVerdict) or a fresh evaluate(probe(), thresholds).verdictHost-level — already fetched once in Phase 1. NICE-b: on a genuine probe FAILURE (no signal), prefer resourceVerdict = null over synthesizing 'green'. null = "no signal" ⇒ G4 passes + warns ('resource signal absent') — honest. Synthesizing 'green' fabricates a positive signal the host never reported and can let an autonomous launch proceed against an unknown host state. Pass the real verdict string when you have one; null when you do not.
recentRunsreadRecentAutopilotRuns({ repoRoot: R }) from scripts/lib/autopilot/recent-runs.mjsNEW reader. Reads <R>/.orchestrator/metrics/autopilot.jsonl, returns the most-recent records (newest-last), never throws ([] on missing/unreadable). Pass the TRUE count — the engine's G2 gate omits-with-warn below 5 runs and otherwise checks fired/N < 0.2.

The launch decision (FAIL-CLOSED invariant):

verdict = computeSuitabilityVerdict({ autonomy, confidenceFloor, confidence, ci, resourceVerdict, recentRuns })

IF autonomy === 'autonomous-gated' AND verdict.suitable === true:
    # MAY launch WITHOUT per-selection confirmation:
    # skip the Phase-2 AUQ and proceed straight to Phase 3 (atomic claim) → Phase 4 (route).
ELSE:
    # INFORM the operator of verdict.rationale + verdict.warnings,
    # then run the Phase-2 AUQ (ask before launch). NEVER auto-launch.
  • Gate on BOTH conditions. The launch wiring MUST check autonomy === 'autonomous-gated' AND verdict.suitable === true. Keying only on verdict.suitable is a fail-OPEN bug — it would auto-launch even in advisory/off mode. The autonomy field inside deps is ADVISORY-ONLY inside the engine (it pushes a warning but never flips suitable); the CALLER is responsible for the autonomy === 'autonomous-gated' half of the AND. resolveDispatcherAutonomy defaults to 'off' when no dispatcher-autonomy: config is present, so an absent config forces the inform-and-ask ELSE branch.
  • null is "no signal", not a failure (NICE-b). Passing ci = null or resourceVerdict = null on a fetch/probe failure is the CORRECT honest wiring: the engine treats each null as absent ⇒ the corresponding gate (G3 / G4) PASSES and a warning is recorded ('CI signal absent' / 'resource signal absent'). A null signal does NOT by itself block an autonomous launch — it just surfaces a warning the operator sees. Reserve synthesized objects/strings for real signals; never fabricate a positive ('green' / { status: 'green' }) to paper over a missing probe.
  • forcedFail path is reachable end-to-end (NICE-c). When CI is red OR the resource verdict is critical, the engine sets verdict.suitable === false REGARDLESS of confidence — the four-gate AND fails on G3/G4, and the engine words the rationale FORCED: CI red / FORCED: resource critical / FORCED: CI red + resource critical. For this branch to be reachable, the wiring MUST actually pass the live signals through: ci wrapped as { status: ciStatus } (a bare string or a synthesized-absent object would hit the malformed-PASS branch and mask a real red) and the real resourceVerdict string ('critical' must arrive lowercase-or-normalizable, NOT replaced by a fabricated 'green'). With the signals wired through, a CI-red / resource-critical repo in autonomous-gated mode falls to the ELSE branch: the gate INFORMS the operator (rationale + warnings) and ASKS via the Phase-2 AUQ — it NEVER auto-launches. (Wave 4 covers this with an integration test; this prose is the wiring contract.)
  • Why fail-closed is the default. resolveDispatcherAutonomy returns 'off' when no config is present, so an unconfigured repo correctly takes the ELSE branch (inform + ask). A CI-red or resource-critical repo also fails the engine's G3/G4 gate (the rationale words it FORCED: CI red / FORCED: resource critical), so even in autonomous-gated mode it falls to inform + ask. The dispatcher never auto-launches against a non-green verdict.
  • Inform-branch content. When taking the ELSE branch under autonomous-gated (verdict not suitable), surface verdict.rationale (the one-line gate breakdown) and every entry in verdict.warnings to the operator BEFORE the AUQ, so they understand WHY confirmation is still required.

Phase 2: Owner-AUQ

Conditional (#682): SKIP this phase when Phase 1.5 green-lit an autonomous launch (autonomy === 'autonomous-gated' AND verdict.suitable === true) — in that branch proceed straight to Phase 3. In EVERY other case (any non-autonomous-gated dial, OR a non-suitable verdict) this phase RUNS: inform the operator of the verdict first, then ask. The dispatcher NEVER auto-launches outside the green-verdict autonomous-gated branch.

Present the decision to the operator via the AskUserQuestion tool — never inline prose (.claude/rules/ask-via-tool.md AUQ-001..005, enforced).

  • AskUserQuestion is a deferred tool. Call ToolSearch with "select:AskUserQuestion" ONCE per session before the first use to load its schema.
  • Option 1 is always the recommendation, labelled (Recommended): the top-ranked free repo paired with a recommended session-type. Options 2–4 are overrides (other high-ranked free repos, or other session-types for the same repo). 2–4 options total, each with a one-line description explaining the trade-off.
  • This skill runs at coordinator level. Never call AskUserQuestion from inside a subagent — if a sub-step needs the decision, bubble it back to the coordinator (AUQ-004).

Recommended session-type heuristic for option 1: high critical/high backlog ⇒ /session deep; stale-but-clean (no backlog signal, high staleness) ⇒ /discovery or /session housekeeping; unscoped/new work ⇒ /plan. Offer the alternatives as the other options.

Phase 3: Atomic claim

Claim the lease for repo R BEFORE launching anything. This runs in BOTH branches — the operator-confirmed Phase-2 path AND the autonomous-gated green-verdict path that skipped Phase 2 (#682). The claim ALWAYS precedes the Phase-4 route: an autonomous launch does not bypass the atomic claim, it only bypasses the per-selection AUQ.

// via the module (preferred — returns the acquire() result verbatim)
import { claimRepo } from 'scripts/lib/dispatcher/cli.mjs';
const res = claimRepo({ repoRoot: R, sessionId, mode, ttlHours, semanticSessionId });

Or reuse the primitive directly: acquire({ sessionId, mode, ttlHours, repoRoot, semanticSessionId }) from scripts/lib/session-lock.mjs. The claim is a linkSync create-or-fail = atomic.

  • ok: true → the claim is held. Proceed to Phase 4.
  • ok: false (race lost / busy — reasons: active, stale-heartbeat, fs-error, …) → exclude R, re-rank the remaining free candidates (drop R from free, re-run Phase 1's rank step), and re-present Phase 2. Loop until a claim succeeds or no free candidate remains (then Phase 5).

Do NOT reinvent the claim — always go through claimRepo/acquire. The ok:false path is the load-bearing concurrency guard: two parallel dispatchers can both recommend R, but only one wins the linkSync; the loser must re-rank, never force.

Phase 4: Route

With the lease held, routing splits on whether the chosen entry is model-invocable:

  • /session housekeeping or /session deep (execution modes) and /plan (read-only planning precursor) are NOT something the coordinator can invoke itself. commands/session.md documents session and plan as reserved terminal-only built-in names — under non-interactive (claude -p) invocation the bare form answers "isn't available in this environment" — and skills/plan/SKILL.md additionally carries disable-model-invocation: true, which blocks the Skill tool from invoking it regardless of interactivity. The coordinator therefore hands the operator the exact command to type, one line per option — /session-orchestrator:session <mode> or /session-orchestrator:plan [new|feature|retro] — rather than attempting to invoke either itself.
  • /discovery — read-only investigation precursor (maps scope; does not execute). skills/discovery/SKILL.md carries no disable-model-invocation flag, so the coordinator MAY invoke it directly via the Skill tool when the operator picks this option — no hand-off line needed.

/plan and /discovery remain read-only precursors, NOT execution modes — the menu may route to them, but they only produce artifacts for a later execution session. The full mode taxonomy lives in the mode-selector surface (P2 of this epic); the dispatcher only routes to the entry command the operator picked.

Phase 5: Edge cases

  • No free candidate (recommended === null / free empty) → report "all repos busy", and offer resume (an in-progress session) or wait via AUQ. Never force a selection of a busy repo.
  • glab/gh missing or timed out → the PRIORITY signal (open critical/high backlog counts via scanBacklog, scripts/lib/dispatcher/rank.mjs) falls back to a neutral 1 and a warnings entry says so: the repo is ranked on staleness × readiness only, surface the warning, continue. A missing CLI is never fatal. Ranking does not read the vault, so vault-integration off changes nothing here.
  • Host resource probe failed → readiness is scored without resource dampening (a warning says so); ranking still completes.
  • Bad --start-dir → CLI exits 1 (user/input error); fix the path and re-run.

CLI

node scripts/lib/dispatcher/cli.mjs [--json] [--dry-run] [--repo <name>] [--start-dir <path>] [--help] [--version]
FlagDescription
--jsonEmit { candidates, free, ranked, warnings, recommended } as a single JSON object to stdout.
--dry-runExplicit non-mutating rank (the read path is already non-mutating; documents intent).
--repo <name>Filter the human-readable table to one repoName (informational; does not change ranking).
--start-dir <path>Override the scan root (defaults to the confinement root).
--help / --versionPrint usage / version and exit 0.

Data → stdout, warnings/errors → stderr (never mixed). Exit codes follow .claude/rules/cli-design.md:

CodeMeaning
0Success
1User/input error (e.g. bad --start-dir)
2System error (unexpected dispatch failure)

Anti-Patterns

  • Inline prose for the Phase-2 decision — always AskUserQuestion (AUQ-001). A numbered markdown list of repos is a bug.
  • Launching before claiming — Phase 3's acquire MUST succeed before Phase 4. Launching then claiming re-opens the race the lease exists to close.
  • Forcing a busy repo when none are free — report and offer resume/wait; never select a free === false candidate.
  • Treating a missing glab/gh as fatal — null priority degrades to staleness × readiness with a warning; never block.
  • Re-implementing the claim — go through claimRepo/acquire; do not hand-roll a lockfile.
  • Ignoring ok:false — on a lost race you MUST exclude-and-re-rank, not retry the same repo or proceed without the lease.
  • Running this from a subagent — coordinator-only (AUQ is unavailable in subagents).
  • Fail-OPEN verdict gate (#682) — keying the autonomous launch on verdict.suitable alone (ignoring autonomy === 'autonomous-gated') auto-launches in advisory/off mode. ALWAYS gate on BOTH.
  • Feeding the bare CI string into the engine — rank.mjs exposes ciStatus as a bare string; computeSuitabilityVerdict wants { status }. Wrap it ({ status: ciStatus }) or pass null — a bare string silently hits the malformed-absent branch. A red CI fed as a bare string would PASS G3 (masked as malformed) instead of forcing the FORCED-fail branch (NICE-c).
  • Flattening a DEGRADED CI reading to null (#1031) — readiness.ciDegraded set (⇒ readiness.ciStatus === 'unknown') means the state could NOT be read, which is weaker than absence, not equal to it. Pass { status: 'unknown' }; null asserts a measured absence nothing established.
  • Synthesizing an absent signal instead of passing null (NICE-b) — on a resource-probe failure, pass resourceVerdict = null (honest "no signal" ⇒ gate passes + warns). Do NOT synthesize { status: undefined } (hits the malformed branch) and do NOT fabricate 'green' / { status: 'green' } (invents a positive signal the host never reported and can green-light an autonomous launch against an unknown state).
  • Pre-truncating recentRuns below 5 — passing fewer than the true on-disk count when ≥ 5 runs exist falsely triggers the engine's <5-run omission branch and skips the kill-switch gate. Pass the TRUE count; never call readRecentAutopilotRuns with limit < 5 on the launch-gate read (the reader honours a small limit literally and will not clamp it upward).
  • Auto-launching against a non-green verdict — a CI-red / resource-critical / low-confidence verdict ALWAYS falls to inform + ask, even under autonomous-gated. Never proceed straight to claim on a non-suitable verdict.

Critical Rules

  • The read path (runDispatch / cli.mjs without a claim) is NON-MUTATING. The ONLY mutating step is the Phase-3 atomic claim.
  • The atomic claim is linkSync create-or-fail via acquire(...). ok:false ⇒ exclude the repo and re-rank — this is the concurrency guard, not an error to swallow.
  • Phase 2 uses AskUserQuestion with option 1 = recommendation (Recommended); coordinator-only.
  • Busy repos are LISTED, never selected (PRD: "busy repos listed as such, not selected").
  • glab/gh/host-probe degradation is surfaced as a warning and never blocks ranking.
  • Phase 1.5 verdict gate (#682) is FAIL-CLOSED: MAY launch without per-selection confirmation requires autonomy === 'autonomous-gated' AND verdict.suitable === true. Every other case informs the operator (rationale + warnings) and asks via Phase-2 AUQ. The dispatcher NEVER auto-launches outside that single green branch. The 10 autopilot kill-switches are reused unchanged once a session is running — the verdict gate is a pre-launch decision, not a kill-switch.
  • Implementation files: scripts/lib/dispatcher/cli.mjs (orchestration: runDispatch, claimRepo) · scripts/lib/dispatcher/enumerate.mjs (enumeration + free/busy) · scripts/lib/dispatcher/rank.mjs (scoring) · scripts/lib/session-lock.mjs (acquire atomic claim) · scripts/lib/autonomy/suitability.mjs (computeSuitabilityVerdict four-gate engine, #682) · scripts/lib/config/dispatcher-autonomy.mjs (resolveDispatcherAutonomy effective dial, #682) · scripts/lib/autopilot/recent-runs.mjs (readRecentAutopilotRuns kill-switch-history reader, #682).

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Use when the user asks to improve architecture, find refactoring opportunities, surface deepening opportunities, consolidate tightly-coupled modules, or make a codebase more testable and AI-navigable. Surfaces shallow modules and hypothetical seams using a precise vocabulary (Module / Interface / Implementation / Depth / Seam / Adapter / Leverage / Locality from LANGUAGE.md).

中文简介正在准备中。当前显示原文说明。

Kanevry/session-orchestrator522026年10月26日 更新

autopilot

免费

Use this skill when running an autonomous session-orchestration loop. Chains session-start → session-plan → wave-executor → session-end for N iterations with all 10 kill-switches (SPIRAL, FAILED wave, carryover > 50%, max-hours, max-sessions, resource-overload, token-budget, stall-timeout, sub-threshold confidence, user-abort). Reads Mode-Selector output (Phase B) to decide auto-execute vs. fallback. Writes one autopilot.jsonl record per loop run. Phase C scaffold (issue #277); implementation lives in scripts/lib/autopilot.mjs (Phase C-1 follow-up).

中文简介正在准备中。当前显示原文说明。

Kanevry/session-orchestrator522026年10月26日 更新

bootstrap

免费

Use this skill when scaffolding the minimum repository structure required by session-orchestrator. Invoked automatically by the Bootstrap Gate when CLAUDE.md, Session Config, or bootstrap.lock is missing. Also available as /bootstrap for manual invocation. Three intensity tiers: fast (demos/spikes), standard (MVPs), deep (production/team).

中文简介正在准备中。当前显示原文说明。

Kanevry/session-orchestrator522026年10月26日 更新

Use when you have a feature idea but the scope or UX is still ambiguous — runs a lightweight Socratic design dialogue (3-5 AUQ rounds) and writes a spec markdown file. Use BEFORE /plan feature when product intent needs validation; skip to /plan feature when scope is already clear. HARD-GATE prevents any code work until the design is user-approved.

中文简介正在准备中。当前显示原文说明。

Kanevry/session-orchestrator522026年10月26日 更新

Use when detecting drift between CLAUDE.md (or AGENTS.md, the Codex CLI alias) / _meta narrative and live repository state. Ten checks: absolute-path resolution, 01-projects/ count claims, issue-reference freshness, session-file existence, command-count sync, session-config-parity (mandatory template keys = error, opt-in gaps = note, unknown local keys = warning), vault-dir-parity (CLAUDE.md vs AGENTS.md), generated-rule-staleness (WARN-only), rule-scoping (paths:/globs: frontmatter defects, dangling rule citations, zero-match globs), and docs-parity (docs/components.md count-claims vs on-disk counts, template-vs-reference config-key parity, stale .claude/metrics/ paths). Full per-check spec in the body table. Invoked as an opt-in session-end phase; mirrors vault-sync's lean JSON+exit-code contract.

中文简介正在准备中。当前显示原文说明。

Kanevry/session-orchestrator522026年10月26日 更新

close

免费

End session with verification, commits, and documentation

中文简介正在准备中。当前显示原文说明。

Kanevry/session-orchestrator522026年10月26日 更新

查看 Kanevry 的全部技能

报告此技能的问题