- Shell 80%
- JavaScript 20%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
gitleaks reported 2 leaks on this repo and nothing was looking, because `gitleaks detect` was never in CLAUDE.md `## Run` — even though rules/quality-gate.md names it as the any-stack half of the security check. A mandated check that no one runs is the "skip that reads as passed" the same rule file warns about. Both findings are false positives, reviewed rather than waved through: the SonarQube web API takes its token as the HTTP basic-auth *username* with an empty password, so /sonar documents `curl -sf -u "$TOKEN:"`. gitleaks' curl-auth-user rule matches the flag shape; the value is a shell variable read from the environment. Verified verbatim at 1ef45e21:commands/sonar.md:61,66 — both are historical, since gitleaks scans commit diffs and the skills/ rename never re-added those lines. Suppressed by fingerprint in .gitleaksignore, not by a regex allowlist, so the two occurrences are frozen and nothing new can hide behind them: re-adding the pattern in a future commit yields a NEW fingerprint and gets flagged, which is the behaviour we want. Proved it still bites — cloned the repo with the ignore file in place, planted an AWS key and a GitHub token, and gitleaks exited 1. CLAUDE.md `## Run` now lists five gate checks, not four. 90 lines, up 2 and still over the under-80 rule; a working security check is worth more than the line count, and the overage stays flagged rather than fudged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Planned-By: Claude Opus 5 <noreply@anthropic.com> |
||
| agents | ||
| docs | ||
| plugins | ||
| rules | ||
| scripts | ||
| skills | ||
| templates | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| .gitleaksignore | ||
| bootstrap-opencode.sh | ||
| bootstrap.sh | ||
| CLAUDE.md | ||
| LICENSE | ||
| NOTES.md | ||
| README.md | ||
| sync.sh | ||
lean-code
A minimalist Claude Code config that does three things: install, configure, get out of the way.
Heads up — this is not a copy-paste magic script. It's calibrated to my setup, my projects, my mood. There's a Qdrant on my homelab, a llama-cpp endpoint, Sonar, opinions about coffee, and a handful of rules that exist because of incidents (...slops!) you weren't around for. Plan to read every file and swap out whatever doesn't match your reality before you trust any of it. You'll inherit my bugs otherwise!
Why this exists
The big agent-config frameworks — pick whichever one your feed is pushing this month — ship skills, agents, hooks, MCP servers, a project memory system, slash commands for every imaginable workflow, and an opinion about which way the toilet paper goes. It's a lot. Most of it is good, but it's a BEAST. I wanted to understand what's actually happening when Claude reads my repo and decides what to do next, so... so I did the only thing I could do, I asked Claude to tell me about itself.
This is the rebuild from first principles and some other blogs and materials. Strip everything to the bone, then add back only the pieces I can explain to the sharpest knife in the drawer after they've had three beers. If I can't justify a file, the file dies. The result is small enough to read end-to-end in one sitting, opinionated enough to actually matter, and dumb enough that I can debug it with cat and grep while petting the dog.
If you want a fully-featured agentic workshop, install one of the big frameworks — you already know which one. If you want to understand how the moving parts fit together and you like tears and suffer, you can build your own. (You will thank yourself later!)
The three-layer model
The whole thing is three layers.
System layer — bash tools, Claude Code itself, the MCPs I actually use. Installed once per machine by bootstrap.sh. After this runs I have a working AI coding setup. This layer doesn't know anything about my projects.
Global config layer — the rules, skills, and subagents that live in ~/.claude/. Loaded by Claude Code every time it starts, in every project. This is where opinions live: "use uv, not pip", "read before you edit", "tests have tiers, pick one." Three artifact types: a rule is an always-on belief; a skill is a procedure, and one frontmatter line decides who may start it — disable-model-invocation: true makes it a tool I pick up (/plan, /spec, /handoff, /sonar, /scaffold), and without it the agent reaches for it on its own (diagnose, when a bug resists the first fix); an agent is a delegable context (codebase-explorer, plan-reviewer, ui-verifier). Also installed by bootstrap.sh.
Commands used to be a fourth type here. Claude Code merged them into skills —
.claude/commands/x.mdand.claude/skills/x/SKILL.mdboth create/x— so this repo did too, and one flag now carries the distinction that used to need its own directory. OpenCode hasn't merged them, which is whysync.shstill derives command files for it. See docs/adr/0001-commands-are-skills.md.
Project layer — per-project state. Three files: CLAUDE.md (durable status the agent reads at session start), NOTES.md (in-session scratch that gets drained by /handoff at session end), and CONTEXT.md (the domain glossary — one word per concept, so naming stays consistent and the agent burns fewer tokens decoding jargon). Plus docs/plans/ — every approved plan, numbered (0001-…/, 0002-…/) and committed to git, so the plan log versions with the code. /plan generates the skeleton for a lib/app (and scaffolds it on accept); /scaffold does it directly for a throwaway script — either way sized to the project's tier: a one-off script gets git + a linter, a full app gets the works.
System assumes nothing (EXCEPT! BTW... I use Arch. And the scripts too!). Global assumes system. Project assumes global. Layers don't reach across.
What's in the box
lean-code/
├── bootstrap.sh # one-shot install: tools + Claude Code + global config
├── bootstrap-opencode.sh # agent-layer add-on: OpenCode CLI + ~/.config/opencode config
├── sync.sh # the release button: deploy config edits to this machine (--check reports drift)
│
├── rules/ # auto-loaded by Claude Code from ~/.claude/rules/
│ ├── core.md # discipline (verify/read/search/ask) + YAGNI, standards, security
│ ├── toolchain.md # mise/uv/podman/pnpm — the modern stack lock-in
│ ├── research.md # Context7 for docs, SocratiCode for code — never stale memory
│ ├── testing.md # tiered testing (script / library / app), anti-patterns
│ ├── workflow.md # session-start ritual, conventional commits, handoff cues
│ ├── quality-gate.md # native floor (types/lint/security/tests) the agent keeps green
│ └── scoped/ # path-scoped rules (paths: frontmatter) — Claude Code only;
│ └── expo.md # Expo gotchas (version-free by doctrine). OpenCode's glob never descends here
│
├── skills/ # one type, two invocation models (see the flag on each)
│ │ # -- user-invoked: disable-model-invocation: true --
│ ├── scaffold/ # /scaffold — new project sized to its tier (script/lib/app); infers, or consumes a /plan decision
│ ├── plan/ # /plan — grill, draft, WAIT; persist numbered to docs/plans/, scaffold on accept
│ ├── spec/ # /spec — deepen ONE plan phase into a cold-executor spec (Context7-pinned) a weak/local model can run; additive, never touches /plan
│ ├── sonar/ # /sonar — deep SonarQube scan + dashboard, you decide (opt-in)
│ ├── handoff/ # /handoff — security checkpoint, drain NOTES, update CLAUDE.md, commit
│ │ # -- model-invoked: the agent reaches for these on its own --
│ ├── diagnose/SKILL.md # disciplined debugging loop for hard bugs (auto-fires when stuck)
│ ├── mobile-screenshot-harness/ # Android dev-client + headless screenshots — the agent SEES mobile UI
│ ├── stop-slop/ # vendored — strip AI tells from prose (fires when writing/editing)
│ ├── security-checkpoint/ # vendored Anthropic security review — /handoff Phase 2's engine
│ ├── codebase-exploration/ # vendored SocratiCode — search/graph/read a codebase
│ └── codebase-management/ # vendored SocratiCode — index, watch, context artifacts
│
├── agents/ # subagents the model can delegate to
│ ├── codebase-explorer.md # vendored SocratiCode — deep multi-file exploration
│ ├── plan-reviewer.md # independent gap + contradiction review of a drafted plan
│ └── ui-verifier.md # Playwright browser testing in its own context window
│
├── plugins/ # OpenCode plugins — JS hooks where prompts aren't enough
│ └── enforce-research.js # tripwire: new third-party import without a Context7 lookup
│
├── templates/ # deployed verbatim into ~/.claude
│ ├── CLAUDE.md # global non-negotiables salience block (the 8 rules)
│ └── statusline.sh # context/cost/git/rate-limit statusline
│
└── scripts/
├── setup-socraticode.sh # wire a project into the Socraticode MCP (per-project .mcp.json)
├── reset-socraticode.sh # drop Qdrant collections for a clean SocratiCode re-index
└── opencode-yolo.sh # opt-in `opencode --auto` launcher (DANGER — VM/container only)
Install
Two scripts, run in order. Step 1 is required for everyone. Step 2 is optional — add it only if you want OpenCode too.
Configure your endpoints first (.env)
The scripts bake in no host defaults — they stay portable by reading every service URL from the environment, so set these up before you run either script. Copy the example, point it at wherever your services actually live, and source it into the shell you'll run the scripts from:
cp .env.example .env
$EDITOR .env
set -a; . ./.env; set +a # export everything into this shell
| Var | Used by | Notes |
|---|---|---|
QDRANT_URL, OLLAMA_URL |
SocratiCode indexing | required, no default |
EMBEDDING_MODEL |
SocratiCode | optional (defaults to nomic-embed-text) |
LLAMACPP_URL, LLAMACPP_MODEL |
OpenCode local model | URL required; model optional |
SONARQUBE_URL, SONARQUBE_TOKEN |
SonarQube MCP server | USER token |
SONAR_HOST_URL, SONAR_TOKEN |
/sonar scanner |
Global Analysis token |
CONTEXT7_API_KEY |
Context7 docs MCP | optional (raises rate limits; runs keyless) — the one hosted service here, see Design rules |
.env is gitignored — secrets never get committed. Anything you'd rather keep
permanent goes in your shell rc instead. Tip: prefer 127.0.0.1 over localhost
— rootless podman can resolve localhost to IPv6 and miss an IPv4-only service.
Step 1 — bootstrap.sh
On a fresh, minimal Arch box (no GUI needed):
git clone <this-repo> ~/lean-code
cd ~/lean-code
./bootstrap.sh
This installs the system layer (git, mise, uv, podman, pnpm, Claude Code, the MCPs) and the global config layer — it drops rules/, skills/, agents/, and the templates into ~/.claude/, and copies setup-socraticode + reset-socraticode into ~/.local/bin (add that to your PATH). Run it once per machine.
Think of this script as the single source of truth. Everything downstream — including OpenCode — reuses what it produces, above all the rule files in ~/.claude/rules/.
Step 2 — bootstrap-opencode.sh (optional, adds OpenCode)
Want OpenCode, the open-source agent — alongside Claude Code, or instead of it? Run:
./bootstrap-opencode.sh
⚠️ Run Step 1 first — even if you never plan to use Claude Code.
bootstrap-opencode.shships no rules of its own. It just points OpenCode at the same~/.claude/rules/files Step 1 created. That's the entire point: one set of rules, two agents, maintained in one place — never the same rule copied into two configs. Skip Step 1 and this script preflight-checks, finds no rules, and stops.
The two scripts complement each other: Step 1 owns the system and the rules; Step 2 is a thin adapter that teaches OpenCode to read them (plus an OpenCode-shaped MCP + provider config). After both, claude and opencode behave the same way in every project — same rules, same conventions, same blind spots ignored.
What Step 2 wires up
- No symlink, no
AGENTS.md. OpenCode reads~/.claude/CLAUDE.mdas a native global fallback when noAGENTS.mdexists, so both agents share the same inline ruleset for free. ~/.config/opencode/opencode.jsonwith"instructions": ["…/.claude/rules/*.md"]— a single glob OpenCode loads additively on top of the CLAUDE.md fallback. Path-scoped rules (paths:frontmatter, which OpenCode can't honor) live inrules/scoped/— a glob's*never crosses/, so they're excluded by construction, not by script logic. The config is merged, never overwritten on re-runs: sync owns the machinery keys (instructions,tools, MCP wiring, canonical permission entries), you keepprovider,model,mcp.*.enabledtoggles, and anything custom.- MCP:
context7(docs) +playwright(browser) +sonarqube(code quality, readsSONARQUBE_URL/SONARQUBE_TOKEN), the same trio Claude Code gets. Context7 usesCONTEXT7_API_KEYif set, runs keyless otherwise. - Provider preset: a
llama-cppentry (@ai-sdk/openai-compatible) pointing at a LAN host, set as the default model. Editprovider.llama-cpp.options.baseURL+ the model id in~/.config/opencode/opencode.json, override at install time withLLAMACPP_URL=… LLAMACPP_MODEL=… ./bootstrap-opencode.sh, or swap the block for Anthropic / OpenRouter and runopencode auth login. - Permissions are three-class in both agents: routine dev commands
allowed (git *reads + commits,mise,uv, …), consequential onesask(git push,git rebase,git reset,curl,podman, …), catastrophic onesdenyed (git push --force,rm -rf ~,dd of=/dev/…). Deny rules survive evenopencode-yolo—--autohonors denies. Claude Code reads them from~/.claude/settings.json(evaluated deny → ask → allow, first match wins); OpenCode from thepermission.bashmap (ordered catch-all → specific → denies last; last match wins). Both are written bysync.sh— canonical rule lists win, your additions are preserved, and you can't weaken adeny. OpenCode gets a second map,permission.skill, on the same last-match-wins rules: it denies the five user-invoked skills, because OpenCode ignoresdisable-model-invocationand would otherwise let its model fire/handoffor/sonaron its own. opencode-yolo(~/.local/bin) — an opt-in launcher wrapping OpenCode's documented--autoflag: every prompt not explicitlydenyed is auto-approved, sodenyrules still apply (unlike the undocumented env-var hack it replaced). It's a separate command, not an alias — plainopencodekeeps the scoped allow-list, and the dangerous choice stays salient at typing time. ⚠️ Edits + bash run unconfirmed — use only in a throwaway VM / container / git worktree.- Commands, skills, and the codebase agent. Commands are derived, not copied:
sync.shreads eachskills/<name>/SKILL.mdand writes~/.config/opencode/commands/<name>.mdwith OpenCode's frontmatter and the same body — one source, two agents, the same trick used for agents below. Claude-side keys (model,disable-model-invocation,name) are stripped on the way. Skills need no copy — OpenCode discoversSKILL.mdfrom~/.claude/skills(a Claude-compatible search path), sodiagnose+ the SocratiCode skills are visible to itsskilltool automatically; the five user-invoked ones are denied there viapermission.skill. Thecodebase-exploreragent is derived into~/.config/opencode/agents/in OpenCode's frontmatter format (mode: subagent+ a least-privilegepermission:block — read/grep/glob/list/skill allowed, edit/bash/webfetch denied) from the same agent body Claude Code uses. - SocratiCode + Understand-Anything work with both agents — see Codebase analysis below.
Releasing config edits — sync.sh
bootstrap.sh builds the factory; sync.sh ships the release. Both bootstraps call it, so first install and day-to-day deploys can never diverge. After editing anything in rules/, skills/, agents/, templates/, or plugins/:
./sync.sh # deploy to this machine (~/.claude + ~/.config/opencode)
./sync.sh --check # report drift (stale/missing/orphan), change nothing, exit 1 on any
Nothing is removed silently: a deployed file with no repo counterpart is reported as an orphan and deleted only after a y/N. Each deploy stamps ~/.claude/.lean-code-version with the repo sha, so "which release is live here?" is a cat away.
Use it
Which model runs which command. rules/workflow.md's Model Roles section settles
it: /plan and /spec are planner-only — architecture and ADR-worthy calls need Opus's
reasoning depth. /scaffold, /sonar, and /handoff are executor-safe — bounded,
mechanical work Sonnet handles fine. Start a planning session on Opus; run the rest
wherever you already are.
Each skill now also carries a model: line saying the same thing — but read it as a
hint, not a guardrail. Claude Code applies the override for the invoking turn and
then the session model resumes, so a multi-turn /plan only gets Opus for the turn that
does the grilling and drafting. It doesn't cross to OpenCode at all (that wants a full
provider/model id, which would be exactly the kind of stale pin this repo refuses), so
derive_command strips it. rules/workflow.md remains the authority; the frontmatter
just saves you a /model on the turn that matters most.
Starting a new project — the order follows the tier:
For anything you'd plan (a lib or an app), lead with /plan — tier and stack are
design decisions, so they belong to planning, not to a guess from a one-liner:
mkdir my-thing && cd my-thing
claude
> /plan a python lib for rate limiting
/plan grills you (tier and stack first, then the design), and when you accept it
self-bootstraps the repo and scaffolds the skeleton — git init, the numbered plan
under docs/plans/, CLAUDE.md/CONTEXT.md, deps resolved live, a green quality gate,
one initial commit — then stops before Phase 1. One command, end to end. Building the
first tracer-bullet slice stays behind an explicit "start Phase 1" (that's the planning
gate doing its job).
For a throwaway script where planning is overkill, skip straight to scaffold:
> /scaffold a python script that renders my docs to HTML
/scaffold infers the tier and stack from what you ask for and builds only what that
tier needs. Versions are resolved live (uv add / pnpm add pin the current release to
the lockfile; config shapes come from Context7), so the skeleton never ships stale pins.
Either order works — run /scaffold first and it infers; run /plan first and scaffold
consumes its decision instead of re-guessing.
Day-to-day:
/plan <what you want> — the agent reads the rules, grills(thx Matt) you one question at a time (proposing its own answer each time, exploring the code instead of asking when it can), drafts a plan, and waits for you to say go. On accept, the plan is saved numbered under docs/plans/NNNN-slug/ (overview + one file per phase) and committed — so it lives in git, and a second plan never clobbers the first. Domain terms settled during the grilling land in CONTEXT.md as they're resolved. Good for anything bigger than "fix this typo."
/spec <phase> — optional, and additive: it never touches /plan. Run it right before you build a phase to expand that one phase into a cold-executor spec — a docs/plans/NNNN-slug/phase-M.spec.md self-contained enough that a model with zero conversation context (a local 27B, or a fresh session, or you-in-a-crisis) can execute it: exact file paths and signatures, every external call Context7-pinned from the lockfile, each task sized to one context window, no decisions left open. It synthesizes the already-approved plan — it does not re-interview (borrowed from Matt Pocock's to-spec). Before you see it, plan-reviewer attacks it through a third "cold-executor readiness" lens — the smart model's spec gets stress-tested before the dumb one runs it. The spec is committed so it reaches a fresh clone, then deleted when the phase lands (the code is now the truth). Skip /spec entirely for phases you'll build yourself with full context; its whole point is the handoff to an executor that lacks it. Move the intelligence to plan-time, and a weaker model can do the typing.
/handoff at the end of a session — runs a security checkpoint over the session's whole diff (skippable when it's docs-only, adversarial when it touched auth/input/SQL/secrets; findings land in NOTES.md, criticals get fixed on the spot — the engine is skills/security-checkpoint, Anthropic's open-source security-review prompt adapted to session diffs, so it works identically in OpenCode), drains NOTES.md (every entry gets classified: promote to a task, promote to a comment, promote to a decision doc, or delete), updates CLAUDE.md's Status block, and commits the bookkeeping as a clean chore commit. Future-you opens the next session and the state is right there.
In between, you (I mean, the AI...) just code. The rules quietly steer the agent away from the usual failure modes. If something surprising comes up mid-task — a TODO surfaced by the code, a workaround you applied, an open question — append a timestamped entry to NOTES.md and keep going. /handoff will deal with it.
That's the whole model. Read the files, follow the conventions, commit the diffs.
Codebase analysis: one for me, one for the "dude" who does the heavy lifting
Two tools live in the box doing similar-sounding work but pointed at different audiences.
SocratiCode MCP is the agent's eyes. The agent queries it on demand during a session — semantic search, blast-radius impact, symbol-level call graphs. It reaches for it the way a human reaches for grep, except it understands meaning. It is not installed as a global Claude Code plugin — the plugin's bundled MCP server is static (Docker-managed Qdrant/Ollama, auto-generated project ID), and my Qdrant/Ollama addresses differ per project and machine. Instead: scripts/setup-socraticode.sh writes a per-project .mcp.json that runs npx -y socraticode against my own Qdrant and Ollama with no pinned project ID — so each source root gets its own per-path collection and the agent indexes polyglot repos one source root at a time (reset-socraticode wipes the collections for a clean re-index). The plugin's workflow skills (codebase-exploration, codebase-management) + the codebase-explorer agent are vendored into this repo (skills/, agents/) and deployed with the rest of the rules pack. Used silently in every project. Cheap to have around because nothing fires unless the agent asks.
Understand-Anything is the human's eyes. Optional, prompt-gated in both bootstraps: bootstrap.sh installs it as a Claude Code plugin, bootstrap-opencode.sh installs it via the upstream installer's first-class opencode backend (install.sh opencode — clones to ~/.understand-anything/repo, symlinks the skills into ~/.agents/skills). Either way its restraint rule rides along: the Understand-Anything restraint lines live in rules/research.md, one of the files OpenCode's instructions glob pulls in. It builds a knowledge graph and ships a Vite dashboard that visualises layers, dependencies, and a guided tour — perfect for onboarding a teammate, prepping a code review, or amusing the moneybag who needs to see something fancy before signing the next invoice. The agent will not invoke it on its own — rules/research.md makes that explicit.
Roughly: SocratiCode answers questions for the agent; Understand-Anything answers questions for the rest of us.
Both work with either agent, with full parity. SocratiCode ships only as a project-scoped MCP server (no global plugin) — setup-socraticode autodetects which agents you have installed and writes the right config for each (.mcp.json for Claude Code, the mcp block in opencode.json for OpenCode). The skills are shared verbatim: both read the same SKILL.md files from ~/.claude/skills (OpenCode lists it as a Claude-compatible search path), so bootstrap.sh deploys them once and OpenCode picks them up for free. The agent is the one artifact whose format genuinely differs — Claude reads ~/.claude/agents/codebase-explorer.md (vendored as-is), while OpenCode reads ~/.config/opencode/agents/ with its own mode: subagent + permission: frontmatter, so bootstrap-opencode.sh derives that copy from the same agent body (one source, two frontmatters — the same trick setup-socraticode uses for the MCP block). Understand-Anything is a first-class OpenCode backend of its own installer, so bootstrap-opencode.sh offers it as a prompt-gated step (install.sh opencode), the same way bootstrap.sh prompts for the Claude Code plugin.
Run claude or opencode from any project — both read the same rules, follow the same conventions, ignore the same noise.
Code quality: the floor and the deep scan
Two layers, both opinionated.
The native floor runs every loop, for free: rules/quality-gate.md makes the
agent clear types, lint, security, and tests before it says "done." No server, no
tokens — just the tools already on the box. Green here means "not obviously
broken," nothing more.
The deep scan is /sonar — a lever I pull, never auto-fired. It runs the
SonarQube scanner against a SonarQube server I host, then reads the findings
back inline. bootstrap.sh pre-pulls both Sonar images so the first scan doesn't
stall on a download:
sonar-scanner-cli— the scanner/sonarshells out to.mcp/sonarqube— the MCP server both Claude Code and OpenCode use to read issues back as me.
Two tools, two token types, one server. The split trips people up:
- The MCP server reads issues as me → USER token (
SONARQUBE_URL+SONARQUBE_TOKEN). - The
/sonarscanner pushes analysis results → Global Analysis token (SONAR_HOST_URL+SONAR_TOKEN).
Both URLs point at the same running SonarQube. Generate both tokens from the web UI
(avatar → My Account → Security → Generate Tokens, pick the type per above); the
per-project analysis key lives in sonar-project.properties. You bring your own
SonarQube — lean-code wires the plumbing, not the server.
Design rules
- YAGNI, ruthlessly. Every file justifies itself or it dies. Three near-duplicate rule sets become one. Templates with placeholder values get the values filled in deterministically by the script, not left for a human to fix.
- Opinionated by default. Modern tools, not legacy ones.
uvoverpip.podmanoverdocker.pnpmovernpm. Expo Router over React Navigation. The rules don't say "consider", they say "always" — and where there's a real reason to break a rule, the rule says so. - Layers don't reach across. A rule doesn't depend on a specific project structure. A project doesn't depend on a specific rule being present. Each layer works alone.
- Plain text, no clever encoding. Markdown for everything humans read. Bash for everything machines run. If you can't fix it with
vimandgit, it doesn't belong here. - No metrics. Coverage thresholds, lint scores, complexity numbers — all gameable by an LLM, all noise. Quality is enforced by criteria (happy path / error path / boundary), not by a number to chase.
- One cloud dependency, and it's named: Context7. Qdrant, Ollama, llama.cpp, SonarQube all run on hardware I control, which makes it easy to read this repo as fully self-hosted. It isn't.
rules/research.mdputs Context7 on the critical path of every task that touches a third-party library, and it's a hosted service — the library name and the lookup question leave the machine on every call, so keep proprietary code and secrets out of the query text. That's the deliberate trade: current docs beat a model's stale memory, and there's no local mirror of the world's documentation to point at instead. With Context7 unreachable the rule degrades to web search (also cloud), and past that to memory — which is the exact failure the rule exists to prevent.plugins/enforce-research.jsis the tripwire for that last case, but it only fires in OpenCode.
Not for
- Teams who need uniform tooling enforced via CI hooks
- Polyglot monorepos (the rules assume Python or TypeScript or both)
- Anyone who thinks "1% test coverage gain" is a meaningful sentence
Credits
The skeleton started as a study of the maximalist frameworks — this repo is what's left after asking "but do I actually need that?" eight hundred times. Go install one of those if you want the deluxe version; come back here when you want to know which parts you need. (It's an opinion, not the only right way. But at least, I understand it better now!)
What survived is mostly mine; what isn't is vendored with gratitude and attribution — none of this is my work, all of it is inspiration:
- stop-slop by Hardik Pandya (MIT) — strips the AI tells from prose before they reach you.
- SocratiCode by Giancarlo Erra — the agent's eyes; its exploration/management skills and the codebase-explorer agent are vendored here.
- Understand-Anything by Lum1104 — the human's eyes; knowledge-graph dashboards for the rest of us.
- claude-code-security-review by Anthropic (MIT) — the security prompt behind
/handoff's checkpoint, adapted to session diffs. - skills by Matt Pocock — nothing vendored, everything influenced. His videos and repo are where the
diagnoseskill, theCONTEXT.mdglossary, requirement-grilling, and vertical-slice TDD came from — without them this would be the ten-thousandth copy of the same mistakes. - A Philosophy of Software Design by John Ousterhout — the deep-modules and different-layer-different-abstraction lenses in the standards, and
/plan's design-it-twice step, are his ideas, deliberately kept in his words. - The Pragmatic Programmer by David Thomas & Andrew Hunt — tracer bullets:
/plan's Phase 1 is the thinnest working end-to-end slice, straight from their book.