How the rules reach the model
Both hosts deliver riprap’s router through a SessionStart hook. Every riprap skill also
loads the same router when it is absent, so disabling or declining native hooks does not make a
skill lose the baseline. Installation writes neither CLAUDE.md, AGENTS.md,
.claude/settings.json, nor global Codex configuration.
Injecting is strictly better than writing a file into the project, for three reasons worth stating because the alternative looks easier:
- The project owns
CLAUDE.md. A tool that edits it is editing something it did not write and cannot fully understand. - An inserted block is one more thing to reconcile on every update. Merge markers in a file that a whole team edits is a recurring cost, paid forever.
- A project that stopped using riprap would still be carrying it. Uninstalling should actually uninstall.
The same reasoning covers the skills. They are namespaced by the harness as /riprap:install, /riprap:learn,
/riprap:spec, /riprap:architect, /riprap:implement, /riprap:advise,
/riprap:prune, /riprap:release, /riprap:review, /riprap:vet,
/riprap:handoff and /riprap:write,
so a repository with its own /learn or /review keeps it. There is nothing to merge and
nothing to collide with.
What it costs you in context
riprap is paid for on every turn, so it is careful about what it injects.
It is not paid on every entry, either. A session that is resumed or forked continues a context that already holds the router, so those two get one line naming where the rules are rather than the rules again — but only after the hook has found the earlier injection in the replayed transcript. It is never silence, and it is never a guess: without that confirmation, or after a plugin update moves the rules, the full router goes out as before.
What arrives at session start is a router of roughly 150 lines — the seven rules, a task-to-document map, and five rules restated in full. It is not the 21 guardrail documents themselves. Those are read when they are needed and not before, which is why the router carries a line count beside each entry: two 80-line files usually beat one 215-line file when either would answer the question.
The five exceptions are restated in full because the cost of forgetting them is not
symmetrical with the cost of carrying them. A model that has to go and read testing.md
before it knows not to weaken a test has already weakened the test.
Where a project rule and a riprap rule disagree
The project document wins. riprap carries generic standards; your repository knows things riprap cannot. Nothing riprap ships overrides a rule a project states for itself.
The corollary matters just as much: riprap’s documents are read-only, and are replaced
whenever the plugin updates. A lesson worth keeping goes in the project’s own
.riprap/instructions/, never into riprap’s copy, where the next update erases it. That is
what /riprap:learn is for — it writes into your project, deliberately.
The seven behavioural rules
1. Clarify, then plan. Unless you are already 95% confident of exactly what is being asked or asked for, ask — before answering, before planning, before building. Ask sequentially: one question at a time, each shaped by the last answer, through the host’s structured choice UI wherever there is one. Never ask what could be read instead; research first, and spend questions on what research cannot settle.
Once over the bar, what happens next depends on what was handed over. A question gets an answer and stops there — answering is not a licence to start building on it. A task gets a summary of what made you confident and what you are going to do, and then waits for the user’s signal. A task already over the bar gets done: the bar is a floor on confidence, not a quota on questions, so at 95% there is nothing to ask and nothing should be manufactured. That last case is what stops the rule taxing a typo — asking there spends a round trip to learn nothing and teaches the user that these questions are noise, which is what makes the important one get skimmed later.
Only then plan: enter plan mode for anything non-trivial — three or more steps, or any architectural decision — and use it for verification steps too, not just for building. If work goes sideways, stop and re-plan rather than pushing through.
With nobody to answer — a scheduled run, a trigger, CI — proceed and record. A question that cannot be answered is not permission to guess freely, and not a reason to produce nothing. Take the narrowest reading that could be right, because a too-narrow change is a follow-up and a too-broad one is a revert; then record the fork in the artifact itself — a pull request body, a handoff — rather than in a transcript nobody will read. The critical rules do not relax: unattended is not a licence to merge, to add a technology, or to open a pull request on a diff nobody reviewed.
This is deliberately not what tech-footprint.md does, and the difference is the point. That rule refuses outright when there is nobody to ask, because it gates adding something whose cost is permanent — refusing ends where you started. Rule 1 gates understanding, where refusing produces nothing, burns the run, and leaves the same ambiguity waiting next time.
2. Use subagents. Offload research, exploration, and parallel analysis to keep the main context clean. One task per subagent.
3. Capture corrections. After any correction, write the lesson into the project’s
.riprap/instructions/ so it survives the session. A correction that only lives in the
conversation gets made again next week.
4. Verify before claiming done. Never mark work complete without evidence: tests run, output shown, behaviour checked. If tests fail, say so and show the failure. If you skipped a step, say which.
5. Prefer the simpler solution. When two designs both work, ship the one with less code in it, and add structure at the second occurrence rather than in anticipation of one. Skip this for obvious fixes — it is a check against hacks, not an invitation to over-engineer.
6. Fix bugs autonomously. Given a bug report, a failing test, or a red CI run: diagnose and fix it. Do not round-trip for permission to start.
7. Keep the handoff current. One document per unit of work in tmp/handoff/, rewritten
in place when a plan is approved, when a stage lands, when a task finishes, before a long
unattended stretch or an announced compaction, and whenever a session stops with work
unfinished. It carries the goal, the plan, what is done, what is next,
what done means, and how to resume. Written before it is needed: when the context actually
runs out there is no turn left in which to summarise, which is why the trigger is never “the
context is full”.
The five that cost the most when forgotten
Never weaken code to make a test pass. When a deliberate change breaks tests, the tests change — all of them, however many. If you are unsure whether a failure is a real bug or a stale assertion, ask. Guessing wrong commits a regression with an updated assertion certifying it as correct.
Always stress-test a plan before presenting it, and again whenever it changes materially. Dispatch critic subagents from distinct angles, plus a devil’s advocate whose brief is that the plan should not happen at all. There is no trivial-plan exemption: a plan’s own author is the worst possible judge of whether it needs review, and the plans that most need it are exactly the ones that feel finished. A revision inherits the approval of the original without inheriting its review, which is how an unreviewed approach ships under a reviewed plan’s banner.
Never merge a security-sensitive change autonomously. Hooks, permissions, CI configuration, auth, payments, and dependency manifests need a human on the merge, however green CI is. This one was added after a self-reviewed pull request touching a security hook came within one step of merging with a genuine regression in it.
Never add a technology the repository does not already use without asking. A script in a new language, a new runtime, a new build tool. The diff shows forty working lines; the cost lands on every future clone, every CI image, and every upgrade — and it is one-way in practice, because reversing it means rewriting code that works.
Never open a pull request on a diff nobody reviewed, and never abandon one you opened.
Before it opens: /riprap:review runs over the diff, every BLOCKER and MAJOR is fixed
first, and every finding is published in the body with a disposition — implemented, deferred
or ignored — and the reason behind it. A finding that was made and then dropped in
silence is indistinguishable from a finding nobody made, so the reviewer repeats the search
you already did. After it opens: a red CI run on your own pull request is the task rather
than a report, every review comment gets a change or an answer, and a conflict gets resolved
rather than announced. The loop ends when the pull request does.
What the permission lists can and cannot do
riprap ships a suggested permissions file and never applies it. Widening an allowlist is
a privilege grant, and riprap’s own merge-gate rule puts .claude/settings.json on the
human-required list. It does not exempt itself from that.
What matters more is what a deny-list can achieve at all. It is literal prefix matching. It stops mistakes — a command typed or generated without thinking — and it cannot stop a determined bypass, because a rule that matches a prefix is defeated by anything that does not start with that prefix. riprap’s own file says so out loud rather than implying otherwise.
The hooks are the real enforcement. They see the resolved command, they can refuse, and they fail closed when they cannot tell.
Conventions riprap documents but does not impose
riprap creates no directories and adds no ignore rules, because a project that already
ignores tmp/ does not need riprap’s opinion about it.
docs/is durable, checked-in documentation.tmp/is session scratch and should be git-ignored. Nothing intmp/is project documentation.- Plans go in
tmp/tasks/<topic>.mdas checkable items, with a review section added when the work lands. - Session handoffs go in
tmp/handoff/, never indocs/or the repository root. - Reference files by path relative to the repository root, never absolutely. A relative path that resolves differently than expected is the most common cause of an agent editing the wrong copy of a file.
The twelve skills
These chain: /riprap:spec defines a feature, /riprap:architect turns it into an
implementation plan, /riprap:implement builds that plan, and /riprap:review reviews what
comes out. Each also runs alone — the stage before it being absent changes where the input
comes from, never whether the skill works.
/riprap:install installs or refreshes the repository-side payload. It refuses a dirty
tree, preserves an incumbent hook manager, proposes rather than guesses stack commands, reports
overlapping guidance and hooks, and finishes by running bin/riprap verify.
/riprap:learn reviews the session and writes what was learned into the project’s
own instructions — the active host’s root instruction file or .riprap/instructions/. Never
into riprap’s own documents, which are replaced on update. This is the mechanism behind rule 3.
It also proposes narrow permissions.allow entries for any tool-and-argument pattern approved
twice or more in the session — the narrowest rule that covers actual usage, never a broad one
granted once to save a prompt, and never applied without asking first.
/riprap:spec is interactive feature definition in five phases: stakeholder interviews,
UI mockups, phased work items, and acceptance tests. It is planning only — it writes no
implementation, deliberately, because a specification that starts writing code stops being
reviewed.
/riprap:architect turns a settled requirement into an implementation plan, and writes no
source — it enters plan mode before reading the first file, which makes that constraint the
harness’s to enforce rather than the model’s to remember. The failure it is written against
is a plan that makes its reader re-explore: they open it, find “update the auth module”, and
spend the same forty minutes of greps the plan was meant to have spent once. So it carries what
that reader would otherwise rediscover — what already exists with line references, what is
missing, the files, ordered steps and how each is verified — and nothing they would type anyway.
It stress-tests itself before presenting, per the critical rule, and what survives goes into the
plan rather than only into the conversation.
/riprap:implement builds an approved plan and stops three times to be told it is wrong.
The tests come first and land as their own commit, because a tests-only diff is a specification
somebody can read; then /riprap:review runs over the tests, again over the implementation,
and again over the pull request, with the findings presented to you before anything is
incorporated. The three exist because each catches what the others structurally cannot — a wrong
specification while it is still four assertions, wrong code before anyone else has read it, and
what only comes into being with the pull request. It asks once how much isolation the work gets,
so two sessions cannot overwrite each other, and it never merges: the party that wrote the code,
ran the review and wrote the summary is the party merge-gates.md exists to keep away from the
merge button.
/riprap:advise is a planning council: intake, clarification, parallel research agents,
a draft, then parallel critic agents against that draft before anything reaches you. It is
rule 2 and the stress-test rule applied to planning itself.
/riprap:prune prunes merged and stale branches and triages quiet pull
requests. It reports the entire plan first and never deletes, merges, or closes anything
without per-action confirmation — the actions are cheap to approve and expensive to undo,
which is exactly the shape that warrants a prompt.
/riprap:release cuts a release and then proves it happened. It works out the base
branch, tag shape, version files and what publishes the artifact, confirms them with you
once, and stores the answers in your own instructions rather than asking you to configure
anything. It
refuses to proceed on a failing check, drafts notes from what actually merged rather than
from a commit log that squash-merging has made meaningless, and puts the tag on the commit
that merged. Its last step verifies the release exists, because the failure it is written
against is a model watching a pipeline go green and reporting a release complete that was
never published.
/riprap:review reviews a branch before a pull request exists, or a pull request
after one does, and closes with an explicit merge verdict against a named commit. It
reports: it never edits the branch, never merges, and never writes anything shaped like an
approval. The failure it is written against is a review that lists findings and stops —
leaving the reader to work out whether the thing ships, which is the one question they
asked and the only part that needed the reviewer’s context. It dispatches at least six
reviewers in parallel — correctness, simplicity, maintainability and dependency creep among
them, plus the devil’s advocate that can come back with don’t — and posts inline comments
on the lines they concern beside a summary giving every finding a class and a recommended fix.
It owns the review procedure, and the guardrail document points at it. The angles, the
dispositions and the tables are defined in the skill; code-review.md states the obligation
to review and stops there. The split is about performing rather than reading: a review has to
be run against a branch or somebody else’s pull request, and a document cannot be run — while
writing the procedure in both places would make it two definitions of one rule, drifting. The
severity classes stay in interaction-preferences.md, shared with the plan stress-test, so a
BLOCKER means one thing everywhere.
/riprap:vet drives that review and the fixes it asks for through a bounded
number of cycles, and stops at the merge gate. It exists because /riprap:review reports and
stops by design, so somebody still has to apply the fixes, push them, and ask again — and
done by hand that loop reliably loses one of three things: the fix is never pushed, so the
next pass reads code it cannot see and reports the finding again; or review and remediation
collapse into one turn, and the findings become indistinguishable from the changes made in
response to them; or nobody notices that the same finding has now been raised three times,
which is not a review converging but two parties disagreeing.
It ends by handing over, never by merging, and that is the whole shape of it. A loop
that ends in a merge is the arrangement merge-gates.md was written against — the same party
writing, judging and merging — with more rounds in front of it, and more rounds do not fix a
blind spot that is structural.
/riprap:handoff writes the document that lets a piece of work survive a lost context,
and resumes from one. Goal, plan, what is done, what is next, what done means, how to resume
— one document per unit of work, rewritten in place rather than appended to, because a
handoff nobody updated is worse than none: it is confidently wrong about where the work
stopped. It is rule 7 made performable, and hooks stand behind it as they do behind no other
skill, because the moment a context actually runs out is the one moment when there is no turn
left in which to write anything down.
/riprap:write reviews or rewrites a document, plan, pull request body or README against
riprap’s writing standard, and carries the full Google developer documentation style guide as
reference — the word list, punctuation, tables, code and UI formatting. The standard ships in
two tiers for a reason: writing-style.md binds every message and is short enough to be read
every session, while the reference behind it is read only when this skill runs. It edits prose
and never changes behaviour, because a document quietly edited into agreement with broken code
has destroyed the only remaining evidence that they disagreed.
- Guardrail architecture — what is enforced, and how a rule is made to hold
- Reference — every document and skill, catalogued
- Installing riprap