by lcvbeek
A powerful layer of patina for your agents' harnesses
# Add to your Claude Code skills
git clone https://github.com/lcvbeek/patinaKeep Claude's harness buffed.
Patina is the retro loop for Claude Code that layers every session,
near-miss, and team agreement into PATINA.md — an AI constitution loaded
into every session, owned by the whole team, polished one cycle at a time.
Each retro deposits one deliberate layer. Works solo; shines on a team.
patina capture Record a notable moment while it's fresh.
UUID-named JSON — no merge conflicts.
patina reflect Answer the questions your team picked. Async.
Every voice lands in the shared data dir.
patina run Claude ingests logs, captures, and reflections
and applies the next layer to PATINA.md.
Review with git diff PATINA.md, commit. Next session, everyone works from
the updated instructions.
patina reflect on
their own machine before the retro; every voice lands in the synthesis.patina run writes it to PATINA.md; a human reads it, approves it,
commits it.No comments yet. Be the first to share your thoughts!
ANTHROPIC_API_KEY in your environment.
Patina falls back to this if the CLI isn't found. Billed separately per token.npm install -g @lcvbeek/patina
First, create an empty git repo. This will just hold the data. JSON files – no code, no builds. GitHub, GitLab, wherever.
One person bootstraps:
cd your-project
patina init --data-repo git@github.com:your-org/patina-data.git
patina run # onboarding questions; first layer auto-applied
git diff PATINA.md # review your first PATINA.md
git commit -am "First patina layer"
--data-repo clones the shared data repo as a sibling directory
(../<repo-name>/), writes a portable relative dataDir to
.patina/config.json, and enables automatic git pull/push.
UUID-named files mean concurrent writes never collide.
Each teammate runs the same command once after pulling the project:
patina init --data-repo git@github.com:your-org/patina-data.git
From then on, dataDir syncs automatically on every patina command.
Without --data-repo, data stays local — fine for solo, but teammates'
captures and reflections won't be included.
| Command | What it does |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| init | Scaffold .patina/ in the current directory, create PATINA.md. Use --data-repo <url> to clone a shared data repo; --skill to install the /patina Claude Code skill |
| capture | Capture a notable moment while it's fresh. Use --synth for an immediate Claude interpretation without waiting for the next retro |
| reflect | Answer reflection questions before the retro — saved locally, loaded by patina run. Press Enter to skip any question |
| run | Run the retro — auto-ingests logs, loads all captures + reflections from the team, calls Claude for synthesis, applies the proposed change to PATINA.md |
| status | Show metrics: token spend, rework rate, tool usage, trends across cycles. Shows a breakdown by project so you can verify which repos are being included |
| layers | Visualise the patina the team has built — one ASCII layer per retro cycle. Shows 5 most recent by default; use -n 10 for more or -n 0 for all |
| ask | Low-level command used by the /patina Claude Code skill — not intended for direct use |
| ingest | Manually parse Claude Code logs (optional — patina run does this automatically) |
| buff / apply | Deprecated. patina run now applies changes automatically. Kept for backwards compatibility. |
patina init
patina init --skill # also install the /patina Claude Code skill
patina init --data-repo git@github.com:org/retro.git # clone and wire up a shared data repo
Creates .patina/ with PATINA.md, config.json, context/, and cycles/,
and adds @.patina/PATINA.md to CLAUDE.md (creating it if needed).
--skill installs the /patina Claude Code skill to ~/.claude/skills/patina/
so any team member can answer reflection questions from inside a Claude Code session.--data-repo <url> clones the given git repo as a sibling directory
(../<repo-name>/), writes a portable relative dataDir to .patina/config.json,
and enables automatic git pull/push sync on each patina command — the
easiest way to share captures, reflections, and sessions across a team.Safe to run once per project.
patina capture # interactive mode
patina capture "agent almost pushed directly to main — need an approval gate rule"
patina capture --tag near-miss "agent almost pushed directly to main"
patina capture --synth "Claude tried to commit an API key" # immediate synthesis
Tags: near-miss (n) / went-well (w) / frustration (f) / pattern (p) / other (o)
Captures are UUID-named JSON files in dataDir — no merge conflicts,
anyone can write anytime. Author comes from git config user.name.
--synth calls Claude immediately, pattern-matches against recent
captures and PATINA.md, prints an insight, and queues a proposed
instruction change for the next patina run to apply.
patina reflect
Walks through the reflection questions and saves answers to dataDir.
Press Enter to skip. Each teammate runs this before the retro; patina run
aggregates every answer since the last cycle.
Customise questions by committing .patina/questions.json.
patina init --skill installs a Claude Code skill at
~/.claude/skills/patina/ so teammates can reflect and capture without
leaving a Claude Code session:
/patina next # next unanswered question
/patina reflect felt good overall # record an answer
/patina capture near-miss: almost... # capture a moment
/patina status # cycle metrics
The skill auto-advances to the next question after each answer, so a
teammate can clear reflections in one conversation. patina ask backs the
skill and isn't meant for direct use.
patina run
patina run --onboard # force onboarding questions
Auto-ingests Claude Code logs, loads all captures and reflections since
the last cycle, synthesises, writes the report to .patina/cycles/<date>.md,
and applies the proposed change to the correct file (core or spoke, by
section number). Review with git diff before committing. First run asks
onboarding questions to establish baseline agreements.
patina run now applies changes automatically. buff and apply remain
as aliases for the pending-diff flow but aren't part of the loop anymore.
Token spend, rework rate, tool usage, and trends across cycles, with a per-project breakdown so you can verify which repos are contributing.
patina layers # 5 most recent cycles
patina layers -n 10 # last 10
patina layers -n 0 # all
One ASCII layer per retro — a quick visual of how the patina has built up. Useful to share at the start of a retro.
Manually parses Claude Code JSONL logs. patina run does this
automatically; use ingest to pre-populate metrics or debug. Only the
current project's sessions are ingested by default (slug derived from
cwd, matched against ~/.claude/projects/).
Operational data (sessions, captures, reflections, metrics, pending diffs) lives outside the project repo. Default location, per machine:
~/.patina/projects/<slug>/
sessions/
captures/
reflections/
metrics.json
pending-diff.json
For team retros, set dataDir in .patina/config.json — or use
patina init --data-repo <url> to have it set up for you.
dataDir supports three formats:
{ "dataDir": "../patina-data" } // relative to project root (recommended)
{ "dataDir": "../../shared/retro" } // deeper relative path — resolved from project root
{ "dataDir": "~/my-patina-data" } // home-directory expansion
Absolute paths work too. patina init --data-repo a