Sno Station
Sno Station은 AI 에이전트를 하나의 팀으로 묶는 오픈소스 워크스테이션으로, 로컬 머신에서 에이전트 협업을 가능하게 함
Claude Code 플러그인, 풀 리퀘스트를 HTML 리뷰 맵으로 변환해 검토자가 변경을 판단하기 전에 읽을 수 있게 합니다
A Claude Code plugin to deal with comprehension debt. Turns a pull request into a published HTML review map a reviewer can read before judging the change.
플러그인HTML · RubyGitHub @wyeworks직접 설치운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
설치형 프로젝트는 배포 도메인 없이도 확인할 수 있습니다. 개인 저장소는 GitHub 로그인으로, 조직 저장소는 위의 저장소 확인 파일로 직접 확인해 주세요.
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
AI-assisted code review for teams that want to move faster with coding agents without losing control of their codebase.
accountable-review turns a pull request into a Review Map: a published HTML page that guides a
reviewer through what changed, how the new behaviour works, what existing code is affected, and what
to understand before merge.
It ships two skills: review-map, which produces the page for a Rails or an Elixir/Phoenix
codebase, with or without a separate client such as Next.js; and setup-ci, which arranges for
one to be produced automatically on every review-ready pull request.README 전문 보기 ↗AI-assisted code review for teams that want to move faster with coding agents without losing control of their codebase.
accountable-review turns a pull request into a Review Map: a published HTML page that guides a
reviewer through what changed, how the new behaviour works, what existing code is affected, and what
to understand before merge.
It ships two skills: review-map, which produces the page for a Rails or a Rust codebase — a
Rust backend or Rust in general — with or without a separate client such as Next.js, with
Elixir/Phoenix and React (a Next.js app or React in general) support still in development; and
setup-ci, which arranges for one to be produced automatically on every review-ready pull
request.
Built by WyeWorks.
AI coding tools can produce large changes much faster than teams can absorb them.
Tests can pass. AI reviewers can find issues. Coding agents can fix those issues.
And still:
Do you understand how the system works now?
That is the problem accountable-review focuses on.
When code enters the codebase faster than the team understands it, short-term speed can become long-term loss of control. That gap has a name — comprehension debt — and it comes due the first time someone has to change the code nobody read.
The answer is not less AI. It is more reviewer understanding alongside it — more productivity and more comprehension, rather than one bought with the other:
Move faster with AI. Stay in control.
AI code review is great at asking:
accountable-review helps the human reviewer ask:
The plugin does not approve the PR for you.
It helps a competent reviewer understand the change well enough to decide.
No approval verdict. No severity score. No fake confidence badge.
Human judgment stays final. A page good enough to approve from without reading the code would be a failure — the reviewer would be holding a verdict instead of a mental model.
Diffs are excellent for reviewing code line by line.
Is this condition correct?
Is this query efficient?
Did this line introduce a regression?
But modern AI-assisted development also pushes review to a higher level:
What behaviour changed?
How does this work across the system?
What must the team understand to maintain it?
A Review Map adds that layer.
A diff is organized by files.
A Rails, Rust, Phoenix or Next.js feature is not.
One behaviour may cross:
routes
↓
controller
↓
model / service
↓
policy
↓
job
↓
serializer
↓
frontend contract
On a Rust backend the hops are different — router and its layers, extractor, handler, error
mapping, query, migration — and on Phoenix different again — router, controller or LiveView,
context, changeset, Repo, worker, template — and on Next.js different again — page, server
component, client component, server action, cache tag, route handler — and the point is the same: no
directory contains the behaviour.
accountable-review traces the PR around the behaviour being implemented, not the order of
files in the diff — and then publishes the part of that work you have to act on: the handful of
judgments the change asks of you, and where to look to make each one.
A PR can change the meaning of code without changing its lines.
Examples:
A normal diff cannot show those relationships. A Review Map can.
A Review Map is a review agenda: the smallest set of things you have to judge before you can approve a change, with the code that settles each one attached.
Five parts, and a shut evidence block at the foot:
What changed one paragraph: what is now true that was not
Context when earned: the pieces of this repository the judgments rely
on, for a reader who knows the stack but not the codebase
What needs your attention 3-5 checkpoints per independent change the PR makes, 7 at the
outside (9 or 11 on a broad change to application code);
about behaviour, structure or how the code was built;
each one judgment, framed as a question, and at
most one small figure where its shape is clearer than prose:
a chain, paths converging on one invariant, a lifecycle, or
an entity and its relationships
Read the code in this order 3-7 stops, in the order that builds understanding
Impact outside the diff 1-3 chains, from changed code into code it gives new meaning to,
each node linked to the file it lives in
▸ Evidence & diff coverage every changed path, the searches run, the rest of what was found
Claims about unchanged code come with the code attached: a collapsed excerpt of the real source, quoted by a script rather than retyped, that you open when you are ready to check that particular claim. The page reads completely with every excerpt closed — the sentence carries the consequence, the excerpt carries the proof.
The Review Map does not replace the diff.
It helps the diff make sense.
📖 Full anatomy of the page — every section, the checkpoint, the staging behaviour, the excerpt and
framework-anchor rules — is in docs/review-map.md.
Add the WyeWorks marketplace and install, from inside Claude Code:
/plugin marketplace add wyeworks/claude-plugins
/plugin install accountable-review@wyeworks
or from a terminal:
claude plugin marketplace add wyeworks/claude-plugins
claude plugin install accountable-review@wyeworks
Restart, and the skills are available in every project as /accountable-review:review-map and
/accountable-review:setup-ci. claude plugin update accountable-review@wyeworks takes the next
release; you only receive one when the version in the plugin's manifest moves, so an update is
something you ask for.
Add --scope project to both commands to declare the plugin in a repository's own settings, so
everyone working on it gets the same one.
To run it from a checkout instead — which is what you want if you are changing the plugin, since
/reload-plugins then picks up your edits without restarting:
git clone https://github.com/wyeworks/accountable-review.git
cd /path/to/your/app
claude --plugin-dir /path/to/accountable-review
Nothing is installed that way, so git pull in the checkout is how you update, and the skills exist
only for sessions started with that flag.
This repository is its own Codex marketplace. From a terminal:
codex plugin marketplace add wyeworks/accountable-review
codex plugin add accountable-review@accountable-review
Restart Codex, and the skill is available in every project as $accountable-review:review-map —
the same name as in Claude Code, behind Codex's $ instead of /. codex plugin marketplace upgrade accountable-review fetches the latest catalogue, and as with Claude Code you only receive a
release when the version in the plugin's manifest moves. codex plugin remove accountable-review@accountable-review uninstalls it.
Open the repository you want to review in Codex, then invoke:
$accountable-review:review-map
The result is a local HTML file, linked from the response, using the same template and
completeness gate as Claude. To choose its destination, add --output /absolute/path/outside-the-repo;
the page is written as index.html there. No hosting service or publishing plugin is required.
High effort is the default and requires Codex subagent tools for the independent falsification
pass. If those tools are unavailable, the skill reports the limitation; use --effort low
explicitly to run without independent readers. The page never presents that pass as an approval.
Codex CI execution is not supported yet. setup-ci and the CI runner still use Claude Code
and Anthropic credentials, so the Codex plugin ships review-map alone.
To run it from a checkout instead — which is what you want if you are changing the skill, since edits apply without reinstalling — link it into Codex's skills directory:
mkdir -p ~/.agents/skills
ln -s /path/to/accountable-review/skills/review-map ~/.agents/skills/review-map
Linked that way it is a standalone skill invoked as $review-map, and git pull in the checkout is
how you update. Use the marketplace or the link, not both, or Codex lists the skill twice.
See Codex setup and verification for removal and the boundaries of this integration.
The skills live under skills/ as ordinary Agent Skills, so the
cross-agent skills CLI installs them into Claude Code
and Codex without cloning anything:
npx skills add wyeworks/accountable-review
It asks which skills and which agents; answer in flags instead with, for example:
npx skills add wyeworks/accountable-review -g --skill review-map -a claude-code -a codex
Prefer -g. Without it the skills are copied into the current project (.agents/skills/,
.claude/skills/ and so on), which puts files in the repository you are about to review. npx skills update takes new commits, and npx skills remove review-map uninstalls.
Installed this way the skill is a standalone one rather than part of a plugin, so in Claude Code it
is invoked as /review-map instead of /accountable-review:review-map, and in Codex as $review-map
instead of $accountable-review:review-map. --effort high still works in Claude Code: the independent readers
are launched as general-purpose subagents handed the same bundled mandate, rather than as the
plugin's registered claim-falsifier agent. Install through the plugin or the skills CLI, not
both, or Claude Code lists the skill twice.
The CLI can place the skills in any other agent it supports, Pi for example. Outside Claude Code,
review-map follows one set of instructions whichever agent it is: the page is a local HTML file,
and --effort high needs an independent reader — the agent's own subagents, or else a read-only
background run of its own CLI. An agent with neither says so and offers --effort low. Only
Claude Code and Codex are tested.
setup-ci is offered too — /setup-ci in Claude Code, the only host it works in. The workflow it
writes clones the plugin itself at a pinned tag, so how you installed the skill locally does not
matter to CI.
Run it from inside the repository you are reviewing:
/accountable-review:review-map # current branch against its base
/accountable-review:review-map 412 # a PR number
/accountable-review:review-map https://github.com/org/repo/pull/412
/accountable-review:review-map feature/some-branch
In Claude Code you get back a URL. The page is a private Claude Artifact until you share it.
Re-running for the same PR publishes a new map and leaves the earlier one where it was; --update
edits the earlier map in place, so the Review Map tracks the PR across pushes at one URL.
It publishes early and fills in as parts complete: open it at minute two, watch it arrive, start reading the moment the part you need lands. The checkpoints arrive one at a time, and their questions arrive first — so you know what the change is asking you to judge well before the explanations land. While it is unfinished it says so in a banner, and every part still coming is marked pending, so a half-written page can never be mistaken for a finished one.
While it runs, Claude Code's status line shows what it is doing — tracing consumers, cutting
excerpts, writing the page — with the elapsed time and how many checkpoints are written. Every
field is read from the run rather than estimated. The one exception is a bar, labelled ~. It
measures against earlier runs of the same kind in that repository, so it appears once one such run
has finished with its coverage gate passed.
The same line counts what the run spends: tokens across every model request the run makes, its falsifiers' included, and — on a Claude subscription — how far your 5-hour usage window has moved since the run began. When the run ends, the transcript gets one line with the breakdown and each window's before and after. The window percentages are your account's, so anything else you run meanwhile moves them too. In Codex, which has no status line a plugin can draw on, the run reports the same line in chat at the end, read from Codex's own session log.
To have one generated for every pull request instead of by hand, see CI integration below.
This generates the default Review Map for PR #412. The skill works best for PRs that are about to be merged, but it also works well with already-merged PRs when you want to catch up on changes.
/accountable-review:review-map 412
What makes it onto the page is the part you actually need to act on. For a small or medium-sized PR, that usually means around 700 to 1,500 words.
/accountable-review:review-map 412 # --effort high, the default
/accountable-review:review-map 412 --effort low # opt out of the falsification pass
Everything the skill writes rests on claims it checked itself — and the context that wrote a claim is
the one least able to see what it assumed. --effort high, the default, adds a second reader that
does not share that context. The run writes its analysis down first, one note per behaviour, and
sends a read-only claim-falsifier subagent at each note before any of it reaches the page, with
a single mandate: assume this is wrong in ways that matter, and find evidence in the repository that
contradicts it. It rewrites nothing; it returns challenges, each anchored in a line it opened. The run
then opens the cited file itself and corrects, downgrades or drops the claim. A challenge it cannot
confirm is dropped, exactly as an unconfirmed finding is.
It is on by default because it costs almost no waiting and it changes what the page finds: on a
28-file pull request the whole pass cost 23 seconds of waiting, under 1% of the run, and the same
change reviewed without it missed five things the falsified page carried. What it does cost is tokens
in the readers' own contexts, a few percent of the run's. --effort low turns it off, which
is worth doing when the diff is small enough that a second reader has nothing to find.
A third axis, and the only one that puts anything inside a checkpoint:
/accountable-review:review-map 412 --mentor # add framework primers
/accountable-review:review-map 412 --mentor rails # the same, naming the stack
A Review Map normally assumes you know the framework and are meeting this change for the first
time. --mentor is for the other case — a reviewer new to Rails, to Rust, to Phoenix or to React,
on their first pull requests in an unfamiliar codebase. Where a judgment turns on a framework rule they may not
know, the page stops linking to the manual and states the rule: a short primer inside that
checkpoint, with the API named, the behaviour explained, a worked example on a generic class, the
line in your repository that made it relevant, and the pinned documentation link it came from.
Phoenix and React today: a primer is gated on the documentation link it escalates from, and the Elixir and React catalogues ship closed until a verification run has opened every row in them. So
--mentoron a Phoenix, React or Next.js project currently produces no primers and says so. That is the fail-closed rule doing its job — a page with no primer is narrower, a page with an invented link is wrong. The Rust catalogue shipped closed the same way and has since been opened, so a Rust page can carry primers, framed in graphite rather than Rails red.
/accountable-review:review-map 412 --update # re-read only the new commits
A Review Map describes one revision, and a pull request that keeps gaining commits after review
opens ends up with a map that quietly describes an older one. --update is the cheap way to keep
it current: it reads the commits since the page it is updating, re-analyses the judgments those
commits reach, and edits that page in place at the same URL. What the new commits did not touch is
carried, which is where the saving comes from — tracing consumers across the diff is most of a
run's cost, and an update traces only what moved.
You are trading re-reading for speed, and the page says so. A carried judgment is one this run
did not verify again. So an updated page names both revisions in its masthead and carries one
sentence saying which parts still describe the earlier one. If you want the fuller read, run it
again without --update — a map generated from scratch describes one revision throughout, and
that is the right call before a final review pass on a branch that has moved a lot.
It refuses rather than guessing. A force-push or rebase, a base branch that moved underneath, a delta covering more than half the diff, a lock file bump, or a recorded search that now finds the changed code — each of those means the previous page is not a safe thing to build on, so the run regenerates from scratch and tells you which one it hit.
The tool separates what is known from what is inferred.
A statement may come from:
A claim the diff shows directly carries no label. Everything else is marked — from unchanged code, inferred from tests, inferred, uncertain — so an inference can never pass as a fact. Where the tool cannot establish intent, it says so:
It is unclear whether existing time entries stay editable after archival. No test covers it.
Every claim also carries a file:line into your repository, and by default a second reader attacks
those claims before the page is finished (see Usage → effort).
Nor does the page claim to have found everything — see What a Review Map cannot do below. It never reads as a clean bill of health, and it never carries a boilerplate disclaimer saying so either: the limits are the same on every Review Map, so they are written down once, here, rather than reprinted under a heading you have already read a dozen times.
The goal is not to sound confident. The goal is to help the reviewer investigate the change.
A Review Map is written by a model reading your repository. That is what lets it trace a consequence into code the diff never opened, and it is also the honest limit on the page.
file:line, so open the citation for anything you would act on.And it depends on the model behind it. We develop and test with Claude Opus 5 most of the time, and that is what the page's depth is calibrated against. Other models will trade cost for reach differently — try a few against your own codebase and keep the one whose maps you actually trust.
The plugin is optimized and most heavily tested for Rails applications. That matters because Rails behaviour often emerges from several pieces working together:
The plugin is designed to help reviewers understand those relationships as a system, and it knows
where the framework's own rules bite: update_all at a call site the diff never opened skips the
validation this PR adds, a uniqueness validation is not a unique index, --sandbox rolls back so
after_commit never fires there.
It also reads the app for what your team already decided. A value object in app/models is
ordinary; a value object in app/models when four of its kind live in app/services is a choice
someone made, and the page will ask whether it was deliberate — with the four siblings cited, because
without them there is nothing to ask. That question is never a recommendation, never appears more than
once, and never takes a slot from a judgment about behaviour.
Rust is also supported and tested, and it comes in two lenses, because what a reviewer looks
for in a crate that serves requests and in one that does not overlaps less than the language
suggests. Rust in general — a library, a CLI, a workspace that serves nothing — is reviewed against the things the
compiler was told not to check or cannot see: the _ => arm a new enum variant falls into silently,
a pub item a downstream crate depends on, a feature combination CI never builds, the module whose
safe code keeps an unsafe block sound. A Rust backend — axum, actix-web, tonic and the
rest — gets that lens and a second one on top of it: an auth layer that covers only the routes
registered before it, an Extension nobody added, and a migration whose unchanged queries still
compile against stale offline query data.
Elixir/Phoenix support is still in development. There is a lens for a LiveView app or a JSON API
that catches the same kind of thing: Repo.update_all builds no changeset, a unique_constraint
does nothing without the index behind it, and a phx-click renamed in a template without its
handle_event clause crashes the LiveView the first time someone clicks it. Parts of it are not
finished yet, such as a Phoenix backend with a React frontend, and it has had far less testing
than Rails or Rust.
React support is still in development too, and it comes in two lenses, built the way Rust's are.
React in general — a Vite single-page app, a component library, a React Router app — is reviewed
against what TypeScript cannot see: an effect whose dependency array stopped naming what it reads, a
wrapper <div> that resets a form's state on every toggle, a context value rebuilt on every render,
and every place a component, a hook or a query key is consumed outside the files the diff touched. A
Next.js app gets that lens and a second one on top of it: a server action that is a public
endpoint with no authorization of its own, a cookies() read that turns every route rendering a
shared header dynamic, per-user data cached for everyone, and a mutation that revalidates the page it
changed and not the dashboard that lists it. Its documentation catalogue ships closed like Elixir's,
so a React page anchors with probes — npm ls, tsc --noEmit, a test runner's list mode, next build's route table — rather than links, and it has had less testing than Rails or Rust.
Which you get is detected from the repository — a Gemfile, a mix.exs, a Cargo.toml or a
package.json that depends on react, and for Rust and React whether the code the diff touches
depends on a server framework or on next — not configured; a repo holding more than one asks which
to cover. A Rails, Phoenix or Rust repository with a React client is reviewed as the backend when the
diff touches it, and as React when the diff is only the client.
Two, against real pull requests in public Rails codebases:
🧭 Read the example Review Maps
| RubyGems.org #6699 — Record every stint a user spends owning or maintaining a gem | An additive diff that all looks safe — a new table, its callbacks, a backfill — where the judgments are about unchanged callers: every path that starts or ends an ownership has to keep the new history in step with it, including the ones that never run the callbacks. |
| Discourse #43845 — Email-code signup collects its details before it creates the account | The case the format exists for: most of what a reviewer has to decide is not in the diff — whether every request that creates an account still passes the CAPTCHA, and what the new signup step does for a visitor who is not logged in yet. The change moves which request creates the account, and the page shows that move before any checkpoint relies on it. |
They are public repositories on purpose: every file:line citation on those pages resolves, so you
can follow any claim into the code it is about. Both are ordinary output at the default settings,
unedited after the run produced them, and regenerated with every release; examples/README.md
says which version and revision each one is.
Worth opening them for:
Both were generated with version 1.0.1. The page format moves between releases, so
examples/README.md records which version produced each page and how to
regenerate them — a linked example quietly rendering an old format is worse than none.
The other way to see one is to run the skill against a branch of your own; a four-file bugfix produces a one-screen page in a couple of minutes.
One command turns "someone runs the review map by hand, sometimes" into "every review-ready pull request has one, and the whole team can open it":
/accountable-review:setup-ci
pull request marked ready for review
↓
Review Map generated for that exact revision
↓
uploaded as a GitHub Actions artifact
↓
available to everyone who can see the repository
Every reviewer opens the same artifact instead of independently reconstructing the same context, and it is there from the moment the pull request becomes reviewable.
Setup looks at the repository first — what CI you already have, whether Claude Code already runs in
it, what conventions your workflows follow — and then writes one file,
.github/workflows/accountable-review.yml. It touches nothing else, and running it twice is safe:
the second run compares what it would write against what is there and says unchanged.
| Triggers | opened, ready_for_review, reopened — one map per pull request |
| Draft pull requests | Ignored — pushing to a draft costs nothing |
| Fork pull requests | Skipped: a pull_request run from a fork gets no secrets |
| Bot pull requests | Skipped: a dependency bump has no judgments to stage |
| Pull requests changing no application code | Skipped — the run says what changed and why none of it earned a map |
| Trivial application changes | Skipped — 2 files and 20 lines or fewer of application code; both configurable |
| Delivery | GitHub Actions artifact, kept 30 days |
| The link | One comment on the pull request, updated in place, naming the revision |
| Concurrency | One run per pull request; superseded runs cancelled |
| Permissions | contents: read, plus pull-requests: write for that one comment |
Setup shows you those before it writes anything, because each decides either when a model run happens on your account or what the job is allowed to do, and asks once. Change any of them there and the workflow is rendered your way — and re-running setup later to move the version pin reads your answers back out of the file rather than reverting them.
The comment is the whole of the write scope. The job cannot push, cannot touch your code, cannot
approve and sets no check — and --no-pr-comment drops the step and the scope together. There is no
"Review Map: passed" status, and there will not be one: a passing check is a verdict, and this page
does not carry verdicts.
One thing is left for you: the credential. Add one of two repository secrets. ANTHROPIC_API_KEY
is an API key from the Anthropic Console, billed to that API account. CLAUDE_CODE_OAUTH_TOKEN is
what claude setup-token prints — run it once on a machine where Claude Code is already signed in,
paste the token in under that name, and the runs bill against that account's Claude subscription
instead of API credit. That is usually what a team already paying for Claude Code wants, and it is
the option the workflow file cannot tell you about, since it names the variable and not where the
value comes from. The token is personal and long-lived rather than permanent: re-run the command and
replace the value when it expires. Setup cannot see your secrets either way, so it says outright that
this is outstanding rather than implying everything is ready.
A pull request that only touches documentation, tests, tooling or a lockfile gets no Review Map —
there is nothing for one to explain. Neither does a trivial application change: two files and
twenty lines or fewer, both, so a change that is large by either measurement still earns one. The
counts are over application code only, so a lockfile's five thousand lines do not make a three-line
model change look substantial. Both numbers live in .accountable-review.yml, and either at 0
gives you a map for every change that touches code. docs/ci.md has the rule and the trade.
One cost worth knowing, and it is quiet: a push does not regenerate the map, so on a branch that
keeps moving it describes an earlier revision while looking current — the revision in its masthead is
how you tell, and --regenerate-on-push is how you change it. A skipped pull request is not the same
kind of quiet: the run still happens and its summary says which rule skipped it and what it counted,
so "too small for a map" never looks like a broken workflow.
The workflow is analysis-only, and its entire effect on your repository is that one comment. It never pushes, never approves, never merges, never labels, sets no check and no status, and it never boots your application: no migrations, no database service, no scripts from the pull request. That is the same principle the page itself follows — validation commands are shown to a reviewer, never run on their behalf.
🚚 Artifacts are the default, not the contract: a Review Map is portable static HTML, and generation
is separated from delivery so a team can send it somewhere browsable instead. See
docs/ci.md for the delivery seam and how to add a provider.
| Supported agents | Claude Code and Codex, each installable as a plugin from its own marketplace or into either with npx skills add wyeworks/accountable-review. In Codex the plugin ships review-map only. Claude ships two skills — review-map, which produces the page, and setup-ci, which configures CI — plus one subagent, claim-falsifier, sent at each of the run's own analysis notes at --effort high. Deliberately single-context otherwise: an earlier version fanned work out to helper agents and paid 41% of its wall clock in a single stalled turn. |
| Repository analysis | git for the diff, the base and head SHAs, and the searches; gh when present, for PR metadata and deep links. Nothing else is required. |
| Stack detection | A Gemfile or config/application.rb selects the Rails lens and catalogue; a mix.exs selects the Phoenix pair; a Cargo.toml selects the Rust lens and catalogue, plus the backend lens when the crates the diff touches depend on a server framework; a package.json depending on react selects the React lens and catalogue, plus the Next.js lens when the package the diff touches depends on next. A repo with more than one asks; a repo with none says so and covers the diff with the stack-independent parts of the page rather than applying a Rails lens to something that is not Rails. |
| Rails discovery | Rails root (repo root, a subdirectory, an engine), API-only vs server-rendered, the authorization library, and the Rails series and gem versions from Gemfile.lock, which is what documentation links are pinned to. |
| Rust discovery | The workspace and its members from Cargo.toml, each crate's package name, kind and features, whether it is published, the test runner CI uses, and on a backend the framework, the database layer and how authentication is attached. Each crate's exact version comes from Cargo.lock and the toolchain's from rust-toolchain.toml or rust-version — docs.rs serves exact versions, so there is no series. |
| Phoenix discovery | The Mix project and OTP app name from mix.exs, lib/<app> against lib/<app>_web, LiveView vs JSON API, and each package's exact version from — hexdocs serves exact versions, so there is no series. |
Nothing is required, and that is deliberate: every setting is a thing that can go stale against the repository it describes.
What you choose per run — effort, mentor and context can also be a team's standing answer in
.accountable-review.yml (below), and a flag beats the file for one run:
| Target | PR number, PR URL, branch, diff range, or nothing for the current branch against its base. |
| Effort | --effort high (default) or --effort low. |
| Mentor | Off by default; --mentor (optionally --mentor <stack>) adds framework primers for a reviewer new to the stack, and --mentor off overrides a file that turned it on. |
| Context | --context auto by default: the repository-orientation section appears only when a checkpoint needs it. never drops it, always lowers the bar for a team onboarding people into the codebase (it still never invents an entry), collapsed puts it behind a toggle. |
| Theme | Daylight by default; workshop or field-notes via review_map.theme in .accountable-review.yml. A setting of the repository, not a flag — and only the default: readers switch from the page's Aa menu. |
| Update | A flag only, off unless you pass it: --update re-reads only the commits since the existing page and edits it in place. CI turns it on for you (review_map.update). |
| Output | A published artifact in Claude Code, a local HTML file in Codex; --output <dir> writes static HTML to a chosen directory instead. |
A repository's standing answers live in an optional .accountable-review.yml — the whole schema,
every key optional:
review_map:
effort: high # high | low
mentor: false # true | false | rails | elixir | phoenix | rust | react | nextjs
context: auto # auto | never | always | collapsed
theme: daylight # daylight | workshop | field-notes
update: true # CI only: edit the previous map on a push rather than rebuild it
trivial_files: 2 # CI only: skip a change this small in application files
trivial_lines: 20 # and in application lines
delivery: # CI only
provider: github-artifact
retention_days: 14
The first four are read by the skill itself, so they apply to every Review Map of the repository, whoever generates it — on your laptop (from the copy you have checked out) and in CI alike. The rest only mean something in CI. The whole file is checked on every run, so a misspelt key stops your local run rather than surfacing in a CI job later.
Daylight is the default theme; Workshop and Field Notes are the alternatives. The key sets the look a page opens in, and every page carries all three: a reader can switch theme, and light, dark or the system's choice, from the Aa menu in the masthead, and their browser remembers it. A theme changes typefaces, radii and hues — never what is on the page.
There is no key for the page's shape, because there is no shape to choose. A key the reader does not recognise is an error rather than a shrug — a misspelling that parsed as nothing would silently give a team the default while their file said otherwise.
Precedence is explicit flags > .accountable-review.yml > defaults, and it is implemented rather
than aspirational: the config reader emits a line only for a key the file actually contains, so
"configured to the default" is distinguishable from "not configured". setup-ci will not write a
file that only restates the defaults — a file nobody chose is one more thing to keep in sync, and a
later reader treats retention_days: 30 as load-bearing when nobody picked it.
Everything else is discovered instead of configured: which stack this is, the Rails root, the Mix
project, or the Cargo or JavaScript workspace, the test framework and package manager, whether the
app is API-only or LiveView, which Next.js router it uses, how authorization is attached, the
frontend location, the framework and package versions, and the project's own conventions. Where
a project documents conventions — CLAUDE.md, a style guide — the skill reads them; where it does
not, house style is inferred from adjacent unchanged code, which is usually more accurate than a
stale document anyway.
Repository-specific guidance is therefore expressed the way the rest of your tooling already expresses it: in the repo's own convention docs, not in a config file belonging to this plugin. Adding an assumption about project layout would be a regression, so if the skill guesses your layout wrong, that is a bug worth reporting.
Issues and pull requests are welcome. To run the plugin from a checkout without installing it:
cd /path/to/your/rails-app
claude --plugin-dir /path/to/accountable-review
/reload-plugins picks up edits without restarting. There is no build and no test suite in the usual
sense — the "source" is prose that another Claude instance executes, so changes are verified by
running the skill against a real PR and reading the page it produces, plus an eval harness that runs it
against real open-source pull requests and grades each page with calibrated LLM judges.
[!NOTE] The safety net is a draft. The deterministic tests and the eval harness cover the scripts and the mechanical page rules; they cover much less of the prose, which is the part that decides whether a page is right. Treat a green run as necessary rather than sufficient — solidifying that net is the next piece of work here, and until then a change is verified by reading a real page it produced.
See CONTRIBUTING.md for the layout, the eval loop and the release process.
MIT.
accountable-review is an open-source project by WyeWorks.
We build software and help teams adopt AI-assisted development practices without giving up the engineering understanding required to operate and evolve what they build.
AI can help us produce more code. The challenge is making sure our teams continue to understand it.
mix.lock| React discovery | The package the diff touches and its workspace, the package manager from the lock file, TypeScript or not, Strict Mode and the React Compiler, the state, data-fetching, form and routing libraries, and the test runner. On Next.js, which router the changed files use, the middleware or proxy and its matcher, how authentication is attached, and the database layer. The locked majors of react and next — react.dev and nextjs.org publish per major, so that is what a link pins. |
| Frontend discovery | Whether a separate client exists at all, and where its API client and types live. Contract judgments need both sides in the diff; with no client, or a PR that does not touch one, none is raised rather than raised emptily. A LiveView app has no separate client by design, so the same material goes to the seam it actually has: the phx-* attribute and the callback that answers it. On a React stack the frontend is the application, so what is looked for is the API it talks to, if any, and whether its types are generated from the server's or written by hand. |
| Test frameworks | RSpec, Minitest, ExUnit, Cargo's own harness (with nextest and snapshot crates), and Vitest or Jest with Testing Library and Playwright or Cypress, detected rather than assumed. Tests are read as evidence of intent, and the test gap is named per behaviour. |
| Review Map generation | Ten ordered steps, from resolving the target to the completeness gate. The diff is traced and clustered by behaviour, then a synthesis step turns that analysis into a ranked agenda of checkpoints; affected-but-unchanged code comes from search recipes per artifact kind; every claim is anchored to a file:line. |
| Output format | One self-contained HTML page — its own design system, light and dark, with collapsed source excerpts, figures built from components rather than drawn per run, and deep links chosen from a four-rung ladder depending on whether the head SHA is reachable on a remote. On an unpushed branch it degrades to plain text rather than emitting permalinks that would 404. |
| Publishing | In Codex or any other agent, a local HTML file. In Claude Code interactively, a Claude Artifact — private until you share it, filled in at one URL as the run goes; a fresh run publishes a new one and --update edits the last. --output <dir> makes the run non-interactive and writes <dir>/index.html as portable static HTML instead, which is how CI generates one. The page is never written into the repository under review; scratch files go to a work directory under $TMPDIR, derived from the repo and the target. It never posts to GitHub. |
| Completeness | One mechanical check at the final publish: set equality between the page's own inventory and git diff --name-only. A file cannot be silently dropped. |
| CI execution | GitHub Actions, via setup-ci: one workflow, superseded runs cancelled, delivery through a provider seam that defaults to a build artifact, and one comment per revision linking the map on the pull request — the only write the job can do, and the only reason it holds pull-requests: write. The triggers, the guard that skips drafts, forks and bots, and whether it comments are confirmed with you at setup, rendered from flags, and recorded in the file so a later upgrade does not revert them. Whether a given pull request is worth a map is decided after checkout by ci/application-code.sh — no application code, or too little of it — and a skipped run says which rule fired and what it counted. |