arbiterforge/tribunal
The deep, rarely-convened whole-codebase audit lane. Routed to when the user invokes {{CMD:tribunal}}. Seven gated phases — cost/model, map, roster dispatch, triage, report, approval+filing, telemetry. Costs on the order of millions of tokens; proceeds only after the user acknowledges the estimate; never a required gate; nothing filed or sent without explicit authorization.
npx skills add https://github.com/arbiterForge/codeArbiter --skill tribunal
The deepest, most expensive review codeArbiter offers — convened rarely, on demand, never as a gate. Routed to when the user invokes {{CMD:tribunal}}. Eleven specialist lenses judge the codebase; every finding persists to its own file (plus append-only triage/run logs) under a run dir that survives compaction and disconnects, so the run resumes from disk.
Read these, or STOP and surface the gap — never guess a command or a path:
{{PROJECT_DIR}}/.codearbiter/tech-stack.md — stack, async model, concurrency primitives, test/lint/secrets commands, and, when documented, the tracker command. Stop if the test/lint/secrets commands are missing; do not guess.{{PROJECT_DIR}}/.codearbiter/CONTEXT.md — the stage: maturity value and domain vocabulary.{{PROJECT_DIR}}/.codearbiter/coding-standards.md — the conventions lenses judge against.{{PROJECT_DIR}}/.codearbiter/security-controls.md — trust boundaries, approved crypto/secret stores; feeds the appsec and secrets lenses. Absent on some repos — proceed without the security lenses' control-file checks if so.{{PLUGIN_ROOT}}/skills/tribunal/references/ — each is cited at its phase, loaded on demand. Do not preload them.This lane is expensive. Orient and get explicit go-ahead before dispatching anything.
.codearbiter/reports/ for the most recent run dir matching the current scope-slug, any date — never just today's. If none, skip to sizing. If found, check completion: incomplete (no report-written event in its run.jsonl) means either resumable or stale, judged by that run dir's latest run.jsonl timestamp. A run whose run.jsonl carries run-aborted is terminal — never offered for resume; a fresh run starts. Younger than 7 days → recover position with the cheap cursor scan in references/schemas.md (grep the last wave-triaged, do not read finding bodies) and offer to resume at the first un-triaged wave instead of restarting; skip the estimate. Older than 7 days → STOP and ask the user to resume anyway or start fresh — the codebase may have drifted under the findings, and stale-tree findings must not silently merge with fresh ones. Complete → start a fresh run.run-aborted event to run.jsonl before stopping.RUN_ID = <UTC-date>-<scope-slug> on a fresh run; create .codearbiter/reports/<run-id>/; open run.jsonl. On resume, reuse the existing RUN_ID as-is — the date is the run's creation date and never changes on resume.references/cost-and-models.md — load now.Gate: the user has acknowledged the estimated cost and confirmed the model. An unacknowledged run does not pass.
Map before reviewing; the map decides what gets scrutiny.
references/cost-and-models.md): file tree, language breakdown, entry points/routes, core-logic and shared-utility locations, dependency and integration surface. Write inventory.md.references/ai-markers.md: risk-rank directories (untrusted input, money, auth, PII, churn = highest), mark trust boundaries, record AI-authorship markers and an iteration-depth estimate. High-marker / high-iteration areas carry a scrutiny boost and a small severity prior.run.jsonl events.references/cost-and-models.md, or a repartition for cause — and record it in the run-started event (references/schemas.md); resume reads this recorded partition, never re-derives it.Gate: inventory.md written with the risk/boundary/marker overlay, and the active-lens set recorded.
Dispatch the active lenses in the wave partition recorded at Phase 1 (default in references/cost-and-models.md) at the concurrency from references/cost-and-models.md (≤5 in flight). Give each agent only its scope slice, on the model/effort from references/cost-and-models.md; the agent itself reads its own mandate (references/lenses/<lens>.md) and the finding contract (references/finding-record.md), and loads neither the other lenses' mandates nor the orchestrator schemas. The orchestrator reads references/finding-record.md to read findings at triage, and consults a lens mandate only to adjudicate that lens's finding.
tribunal-* agent writes each finding to its own file findings/<lens>/<finding-id>.json the moment it is found — one file per finding, never a batched write at the end (write contract: references/finding-record.md).path:line and the minimal snippet. An absence claim — "no handler", "no teardown", "missing validation" — requires reading the whole unit, never a truncated window.run.jsonl as it flushes.lens-completed event in run.jsonl with surface_seen/findings/model taken from the agent's summary, plus tokens when the orchestrator can observe that lens's spend.{{IF:claude}}agentId from each Agent dispatch as agent_id on its lens-launched event. If the host returns no usable ID, record tokens_status: unavailable and tokens_reason: host-result-missing on lens-completed. Before constructing any shell command, require the returned ID to match ^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$; on mismatch, record tokens_status: unavailable and tokens_reason: invalid-agent-id, and do not invoke the helper. Otherwise, after the lens completes, invoke the tribunal-usage.py observe --agent-id mode with python3 "${CLAUDE_PLUGIN_ROOT}/hooks/tribunal-usage.py" observe --agent-id <validated-agent-id> || python "${CLAUDE_PLUGIN_ROOT}/hooks/tribunal-usage.py" observe --agent-id <validated-agent-id>. The helper resolves only that agent's documented agent-<agentId>.jsonl transcript and reads only assistant identity and complete message.usage records. On status: observed, copy its integer tokens and component token_usage, set tokens_status: observed, and copy source as tokens_source. On status: unavailable, omit tokens, set tokens_status: unavailable, and copy reason as tokens_reason. Usage recovery is best-effort and never blocks a tribunal.{{END}}{{IF:codex}}tokens_status: unavailable and tokens_reason: host-usage-unsupported. If dispatch succeeds but returns no usable thread ID, record tokens_status: unavailable and tokens_reason: host-result-missing. Otherwise capture the returned agent thread ID on the lens-launched event. After that lens completes, resolve the installed plugin root from this routine's own loaded SKILL.md path (ordinary shell calls do not inherit a plugin-root environment variable) and run hooks/tribunal-usage.py observe --thread-id <agent-thread-id>. The helper reads only metadata and cumulative token-count events from the exact agent session. On status: observed, copy its integer tokens and component token_usage, set tokens_status: observed, and copy source as tokens_source into lens-completed. On status: unavailable, omit tokens, set tokens_status: unavailable, and copy reason as tokens_reason; never turn a parser or capability failure into an unexplained omission. Codex session JSONL is explicitly not a stable extension interface, so this recovery remains best-effort and every changed-format path must degrade to a reason, not block the tribunal.{{END}}Gate: every active lens has flushed its findings/<lens>/ files, and each wave's status is recorded.
Triage per wave from disk as soon as it flushes; do not wait for the whole run.
final_severity/final_confidence from the evidence yourself — the lens's values are provisional input; every critical/high carries a counter_argument.triage.jsonl. Below the confidence gate after calibration → investigate (medium/low) or decision-required (critical/high) — never dropped silently.plans/phase-<n>.md for its kept (keep/combine) work.references/triage.md — load now.Gate: every wave's findings triaged into triage.jsonl and a plans/phase-<n>.md written for its kept work.
Regenerate report.md and manifest.yaml from the two logs per references/report.md — projections, never hand-authored. Task-list-structured (not prose): findings grouped by calibrated severity then type, each with id, path:line, one-line description, remediation shape, triage decision, and a link to its phase plan; decision-required in its own section; a launched/skipped-lens summary; an investigate appendix. Apply {{PLUGIN_ROOT}}/includes/anti-slop-design/ (core + medium-documents) to the prose.
State plainly that critical/high are blocking-severity findings — work that should block shipping the affected code — but that this lane is not itself a gate and blocks nothing.
Gate: report.md regenerated from the logs and presented. No issues created.
Findings become GitHub issues only on explicit selection and authorization. Silence or ambiguity → file nothing; "looks good" is not authorization.
issue_ref in triage.jsonl, then dedup against the tracker — this lane reruns over time and will re-find the same issues.issue-commands.sh; execute only on explicit approval, writing each issue_ref back into triage.jsonl.open-tasks.md — a periodic-review finding must survive PR abandonment.references/issue-filing.md — load now.Gate: either issue-commands.sh written and printed, or — on approval — issues filed with the id→result table and issue_ref recorded. Nothing filed without explicit selection; no duplicates against the tracker.
Optional, opt-in KPI feedback to refine the skill and the estimator — off by default, sent only on explicit per-run authorization.
--tag.references/telemetry.md — load now.Gate: the payload is shown, and it is either handed to the user as a command or — on approval — posted. No telemetry leaves without per-run authorization.
.codearbiter/reports/<run-id>/ until the filing gate.path:line and a minimal evidence snippet.counter_argument.manifest.yaml, report.md, and plans/ are regenerated from them, never hand-edited.open-tasks.md.issue_ref, and dedup against the tracker by dedup_key/title before filing.decision-required findings file as a discussion issue; ADRs are authored only via {{CMD:adr}} with user attribution.--tag) in the payload — KPI aggregates only.tech-stack.md or STOP. For the tracker: use tech-stack.md if it documents one; else default to gh issue create on a GitHub origin; else STOP.Take arbiterforge/tribunal from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.