Shale — every agent PR explains itself
The problem: your team ships AI-agent code every day, but reviewers still get what they always got — a diff. The prompt that produced it, the files the agent actually touched, the tests it ran before pushing: all of that lives on the author’s laptop and dies there. So reviewers re-derive context the agent already had, approve on faith, or slow everything down asking “what was this supposed to do?”
What Shale does: it records the agent session — intent, files touched, commands run, model and cost — and renders it as a card on the pull request. The evidence travels with the code. The reviewer reads the card, then the diff.
Every output line above is real — captured verbatim from a live session.
What lands on the PR
A card like this one, on a live demo PR:
Shale · 1 session · claude-code (claude-fable-5) claude-fable-5 · 60k tokens · ~$0.67 · 2 iterations · < 1 min
Intent — Add rate limiting to the login endpoint. Token bucket per client IP, 10 requests/min, in-memory. Return 429 with Retry-After.
Changed files (3) — all with session evidence
File Session Notes internal/ratelimit/ratelimit.go✅ 25f37dfc new file internal/ratelimit/ratelimit_test.go✅ 25f37dfc new file main.go✅ 25f37dfc Checks recorded locally —
go test ./...✅ passedAdvisory — CI is authoritative.
And just as importantly, what the card shows when things are less tidy:
- a file changed with no session evidence → flagged, not hidden
- a sensitive path touched (dependency manifest, CI config, auth code) → bolded, kept above the fold
- evidence edited after capture → a tamper warning, and the affected text treated as unverified
- a PR with no evidence at all → an explicit “No shale for this PR” note instead of silence
The card’s honesty about gaps is the feature. Reviewers learn to trust it precisely because it never pretends to know more than it does.
Five minutes, one person, whole team
cd your-repo
shale init
git add . && git commit -m "chore: enable shale" && git push

shale init writes everything into the repo — agent steering, capture
hooks, evidence store, and the GitHub Action. Your teammates get wired
automatically on git clone. Nobody signs up for anything; there is no
server, no account, no GitHub App, no token to paste.
The one question it asks (real terminals only, default no): whether to
auto-approve the three shale evidence commands for Claude Code. Saying yes
writes a permissions allowlist — scoped to exactly shale intent,
shale done, and shale note, never a wildcard — into the committed
.claude/settings.json, so the whole team’s agents stop hitting permission
prompts for evidence. It’s visible in the bootstrap PR diff and
shale uninstall --repo removes it.
Teammates who haven’t installed the CLI see nothing at all: the committed
hooks are self-guarding and stay silent until shale appears on their PATH.
Repos with branch protection: run shale init on a branch, open a
normal PR, merge it. The bootstrap PR won’t have a Shale card — that’s
expected, because the workflow doesn’t exist on main yet. Every PR
after that merge gets a card. Full guide →
Already using husky/lefthook or another PR bot? Fine on both counts.
init never clobbers existing hooks (it honors core.hooksPath and names
the exact hook file if you want to chain shale finalize --auto-commit
into it) — and since evidence now publishes at shale done, agent sessions
don’t depend on that hook at all; chaining only matters as the safety net
for sessions without a done. The card never touches comments posted by
other tools.
How it works, honestly
- The agent declares intent. A steering block (in
CLAUDE.md,AGENTS.md,.cursorrules, …) tells your agent to runshale intent "<goal>"before its first edit andshale donewhen finished. Works with any agent that can run a shell command. - Hooks capture the session. For agents with hook support, every file touch, command, and prompt streams into a local, redacted session log. Claude Code and Codex are tested against real sessions today; Cursor and Copilot adapters are implemented but not yet validated against real payloads — real payload samples welcome. No hooks? Shale falls back to git to derive the file list — and labels it as such on the card.
shale donepublishes. The done call folds the session into.shale/<session>.yamland commits it on the spot — the evidence commit exists before you push, so it always travels with the code. A pre-push hook remains as the safety net, finalizing any session that never got adone(interrupted agents, sessions an agent abandoned). Fail-open both ways: a Shale problem can never block your push.- CI renders the card. The GitHub Action reads the evidence and the diff through the API — it never checks out PR code — verifies the transcript hashes, and posts the card as a comment plus a neutral check.
The questions your security team will ask
What exactly gets recorded? Committed evidence (.shale/<session>.yaml)
holds the agent’s intent, the paths of files it touched and the operation
(write / edit / delete), the commands it ran and their exit codes, and the
model, tokens, cost, and timing. Nothing more.
What does it deliberately not capture?
- File contents or diffs — Shale records that
auth.gochanged, never what changed. The diff is already in the PR. - Gitignored files — any touch whose path your repo ignores (
.env,*.pem,secrets/, anything in.gitignore) is dropped at finalize. Secrets live in exactly those paths, so they never reach committed evidence. - Files outside the repo — a path resolving outside the repo root is dropped.
- Raw prompt text — see below.
What about secrets in commands? Agent-authored text — intent, notes, and
the commands themselves — is run through a secret-redaction pass before it is
written. It catches vendor token shapes (AWS, GitHub, OpenAI, Anthropic, Slack,
Stripe, and more) plus the command-line forms agents actually use: env-prefix
assignments (API_KEY=… ./run), secret flags (--token=…, --password …),
and bearer headers. The command stays on the card — knowing the agent ran
go test is the point — only the secret value is masked.
Does prompt text leave the laptop? No — period, in current builds.
Shale can capture the raw prompts developers type and redact them (secrets,
credentials, tokens) before committing a prompts-only transcript, but we
have turned that off in the product — a build-time flag, deliberately
not configurable — until we are confident the redaction layer handles
free-form human text and the regulatory questions around capturing raw
prompts are settled. Prompts stay in gitignored .shale/local/ on the
laptop; committed evidence carries only a prompt count and an intent
integrity hash. Agent-authored text (intent, notes, commands) is redacted
before persistence (full / redacted / hash-only modes).
What permissions does it grant agents? None by default. With your
explicit consent at init (an interactive [y/N], or a flag in scripts),
it allowlists exactly three commands for Claude Code — shale intent,
shale done, shale note — in the committed .claude/settings.json.
Never shale *: uninstalling, re-initializing, and anything shipped later
still prompt. The grant is reviewable in the PR that adds it and
shale uninstall --repo removes precisely those entries.
Can the author fake the evidence? Editing evidence after capture is
detected and flagged on the card (hash verification at render time).
Wholesale fabrication by a determined insider is explicitly out of scope for
v1 — and the card never claims otherwise. Honest labels (hook-verified vs
git-derived) are load-bearing.
Can it block our merges? No. The check is never failure, the pre-push
hook always lets the push through, and capture exits 0 on every error. Shale
is evidence, not enforcement.
What does it phone home? Nothing. No telemetry, no accounts, no network calls from the laptop — enforced by test.
What if we try it and walk away? shale uninstall removes everything on
your machine; shale uninstall --repo also removes the committed files
(commit the removal). It only deletes what Shale wrote — your instruction
files, your hook entries, and your hook manager’s files survive. And because
the committed hooks are self-guarding, brew uninstall shale alone makes
everything go silent for you. No account to close, nothing left running.
Start here
- Getting started — the full walkthrough, including branch protection setup
- CI integrations — Jenkins, CircleCI, GitHub Enterprise Server, and the env contract
- Live demo PRs — happy path, coverage gaps, and the no-evidence nudge, on real PRs
- Troubleshooting — when something looks off
- Product & architecture — design decisions, capture tiers, security model