agentsclimarketplace

Roster doctor

Skill mathiasbourgoin/roster/.agents/skills/roster-doctor

Health check + pipeline pre-flight — verifies roster install integrity and that the project's dev environment (build/test/lint/format) is actually runnable before work starts.From its SKILL.md

Install
npx -y skills add mathiasbourgoin/roster --skill roster-doctor

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

20.9 KB, as published. Nobody here has run it


name: roster-preamble version: 1.6.1 description: Shared preamble injected into every roster skill that declares preamble true. Not a standalone command.

Roster Preamble

This preamble is injected into every roster skill that declares preamble: true. It encodes the non-negotiable principles that govern all skill runs.


Principles

Completeness

Do not defer tests, documentation, or robustness in the name of speed. A short-term shortcut is rarely faster than a complete solution. "We'll add tests in a follow-up" is not an acceptable decision — it is explicit debt, or it is not a decision at all.

Search Before Build

Before creating anything, verify what already exists:

  1. Local (current repo, harness, KB)
  2. Roster (index.json, roster GitHub)
  3. Web (if webfetch available)

A false positive (checking for something that didn't exist) costs seconds. A false negative (building something that already existed) costs hours and creates debt.

Anti-Sycophancy

Do not validate a direction if you have a grounded objection. Do not say "good idea" before verifying it is a good idea. If you spot a problem, say so — clearly, factually, without softening. State your recommendation, explain why, mention what context you might be missing, and ask.

User Sovereignty

When you and a sub-agent both agree to change the user's direction: → present the recommendation → explain why you both think it is better → state what context you might be missing → ask

Never act unilaterally in this case. The decision belongs to the user.

Escalation

If you are blocked, the situation is ambiguous, or the action exceeds the declared scope: → escalate to the human — do not deviate from scope, do not guess

Asking Questions

When you need to ask the user something, use your runtime's interactive input tool if one is available — do not ask via plain text output.

Known runtime tool names:

RuntimeTool name
Claude CodeAskUserQuestion
Copilot CLIask_user
Codexrequest_user_input
OpenCodequestion

Rules:

  • One question at a time — never bundle multiple questions into one message
  • Prefer multiple-choice options over open-ended when the answer space is predictable
  • If no interactive tool is available, output a clearly marked plain-text question and wait for the user's reply before proceeding

Friction Log

At the end of each run, honestly record:

  • frictions encountered (workarounds, long searches, ambiguities)
  • methods used
  • any suggestion for a tool, skill, or adaptation

This is not a performance review. It is cross-run memory. Format: see skills-meta/friction.jsonl.

Pipeline State

If your skill's phase: frontmatter field is non-null (i.e. you are one of the staged pipeline phases) and you are operating on a task with a briefs/<task>- context, append one event to briefs/<task>-state.json when you finish — this is the durable, resumable record /roster-run reads to resume and /roster-doctor status renders. Skip entirely if your phase: is null (standalone skills: doctor, audit, investigate, init, skill-health) or there is no task context. Create the file if absent; preserve every prior events entry:

{
  "task": "<slug>",
  "mode": "express|fast|full",
  "current_phase": "implement",
  "events": [
    { "phase": "implement", "outcome": "COMPLETED", "at": "<ISO-8601 or omit>", "by": "roster-implement" }
  ]
}

Rules for writing your event:

  • task is the canonical slug, derived once from the task description and reused identically by every phase: lowercase, kebab-case, the ≤4 most significant words (the same rule /roster-question and /roster-intake use to name briefs/<task>-*). The first phase to run — roster-implement in Express/Fast, roster-question/roster-intake in Full — fixes the slug; every later phase, and /roster-run's resume check, MUST derive the byte-identical slug or the ledger will not be found. When in doubt, reuse the slug already present on existing briefs/<task>-* files for this task rather than re-deriving.
  • phase MUST be your skill's own phase: frontmatter value, verbatim — one of the legal tokens: question, research, intake, spec, plan, implement, review, qa, ship. Never invent a synonym (implementation, code-review, …); resume matches on these exact tokens.
  • outcome is per phase, from this fixed vocabulary — intake: VALIDATED; spec: VALIDATED, SKIPPED (non-spec'd task types), or BOUNCED; review/qa: GO or NO-GO; ship: COMPLETED or BLOCKED; implement: COMPLETED or PARTIAL; question/research/plan: COMPLETED. Do not invent other values — PARTIAL is legal only on implement, and BLOCKED only on ship; every other phase/outcome pairing is schema-illegal.
  • Emission invariants for the two non-success terminals:
    • implement/PARTIAL — emit only when in-scope work remains after the improve-loop budget is exhausted, or a scope blocker stops the run. Never emit PARTIAL for "tests failing" — a failing gate is not a terminal state; keep iterating within the budget or escalate.
    • ship/BLOCKED — emit only when review and QA are GO but the ship action itself is impossible (permissions, remote state, human hold). A NO-GO gate is not BLOCKED.
    • Both events carry an optional reason string field in the event itself — no pointer-by-convention to an external artifact: { "phase": "ship", "outcome": "BLOCKED", "reason": "<why>", "by": "roster-ship" }.
    • Artifact writes happen BEFORE the event append. Write your phase artifacts (impl brief, ship gate/summary) to disk first — appending the ledger event is the last thing a phase does.
  • Resume semantics (read by /roster-run Step 1.4): a latest event implement/PARTIAL re-routes to /roster-implement; a latest event ship/BLOCKED halts the pipeline and surfaces the event's reason to the human.
  • Append-only audit trail. Always push a new event — never rewrite or delete a prior one. A re-run after a NO-GO bounce legitimately produces a second implement/review pair; that repetition is the history, not a bug. Set current_phase to your phase (the latest completed).
  • mode is the task's mode (express/fast/full); set it on first write, leave it thereafter.
  • Use a timestamp in at if your runtime can produce one; otherwise omit the field. by is your skill name (or human-gate for a gate decision).
  • Skill hooks receive the task slug via the TASK environment variable — export it when invoking hooks manually.

Roster Doctor

You verify two things and modify no source code: (1) the roster installation is intact, and (2) the project's dev environment is actually runnable — build compiles, tests execute, linter/formatter are installed. You report findings; when something is missing you present exact remediation and, only with explicit consent, help install or configure it.

Modes

InvocationRunsUsed by
/roster-doctor (full, default)Section 1 + Section 2 + reportHuman, on demand
/roster-doctor preflightSection 2 only → READY / NOT-READY verdictroster-run before an implementation phase
/roster-doctor status [<task>]Section 4 only → pipeline progress timelineHuman, to see where a task stands

Read the argument: preflight runs Section 2 only; status runs Section 4 only; otherwise run the full check (Sections 1 + 2).

Steps

1. Roster install health (skip in preflight mode)

Run and tabulate. Never fail the whole check on one miss — collect all findings.

# Tooling
printf 'bash: %s\n' "${BASH_VERSION:-unknown}"; [ "${BASH_VERSINFO[0]:-0}" -ge 4 ] && echo "  bash>=4 ✓" || echo "  bash<4 ✗ (installer needs >=4)"
for t in jq git gh curl; do command -v "$t" >/dev/null 2>&1 && echo "$t ✓" || echo "$t ✗"; done
# Release channel the project was installed from (sentinel written by install.sh). Default
# "stable" when no marker exists (installs predating channels, or an explicit stable install).
ch="$(cat .claude/.roster-channel .opencode/.roster-channel .agents/skills/recruit/.roster-channel 2>/dev/null | head -1)"
echo "channel: ${ch:-stable (default — no .roster-channel marker)}"
# Harness manifest valid
[ -f .harness/harness.json ] && { jq empty .harness/harness.json 2>/dev/null && echo "harness.json ✓ valid" || echo "harness.json ✗ invalid JSON"; } || echo "harness.json — absent"
# Pipeline skills present (at least the entry point), per runtime
for p in .claude/commands/roster-run.md .agents/skills/roster-run/SKILL.md; do [ -f "$p" ] && echo "pipeline skills ✓ ($p)"; done
# Projection / source drift (only when the dev checkout is present)
[ -f scripts/sync-harness.sh ] && bash scripts/sync-harness.sh --check 2>&1 | tail -1
[ -f scripts/check-recruiter-sync.js ] && node scripts/check-recruiter-sync.js 2>&1 | tail -1

Report each as ✓ / ✗ / absent. gh absent is a warning (only /roster-ship PR creation needs it), not a failure.

# Workflow templates health (Phase 1: JSON syntax only — cwr lint requires cwr CLI)
if [ -d workflows/templates ]; then
  for f in workflows/templates/*.cwr.json; do
    [ -f "$f" ] && { jq empty "$f" 2>/dev/null && echo "$(basename $f) ✓" || echo "$(basename $f) ✗ invalid JSON"; }
  done
else
  echo "workflows/templates/: absent ✗ (workflow dispatch unavailable)"
fi
# Workflow instances gitignore check
if ls workflows/*.cwr.json 2>/dev/null | grep -v '/templates/' | grep -q .; then
  grep -q 'workflows/\*\.cwr\.json' .gitignore || \
    echo "⚠ WARN: workflow instances present but not gitignored — add 'workflows/*.cwr.json' to .gitignore (and '!workflows/templates/*.cwr.json' to preserve templates)"
fi

Capability tag check (formal skills).

Scan pipeline skills for a mismatch between description content and the presence of a capability: frontmatter field. A skill that mentions formal tools but omits the tag will be invisible to roster-formal-verify's tool-resolution grep:

for f in skills/pipeline/*.md; do
  # Extract the name: field from frontmatter
  skill_name=$(grep -m1 "^name:" "$f" 2>/dev/null | sed 's/^name: *//')
  # Skip roster-* orchestration skills — they describe the formal route but are NOT backends.
  # The check targets third-party tool skills (e.g. formal-apparatus) that perform verification.
  case "$skill_name" in roster-*) continue ;; esac
  # Case-insensitive: match description lines containing formal tool names
  if grep -qi "^description:.*\(formal\|rocq\|coq\|quint\)" "$f"; then
    if ! grep -q "^capability:" "$f"; then
      echo "⚠ WARN: $f ($skill_name) — description mentions formal tools but lacks 'capability:' field"
    fi
  fi
done

Report each match as a warning, not a failure. The fix is to add capability: formal-rocq or capability: formal-quint to the skill's frontmatter. If formal-apparatus was installed without this tag, patch it before running roster-formal-verify.

2. Project dev-env readiness

Detect the gate commands. Prefer explicit harness tunables when present, else infer from project signals (mirror of the post-edit-lint hook's detection):

# Explicit tunables win, if the manifest declares them
jq -r '.. | objects | (.test_command // .build_command // .lint_command // empty)' .harness/harness.json 2>/dev/null

# Otherwise detect by manifest file → toolchain
ls package.json Cargo.toml dune-project pyproject.toml go.mod 2>/dev/null
Signalbuildtestlint / formatunderlying tool(s)
package.jsonnpm run build if script presentnpm test if script presenteslint/biome if configurednode, npm
Cargo.tomlcargo buildcargo testcargo fmt --check, cargo clippycargo
dune-projectdune builddune testdune fmt (.ocamlformat)dune, opam
pyproject.toml—pytestruff/flake8 if configuredpython, pytest, ruff
go.modgo build ./...go test ./...golangci-lint if .golangci.ymlgo

Verify, cheapest signal first — do not run the full suite blindly:

  1. Tool presence: command -v <tool> for every underlying tool the detected gates need. A missing tool is the most common and most actionable failure.
  2. Command resolves: confirm the build/test/lint command is defined (e.g. the npm script exists: jq -e '.scripts.test' package.json).
  3. Build runs: attempt the build command (bounded). A clean baseline build is the strongest readiness signal.
  4. Tests collect: prefer a non-executing collection where available (pytest --collect-only, cargo test --no-run, go test ./... -run x -count=0) over a full run — confirms the test harness is wired without paying full runtime.

Record, per gate, one of: runnable / tool-missing:<tool> / not-configured / fails:<short reason>.

3. Verdict + escalation

  • READY — every detected gate is runnable (or legitimately absent for the project type).
  • NOT-READY — any gate is tool-missing, not-configured, or fails.

On NOT-READY, present exactly what is missing with concrete remediation, then ask (via the interactive question tool) before changing anything:

Dev environment is NOT READY to start the pipeline:
  ✗ tests: pytest not installed
  ✗ lint:  ruff configured in pyproject.toml but not installed
Fix options:
  A) Install the missing tools now (I'll run: pip install pytest ruff)
  B) I'll configure it myself — re-run /roster-doctor when done
  C) Proceed anyway (NOT recommended — the pipeline will fail at the quality gate)

Only install/configure on explicit approval (option A). Never install global packages or modify environment config without consent — this is an escalation trigger.

In preflight mode, return the single-line verdict to the caller and do not print the full report: READY or NOT-READY: <comma-separated reasons>.

4. Pipeline status (status mode only)

Render the durable, append-only state ledger each pipeline phase writes (see the preamble's Pipeline State section). This is read-only — it never writes or repairs the ledger.

Select the ledger(s). If a task was named, target only its ledger; otherwise list all:

if [ -n "<task>" ]; then
  [ -f "briefs/<task>-state.json" ] && echo "briefs/<task>-state.json" \
    || echo "no ledger for <task> — it has not started, or predates state tracking (inspect briefs/<task>-* directly)"
else
  ls briefs/*-state.json 2>/dev/null || echo "no pipeline state recorded"
fi

For each selected ledger, print the timeline in recorded (append) order — the order phases actually completed, which for a re-run after a NO-GO is e.g. implement, review, implement, review and is itself informative:

Validate each ledger against the byte-identical schema gate roster-run's Step 1.4 uses (not just a JSON parse), so status flags exactly the ledgers a resume would reject — a valid-JSON-but-malformed ledger (empty events, bad mode, slug/current_phase mismatch, current_phase not in the mode's sequence, or an illegal last-event outcome) is a finding, not a clean render. The expected slug is the file's own basename (briefs/<slug>-state.json):

# LEDGER_SCHEMA is the SAME predicate as roster-run Step 1.4 — keep the two copies identical.
# Byte-identity mechanically enforced by `scripts/check-pipeline-install.js`.
LEDGER_SCHEMA='
  {express:["implement","review","ship"],
   fast:["implement","review","qa","ship"],
   full:["question","research","intake","spec","plan","implement","review","qa","ship"]} as $seq
  | {intake:["VALIDATED"],spec:["VALIDATED","SKIPPED","BOUNCED"],
     review:["GO","NO-GO"],qa:["GO","NO-GO"],ship:["COMPLETED","BLOCKED"],
     question:["COMPLETED"],research:["COMPLETED"],plan:["COMPLETED"],implement:["COMPLETED","PARTIAL"]} as $vocab
  | .current_phase as $cp | .mode as $m | (.events[-1]) as $last
  | (.task == $t)
    and ($seq[$m] != null)
    and ($cp|type=="string")
    and (.events|type=="array") and ((.events|length)>0)
    and (all(.events[]; . as $e
          | ($e|type)=="object"
          and ($e.phase|type=="string")
          and (($vocab[$e.phase] // []) | index($e.outcome) != null)
          and (($e|has("reason")|not) or ($e.reason|type=="string"))))
    and ($last.phase == $cp)
    and (($seq[$m]|index($cp)) != null)
'
for f in <selected ledgers>; do
  # The expected slug is the file's own basename (status scans whatever ledgers exist, so it
  # derives `$t` from the filename — unlike roster-run, which knows the task slug from its arg).
  slug="${f#briefs/}"; slug="${slug%-state.json}"
  if jq -e --arg t "$slug" "$LEDGER_SCHEMA" "$f" >/dev/null 2>&1; then
    jq -r '
      "Task: \(.task)  [\(.mode) mode]  — last completed: \(.current_phase)",
      (.events[] | "  \(.phase): \(.outcome)\(if .at then "  (\(.at))" else "" end)\(if .by then "  ·\(.by)" else "" end)")
    ' "$f"
  else
    echo "  ⚠ $f is invalid JSON or fails the ledger schema — corrupt; report it, do not rewrite it. Skipping next-phase computation."
  fi
done

Compute the next phase (below) only for ledgers that passed the schema gate.

Then state the next phase roster-run would resume into, computed from current_phase in the recorded mode's sequence (express: implement→review→ship; fast: implement→review→qa→ship; full: question→research→intake→spec→plan→implement→review→qa→ship):

  • If current_phase is the last in its mode's sequence (ship), print next: complete when the latest ship outcome is COMPLETED; if it is BLOCKED, print next: halted (ship BLOCKED) plus the event's reason if present.
  • If current_phase is an outcome-bearing phase (intake/spec/review/qa), note that the actual route is verdict-dependent (read the brief's VALIDATED/SKIPPED/BOUNCED or GO/NO-GO) — don't assert a positional successor.
  • If current_phase is implement with latest outcome PARTIAL, print next: implement (re-run — PARTIAL); with COMPLETED, print the positional successor as usual.
  • Otherwise print the positional successor in that mode's sequence.

A malformed ledger is reported as a finding (above) — never crash, never rewrite it; a corrupt ledger is something the human resolves.

Output Contract

A health report (full mode), a one-line READY / NOT-READY: … verdict (preflight mode), or a per-task pipeline timeline + next-phase line (status mode). No source files modified — including the state ledger, which is read-only here. Tool installation happens only after explicit human approval.

When to Go Back

ConditionAction
NOT-READY and user declines to fixStop — do not proceed into the pipeline; report blocked
Roster install health shows projection driftPoint the user at ./scripts/sync-harness.sh; do not auto-sync from here
Detected gate commands are ambiguous (multiple toolchains)Ask the user which is authoritative before verdict

What Next

From full mode: report only — the human decides next action. From preflight (READY): roster-run continues routing. From preflight (NOT-READY): roster-run halts at the gate until resolved.

💡 Run /roster-skill-health periodically to surface friction patterns and improve the pipeline.

Friction Log

{
  "date": "<ISO-8601>",
  "skill": "roster-doctor",
  "task": "<task-slug>",
  "frictions": [],
  "methods": [],
  "suggestion_type": null,
  "suggestion": null,
  "effort_estimate": null
}

Rules

  • Never modify source code — this skill only reports and (with consent) installs tooling.
  • Never install packages or change environment/global config without explicit approval.
  • Never run a full, expensive test suite when a non-executing collection proves readiness.
  • In preflight mode, return only the verdict line — do not flood the caller with the full report.
  • A missing gh is a warning, never a readiness failure.

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.