本文へ移動
cccskills
無料GitHub で公開

loop-station

Observe the harness itself — (WS1) measure context budget as a deterministic, trendable inventory (tokens per CLAUDE.md / skill / agent, lexical redundancy, per-CI cold-write totals; committed history.jsonl), (WS2) reconstruct the real invocation trace (which skills/agents/tools fired and how they nested) from session transcripts, and (WS-A) roll the per-run CI traces up into a committed weekly usage record (per-skill invocation counts; usage.jsonl) — the usage side of the dead-weight join. Use for "context budget", "how big is CLAUDE.md / our skills", "is the harness bloating", "how do our agent loops actually run", "which skills actually get used", "trace this session", "loop station".

インストール方法を見る

含まれるファイル(17)

  • SKILL.md15.9 KB
  • advisor.mjs9.7 KB
  • aggregate-usage.mjs5.4 KB
  • append-history.mjs2.3 KB
  • append-usage.mjs2.9 KB
  • collect-traces.mjs4.7 KB
  • gather.mjs10.6 KB
  • lib/advisor.test.mjs6.0 KB
  • lib/aggregate-usage.test.mjs3.3 KB
  • lib/loop-station.test.mjs2.9 KB
  • lib/parse-transcripts.test.mjs6.4 KB
  • lib/redundancy.mjs5.2 KB
  • lib/scorecard.mjs2.8 KB
  • lib/tokens.mjs3.2 KB
  • parse-transcripts.mjs11.7 KB
  • pi-telemetry.mjs9.7 KB
  • pi-telemetry.test.mjs4.7 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Loop Station — harness observatory (WS1 inventory + WS2 trace)

WS1 (context-budget inventory) is below; the WS2 invocation trace is the second section. Both are producers — WS3 (pocs/loop-station) renders them.

WS1 — context-budget inventory

The first, cheapest layer of the Loop Station observatory (epic #926): a deterministic snapshot of how big our always-on harness context is and how much of it is restated, captured at every merge that touches it. No LLM in this path — count_tokens is free tokenization, not generation — so the trend is clean and reproducible.

Boundary: this is the producer. The daily one-line readout is WS4 (housekeeping digest reads the latest record); the rendered view is WS3 (pocs/loop-station); the runtime invocation trace is WS2. Compute stays here in the scripts — the view only renders.

What it measures

Walking root CLAUDE.md + every skill (.claude/skills/**) + every agent (.claude/agents/**) + each LLM CI workflow's prompt: block:

  • tokens per artifact — via Anthropic count_tokens when ANTHROPIC_API_KEY is set (free, deterministic), else a deterministic lexical heuristic. The record carries tokenizer so a trend is never silently compared across rulers.
  • lexical redundancy — shingle-containment (8-word shingles). Corpus % of duplicated shingle occurrences (intra- and cross-file restatement), each file's self-redundancy, and the top restated artifact pairs (e.g. the near-duplicate a11y / frontend-review skills). Lexical, deterministic, trendable — escalate to embeddings only if real paraphrase slips through.
  • threshold scorecard — length / redundancy / drift-risk graded green/amber/red by fixed formulas in lib/scorecard.mjs (not LLM judgments). Tune the bands in one place there.
  • cold-write totals — for each CI workflow that runs claude-code-action, what it cold-writes per run (always-on CLAUDE.md + its own prompt: block).
  • budget by harness layer — totals.byLayer rolls each skill/agent's tokens up by its layer: tag (method / stage / stack; epic #952), with untagged artifacts (CLAUDE.md, an un-tagged new skill) bucketed as unlayered so the per-layer tokens reconcile against totals.tokens. Quantifies how much of the always-on surface is the portable method vs. the swappable crouton stack.

Files

filerole
gather.mjswalk + count + score → one JSON record on stdout (--pretty adds a summary on stderr)
append-history.mjsappend the record to writeups/loop-station/history.jsonl, idempotent per commit
lib/tokens.mjscount_tokens with deterministic heuristic fallback
lib/redundancy.mjsshingle-containment redundancy + self-redundancy
lib/scorecard.mjsthreshold bands (the one place to tune)
writeups/loop-station/history.jsonlthe committed trend data (see its README)

Run by hand

node .claude/skills/loop-station/gather.mjs --pretty                       # inspect
node .claude/skills/loop-station/gather.mjs | node .claude/skills/loop-station/append-history.mjs   # record a point
LOOP_STATION_FORCE_HEURISTIC=1 node .claude/skills/loop-station/gather.mjs  # force offline tokenizer (deterministic tests)

In CI

.github/workflows/loop-station-inventory.yml runs on merge to main path-filtered to CLAUDE.md / .claude/skills/** / .claude/agents/**. It gathers (with ANTHROPIC_API_KEY → count_tokens), appends, and commits the new history.jsonl line back with [skip ci] and the causing PR recorded — one data point per relevant merge, with the cause attached, no filler.


WS2 — invocation trace

Reconstructs the real call tree of a session — which skills/agents/tools fired, how they nested, how long sub-agents ran — from Claude Code transcripts.

Hard privacy rule: the trace carries names + correlation ids + durations only, never a tool's input or a tool_result's content. It is runtime exhaust → gitignored, shipped from CI as an artifact, never committed (unlike WS1's history.jsonl).

What it reads

~/.claude/projects/<slug>/<session>.jsonl (+ its subagents/agent-*.jsonl). Two transcript layouts are auto-detected — the parser handles both because Claude Code has shipped both:

  • inline (current local schema) — sub-agents are isSidechain records in the main transcript; skills tag their calls with attributionSkill. Nesting comes from the parentUuid tree + those markers.
  • files (the proven prototype layout) — each sub-agent is its own subagents/agent-*.jsonl, linked to its spawning Agent call by global start-time order (robust for sync and async agents), carrying durations.

Both reconstruct 2+-level recursion (agent→agent→…) to the correct depth.

Files

filerole
parse-transcripts.mjsclaude harness: parse one Claude Code session → trace.jsonl of {ts,kind,name,parent,depth,agentId?,durMs?} (also importable: parseSession())
pi-telemetry.mjspi harness (#944): adapt pi.dev telemetry (native session JSONL + subagent meta, per writeups/architecture/pi-telemetry-schema.md) → the SAME WS2 event shape and the #883 ledger slice. buildPiTrace(dir) / runOutcomeToLedgerRecord(outcome); CLI: node pi-telemetry.mjs <dir> [--ledger]
pi-telemetry.test.mjsruns the adapter against the real captured fixtures (pocs/loop-station/data/pi-telemetry-sample/); asserts the ledger slice passes the real eval-ledger/schema.mjs validator + payload-freeness
collect-traces.mjsCI collector — discover the run's session across all project dirs, tag events with the run id, write one NDJSON file (meta header + tagged events) for artifact upload
lib/parse-transcripts.test.mjsfixtures for both layouts, 2-level recursion, payload-freeness, defensiveness

Harness parity (#944)

WS2 reads whichever harness is active. The data seam (pocs/loop-station/scripts/prepare-data.mjs) branches on AGENT_HARNESS: pi → pi-telemetry.mjs (live PI_TELEMETRY_DIR of subagent metas, else the committed real sample); anything else → the claude transcript parser. One feed, two consumers: the same pi telemetry yields the WS2 trace and the {model,cost,turns,wall} slice for the #883 run-outcome ledger — so the cost ledger consumes pi telemetry, it doesn't re-derive it. Note: pi's WS2 trace is agent-granularity today (one node per subagent); tool-level nesting arrives when pi-otel spans are actually collected (schema doc §3, not yet wired).

Run by hand

node .claude/skills/loop-station/parse-transcripts.mjs --out trace.jsonl   # latest session
node .claude/skills/loop-station/parse-transcripts.mjs <session> --json     # inspect
node .claude/skills/loop-station/collect-traces.mjs --out loop-station-trace.jsonl

In CI

Every Claude-agent workflow ships its trace via the composite action ./.github/actions/loop-station-trace (one uses: step after the agent, if: always(), tolerant — never fails the job it rides along with). Each ephemeral runner ships its trace tagged by run_id; the weekly WS-A rollup (below) aggregates the artifacts. The pi workflows are excluded — their trace comes from pi telemetry (#944), not Claude transcripts.


WS-A — cross-run usage rollup (#1064)

Turns the per-run trace artifacts (which otherwise expire unread) into a committed, trendable usage fact: per-skill/agent invocation counts across all CI runs in a window. This is the usage side of the dead-weight join — the observatory panel (#1065) and the advisor's dead-weight rule (#1066) read it.

Privacy line: raw traces stay gitignored/artifact-only (WS2 rule). What gets committed is the aggregate — names + counts, the same granularity history.jsonl commits for size. The record carries source: 'ci-rollup' and scope: 'pipeline' so a consumer can't over-read it: 0 means "never fired in CI", not "never used" (interactive coverage is #1067).

Files

filerole
aggregate-usage.mjsN trace NDJSON files → ONE usage record (counts per name, runs, workflows, first/lastSeen). Importable aggregate(texts, opts). Zero input ⇒ a visible meta-only record, never silence
append-usage.mjsappend the record to writeups/loop-station/usage.jsonl, idempotent per ISO week (exports isoWeek())
lib/aggregate-usage.test.mjscounting, attribution, meta-only-on-empty, scope fields, week-key idempotence
writeups/loop-station/usage.jsonlthe committed usage trend (one record per week)

Run by hand

node .claude/skills/loop-station/aggregate-usage.mjs --window 7 trace1.jsonl trace2.jsonl \
  | node .claude/skills/loop-station/append-usage.mjs

In CI

.github/workflows/loop-station-usage.yml runs weekly (Mondays 06:41 UTC, before the advisor): list the window's loop-station-trace-* artifacts → download → aggregate → append → commit back [skip ci]. Fail-loud contract (#1037): a listing failure fails the job (an outage must not read as a quiet week); zero artifacts appends a meta-only record (a gap you can see).


WS5 — advisor (state → actionable ticket)

Turns the observatory from numbers-to-look-at into decisions. An agent reviews the inventory state and, only when something's actionable, files a single GitHub issue assigned to the maintainer with concrete recommendations.

Two layers, kept separate: deterministic numbers → the WS4 digest (no LLM); qualitative remarks → a ticket (this). The LLM never touches the trend and only recommends — epic #926's observatory-not-builder boundary holds.

Files

filerole
advisor.mjsdeterministic gate — reads history.jsonl + usage.jsonl, surfaces candidate findings (scorecard reds, sharp always-on growth, redundancy jumps, dead-weight skills), decides actionable. No LLM, no issue. Importable analyze() / usageCoverage().
lib/advisor.test.mjsfindings logic (reds flag, growth flags, cross-tokenizer deltas are NOT compared, dead-weight coverage gates, deterministic)
.github/workflows/loop-station-advisor.ymlweekly: run the gate → only if actionable invoke claude-code-action to open/update ONE loop-station-advisor issue assigned to pmcp

Dead-weight rule (#1066)

Joins WS1 size × WS-A usage: an oversized skill (≥ the scorecard's artifact amber band) that provably never fired becomes one dead-weight finding listing the candidates. "Provably" is gated — the rule judges ONLY when the usage rollup covers ≥ 60 cumulative days AND ≥ 5 observed runs (tune in ADVISOR); anything thinner stays silent with usage.why naming the reason, because "no data" must never read as "dead". Evidence carries scope: 'pipeline' — 0 means never fired in CI, not never used (#1067).

Why the gate is deterministic

The cheap deterministic pass decides whether to bother the human (and whether to spend an LLM call) — so the model runs only on a real signal, never on a quiet week, and the trend numbers stay LLM-free. Deltas are compared only within the same tokenizer (a heuristic→anthropic switch isn't real growth).

Run by hand

node .claude/skills/loop-station/advisor.mjs --pretty   # see findings + actionable verdict

WS6 — accountability scoreboard (#1570)

The reviewer-vs-author lens: every confirmed defect is a severity-weighted, zero-sum-ish transaction — −w to the author flow, +w to the gate that caught it — and a clean merge earns its author +1. Turns review gates and coding agents into opposing teams so we can see who ships clean and which gates actually earn their keep.

Boundary holds: a new lens over existing data, not a new pipeline. It joins the findings ledger (writeups/loop-station/findings.jsonl) × the run-outcome eval-ledger (writeups/reports/eval-ledger.jsonl, #883). The tally is deterministic arithmetic — no LLM. Severity comes from the gate's own rating.

The asymmetric model (decided on #1570)

EventAuthorCatcherGate that missed it
Defect caught in review−w+w—
Clean merge, stays clean+10—
Defect escaped, caught later−w·2+w−w
Flag rejected (false-positive)0−w (noise)—

w is severity-weighted (critical 5 / high 3 / medium 2 / low 1). A find scores only once confirmed (fix merged / reverted / lgtm) — unconfirmed = pending.

Two lanes (class). defect (default) = a correctness/security/a11y/convention failure — the main board. quality = a preference on correct code (a /simplify cleanup) — a separate low-weight lane that never touches an author's defect Net/Rate (so it can't punish verbose-but-correct code or drown the defect signal). A quality gate captures on any change (capture-finding.mjs --gate simplify --class quality), not just 🔴 critical.

Files (live in scripts/eval-ledger/ with the ledger they join)

filerole
findings-schema.mjsfinding record shape + validate() + transactionsFor() (the scoring rules — tune weights here) + dedupKey()
append-finding.mjsvalidate + append ONE finding to findings.jsonl (idempotent via dedupKey; --check / --no-dedup)
accountability.mjsjoin findings × ledger → two leaderboards (markdown / --json / --html); importable tally()
capture-finding.mjsgate-side: a <gate>-verdict.json → a pending finding candidate (only for 🔴 critical)
ingest-findings.mjsrollup-side: resolve candidates by PR-merge fact (merged → confirmed · closed → drop · open → skip); importable resolveCandidates()
reconcile-findings.mjsrollup-side: reverted eval-ledger rows → escaped-defect findings; importable reconcile()
accountability.test.mjspins the arithmetic + reconcile + candidate resolution (19 tests)

Capture in CI (#1570)

Two deterministic sources feed findings.jsonl — no LLM, no CI state machine:

  1. PR gates (frontend-review / a11y / red-team) upload a finding candidate artifact (loop-station-finding-*) whenever they flag a 🔴 critical. Confirmation is the durable PR-merge fact: merged ⇒ the blocking defect was fixed ⇒ a confirmed caught defect; closed ⇒ dropped; open ⇒ left for a later run.
  2. Reverts — a reverted run in the eval-ledger ⇒ a confirmed escaped defect.

.github/workflows/loop-station-findings.yml (merge-to-main + weekly, mirrors loop-station-usage.yml) downloads the candidates, resolves them, runs reconcile, and commits new findings to main. Only this main-context job writes the committed ledger — a PR-branch gate run never does. Rendered in pocs/loop-station (the AccountabilityBoard panel, staged by its prepare-data.mjs).

Run by hand

node scripts/eval-ledger/accountability.mjs            # the two leaderboards
node scripts/eval-ledger/append-finding.mjs --gate code-review --severity high \
  --status confirmed --confirmed_via fix-merged --author_flow task-worker --author_ref <PR-url>

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

a11y

無料

Accessibility review for Vue surfaces — the code-cleaning analog of /code-review and /simplify, pointed at WCAG/ARIA. Reviews just your diff (or a package/file), rates findings by severity, and either comments inline on the PR (--comment) or applies the safe fixes for you (--fix). Steers the depth-aware `a11y` subagent. Use when asked to "check accessibility", "a11y this", "audit ARIA/keyboard", or run /a11y.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月6日 更新

ask-human

無料

Emit a blocking question the owner can read in ~10 seconds and answer in one reply — the scannable, recommendation-first handoff every agent posts when it hits a fork it can't own. Leads with the one decision + a recommendation, carries the 🤖 provenance header, doubles as the

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月6日 更新

audit

無料

Audit packages for documentation completeness, detect drift between code and docs, and maintain documentation quality across the monorepo. Use when checking package docs, running audits, or reviewing documentation health.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月6日 更新

Author a placeable layout block that looks right at ANY pane size. The one hard rule — size to the PANE with container queries (@container), never the viewport — plus list/form playbooks and the sizing contract (minWidth etc.) the viability metric reads. Use when adding/converting a croutonLayoutBlocks block, or when a block overflows/breaks in a narrow pane.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月6日 更新

When a bug or regression is reported, the FIRST step — before fixing — is to research how and when it was introduced (git archaeology), then record that finding on the tracking issue/PR. Use the moment a bug, error, broken build, or "this used to work" is reported, before writing a fix. Produces a first-bad-commit (or "not a code regression") note you paste onto the issue.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月6日 更新

commit

無料

Smart, granular git commits following monorepo conventions. Analyzes changes, filters to session-relevant files, groups by intent, and uses conventional commit format. Use when committing code changes.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月6日 更新

FriendlyInternet のスキルをすべて見る

このスキルの問題を報告する