A portable Secure-by-Tier + Production Readiness harness for Claude Code and Codex CLI, packaged as a plugin. It right-sizes security and production-grade review to a project's tier/profile β it never gold-plates a throwaway spike, and never under-protects an app holding real user data. You opt in per project; projects you don't opt in stay untouched.
Review effort should scale with blast radius, operational reality, and maintainability risk β not ambition.
- Why this
- The tiers
- What's in the box
- Install β Claude Code
- Install β Codex CLI
- How to use it
- Do I need a line in CLAUDE.md?
- How it works
- Production readiness expansion
- The opt-in model
- Limitations
Every app that touches a network or stores data has a security surface. Every production app also has an operational surface: tests, rollback, logging, scaling limits, data deletion, and the ability for someone else to understand the code later. The question is never "is it secure?" or "is it production ready?" in the abstract β it's "has it been checked enough for what it actually does?"
Two failure modes are equally bad:
- Under-securing. A real app with users and PII that skips the basics. Most breaches are
not exotic β they come from cheap-to-prevent mistakes: a secret committed to git, a
known-vulnerable dependency, a missing auth check, SQL injection, a cookie without
httpOnly. These are the OWASP Top 10 and they account for the large majority of real-world incidents. - Over-securing. Forcing a weekend prototype through a SOC 2 checklist, a pentest, and encryption-at-rest. That burns time and money on risk that doesn't exist yet, and it teaches people to ignore the process.
The fix is right-sizing. Classify the project by blast radius, then apply only the controls that match. A scratch script needs secret hygiene. A multi-tenant SaaS holding customer data needs that plus auth, tenant isolation, input validation, tests, observability, rollback paths, and dependency/secret scanning in CI. A health or fintech app needs all of that plus encryption, audit logging, a threat model, compliance scope, and a pentest.
This plugin encodes that judgement so you don't have to re-derive it each time, and so an AI agent working in your repo applies the correct bar automatically. It also calls out technical debt from fast AI-assisted coding when that debt would block safe production work.
The cheapest, highest-value controls (any real project): keep secrets out of the repo
(gitleaks), scan dependencies in CI (npm audit / pip-audit), require auth on anything
non-public, add security headers, and set httpOnly/secure cookies. Near-zero effort,
catches most real issues. The plugin proposes these first.
Cumulative β each tier includes every control from the tiers below it. First match wins, top-down.
| Tier | Name | You're here if⦠| Core controls it adds |
|---|---|---|---|
| T0 | Throwaway / Local | Never deployed; no real data; runs only on your machine | Secrets gitignored; no prod creds locally. That's it. |
| T1 | PoC / Demo | Deployed, but throwaway data; internal eyes only | + OWASP basics, dependency scan, secret scan, auth on non-public |
| T2 | Production (low-sensitivity) | Real users + auth; non-sensitive PII (name/email) | + SAST, input validation, per-request authZ + tenant isolation, security headers, rate limiting, HTTPS + secure cookies, no PII in logs, GDPR/PDPA baseline |
| T3 | Production (regulated) | Health/financial/biometric data, payments, or contractual ISO/SOC 2 | + encryption at rest, full GDPR/PDPA program, HIPAA controls, threat model, audit logging, pentest |
Overlays (any tier): EU users β GDPR Β· Thai users β PDPA Β· health data β HIPAA Β· payments β bump to T3.
The full model with the complete per-tier checklist lives in
reference/security-baseline-spec.md.
| Component | What it does |
|---|---|
skill security-baseline |
Tier-aware security review. Detects the tier β applies only that tier's checklist β reports findings as π΄/π‘/π’ with file:line + a concrete fix. |
skill production-readiness |
Production-grade review orchestrator. Selects the right review mode and dimensions across security, privacy/compliance, architecture, scalability, reliability, testing, observability, technical debt, and release readiness. |
skill security-baseline-init |
The per-project opt-in. Classifies the security tier and production readiness profile, writes the baseline block into CLAUDE.md / AGENTS.md, and optionally installs the pre-commit scanner. |
skill security-reviewer |
Cross-runtime, read-only reviewer for one delegated security area. Codex subagents can invoke it explicitly during fan-out. |
| agents | Read-only, area-scoped reviewers. The security and production-readiness skills can fan out to security, architecture, technical debt, scalability, ops, testing, observability, and compliance reviewers for larger audits. |
hook pre-commit-scan.sh |
Deterministic scanners (gitleaks + npm audit / pip-audit). Optional SBL_PROD=1 strict mode also runs discoverable lint/typecheck/test gates. No AI reasoning involved. |
script check-baseline-config.sh |
Lightweight deterministic check that CLAUDE.md / AGENTS.md contains the expected security tier and production readiness profile block. |
skill security-ledger |
Reviews with memory: a per-project ledger (.security-baseline/ledger.md, private by default) with stable SB-### IDs, a status lifecycle (open β fixed β fixed-verified, plus accepted-risk and false-positive; a fixed-verified item that returns is reopened and annotated regressed), a foundation checklist, and review history. Runs the CLI decision loop. |
script ledger.py |
Deterministic ledger operations (IDs, transitions, summary, history). Stdlib Python; the skill is its only caller. |
security-reviewer exists twice on purpose: the agent (agents/security-reviewer.md) and
the skill (skills/security-reviewer/SKILL.md) do the same job for different runtimes β the
agent is Claude Code's native subagent form, the skill is the portable one Codex invokes as
$security-reviewer. Same review, one per runtime; you never need both in a single fan-out.
security-baseline/
βββ .claude-plugin/
β βββ plugin.json # manifest
β βββ marketplace.json # makes the repo installable
βββ .codex-plugin/
β βββ plugin.json # Codex / universal plugin manifest
βββ skills/
β βββ security-baseline/SKILL.md # review
β βββ production-readiness/SKILL.md # production gate orchestrator
β βββ security-baseline-init/ # opt-in command
β β βββ SKILL.md
β β βββ scripts/install-project-assets.sh # copies consumer assets, migrates legacy
β β βββ assets/codex-agents/*.toml # project-scoped Codex reviewer templates
β βββ security-reviewer/SKILL.md # portable delegated reviewer
β βββ security-ledger/SKILL.md # reviews with memory
βββ agents/
β βββ security-reviewer.md
β βββ architecture-reviewer.md
β βββ technical-debt-reviewer.md
β βββ scalability-reviewer.md
β βββ ops-readiness-reviewer.md
β βββ testing-reviewer.md
β βββ observability-reviewer.md
β βββ compliance-reviewer.md
βββ hooks/pre-commit-scan.sh
βββ scripts/
β βββ check-baseline-config.sh
β βββ ledger.py # deterministic ledger operations
β βββ validate-package.py # cross-runtime packaging checks
βββ tests/
β βββ smoke.sh # packaging, installer, scanner, ledger CLI end-to-end
β βββ test_ledger.py # ledger.py unit tests
βββ reference/
βββ security-baseline-spec.md # the security model
βββ production-readiness-spec.md # the production-readiness model
βββ production-readiness-plan.md # expansion roadmap
βββ models.md # model tiers, profiles, guard rules
βββ decision-brief.md # decision brief shape + prompt handling
βββ examples/
βββ production-readiness-report.md
βββ github-actions-production-gates.yml
No marketplace needed β point Claude Code at the plugin directory for a session:
claude --plugin-dir /path/to/security-baselineThe repo ships a .claude-plugin/marketplace.json, so:
/plugin marketplace add pmrster/security-baseline-plugin
/plugin install security-baseline@security-baseline-marketplacePin a release with <owner>/<repo>@v0.3.0, or use a full git URL for non-GitHub hosts.
Team-wide, add it to .claude/settings.json instead of running the command on each machine:
{
"extraKnownMarketplaces": {
"security-baseline-marketplace": {
"source": { "source": "github", "repo": "<owner>/<repo>" }
}
}
}The repo includes a validated .codex-plugin/plugin.json following the
OpenAI plugin packaging model. For local
development before the plugin is published, link the skills into the Codex skills directory
(~/.codex/skills/, or the cross-runtime ~/.agents/skills/):
ln -s /path/to/security-baseline/skills/security-baseline ~/.codex/skills/security-baseline
ln -s /path/to/security-baseline/skills/production-readiness ~/.codex/skills/production-readiness
ln -s /path/to/security-baseline/skills/security-baseline-init ~/.codex/skills/security-baseline-init
ln -s /path/to/security-baseline/skills/security-reviewer ~/.codex/skills/security-reviewerCodex notes:
-
It reads
AGENTS.mdfor project instructions βsecurity-baseline-initwrites the same tier block there. -
Current Codex releases enable subagent workflows by default. No legacy
multi_agentfeature flag is required. A user can disable them withagents.enabled = false; the skills then review inline. -
To install project-owned scanner assets and the bundled read-only Codex custom agents, run from the consuming project after reviewing the script:
bash /path/to/security-baseline/skills/security-baseline-init/scripts/install-project-assets.sh \ --codex-agents .Then, if
.git/hooks/pre-commitdoes not already exist, wire the runtime-neutral scanner:ln -s ../../.security-baseline/hooks/pre-commit-scan.sh .git/hooks/pre-commit
Never overwrite an existing Git hook; compose it deliberately instead.
There are three ways the security review reaches your code. They stack β use as many as you want.
Run this once in a project:
/security-baseline:security-baseline-init
It will:
- Detect or ask the project's tier, production readiness profile, and overlay questions.
- Write a baseline block into
CLAUDE.md(andAGENTS.mdfor Codex) β see the next section. - Offer to install the pre-commit scanner. If you say yes, it copies project-owned files to
.security-baseline/, then offers Claude Code hook wiring or a native Git hook for Codex and other runtimes. Hook configuration requires approval because it can block commits. - For Codex projects, offer project-scoped read-only reviewer agents under
.codex/agents/. - Report exactly what it changed. Nothing global is touched.
Re-run it anytime to change the tier or refresh the hook.
You don't have to name the tool. Skills carry a description that tells the agent when to fire. Just ask, in plain language:
"Is this safe to deploy?" "Review the security of my changes before I open a PR." "Run a production-readiness review before launch." "Check whether this vibe-coded feature has technical debt that blocks production." "Did I leave any secrets or obvious vulns in here?" "Set up CI security scans for this repo."
Claude (or Codex) will invoke the relevant skill, detect the tier, and review the diff or production path against the selected controls.
Invoke them directly by name. In Claude Code, use plugin-namespaced slash commands:
/security-baseline:security-baseline # run a tier review
/security-baseline:production-readiness # run a production-readiness review
/security-baseline:security-baseline-init # opt the project in / change the tier
In Codex CLI or the IDE extension, use skill mentions:
$security-baseline
$production-readiness
$security-baseline-init
$security-reviewer
Every review groups findings by severity, and each finding names the file, the control it violates, and the fix:
π΄ Must fix before merge
src/server.js:3 β hardcoded Stripe key (secrets must come from env) β move to process.env.STRIPE_KEY
π‘ Should fix
no rate limiting on /login β add express-rate-limit (e.g. 20 req / 15 min)
π’ Nice to have
no .gitignore β add one so .env can't be committed
It only flags controls for your tier (no T3 demands on a T1 demo), and it never claims your app is "secure" β only "checked X against tier Y; out of scope: Z."
Once a project has a ledger, every review reads it first and reports New Β· Still open Β·
Regressed Β· Verified fixed by ID β a fixed issue can't silently come back as "critical";
it comes back as SB-004 regressed @<commit>. quick-diff and pr-gate reviews scope to the
diff since the last review, which is also the main token saving; pre-prod and full-audit
deliberately ignore that boundary and review the full production path or the whole repo.
In the CLI you see a compact verdict, then one decision at a time for π΄/π items: a plain
"why it matters", the standard it comes from, and a full comparison of the options across
security, effort, user impact, performance, conflicts, tech debt, over-engineering, structure,
deployment/live, rollback, cost, and testing β then go A / go B / accept-risk / later / explain more / ask a question. Your answer is the only thing that gets written as a decision.
open: 2 (π΄1 π 1) Β· accepted-risk: 1 Β· fixed-verified: 5 Β· checklist: 7/12
New SB-007 π β Invoice job can double-charge on retry β src/jobs/sendInvoice.ts:31
Regressed SB-001 π΄ β Any user can read another customer's project by ID β src/app/api/projects/[id]/route.ts:42
decisions needed: 2
Model use follows reference/models.md: judgment work on the best model, verification on a
balanced model, presence checks on the cheapest β and a cheap model never closes a finding.
The pre-commit scanner is plain bash and needs no AI:
bash hooks/pre-commit-scan.sh # scan staged changes (or the repo if nothing staged)
SBL_FULL=1 bash hooks/pre-commit-scan.sh # force a full repo secret scan
SBL_PROD=1 bash hooks/pre-commit-scan.sh # include strict production gatesExit 0 = clean / warnings only Β· exit 2 = blocked (a configured blocking finding). A scanner that
isn't installed is skipped with a warning β a missing tool never blocks your commit.
SBL_PROD=1 adds deterministic readiness checks when they are discoverable:
- Node: every npm script named in
SBL_PROD_CHECKS(default:lint,typecheck,test) that exists inpackage.json. - Python:
ruff,mypy, andpytestmap to thelint/typecheck/testcheck names and run only when matching config/test signals exist.
Set SBL_PROD_CHECKS to choose which checks run (any npm script name works for Node), for
example:
SBL_PROD=1 SBL_PROD_CHECKS=lint,typecheck,build bash hooks/pre-commit-scan.shCheck that a project has opted in correctly (from the plugin repo, or via the copy that
security-baseline-init places at .security-baseline/scripts/check-baseline-config.sh in opted-in
projects):
bash .security-baseline/scripts/check-baseline-config.shNo β the skills work without it. You can call them manually (/security-baseline:β¦) or let
the agent auto-invoke them when you ask a security question. Nothing in CLAUDE.md is required
for that.
But the block is what makes it stick. security-baseline-init writes a small block like:
<!-- security-baseline:start -->
## Security tier
This project is **T2** (production, low-sensitivity PII). EU users: no. Thai users: yes (PDPA applies).
Apply the Secure-by-Tier baseline via the `security-baseline` skill. Run a tier review before each PR to `main`.
## Production readiness profile
This project uses the **production** profile. Default PR review: `pr-gate`. Default deploy/launch review: `pre-prod`.
Enabled dimensions: security, architecture, scalability, reliability/ops, testing, observability, technical debt, release readiness; compliance only when triggered.
Strict deterministic gates: use `SBL_PROD=1` in CI or pre-push; the default commit hook remains security-focused.
Apply the Production Readiness baseline via the `production-readiness` skill. Run a production-readiness review before major PRs and launches.
<!-- security-baseline:end -->That block does three jobs a one-off command can't:
- Declares the tier, so the review skill stops asking "what tier is this?" every time and reviews against the right bar immediately.
- Declares the production profile, so
production-readinessknows whether to run asquick-diff,pr-gate,pre-prod, or a fuller review. - Is a standing instruction. Because
CLAUDE.md(andAGENTS.mdfor Codex) is loaded into the agent's context every session, the agent proactively remembers to run a tier review before a PR β instead of only when you happen to ask. It turns "I review when I remember" into "the agent reviews for me."
So: optional for ad-hoc use, recommended for any project you'll come back to. That's why
init writes it for you.
- Classify. The tier and production readiness profile are read from
CLAUDE.md/AGENTS.mdif declared; otherwise inferred from signals (deploy config, auth code, PII/payment in the schema, regulated data) and confirmed with you. - Load the checklist. Only the cumulative controls for that tier/profile (T0 β T1 β T2 β T3).
- Review. The diff by default (token-lean); the whole repo on request. For a big audit, the review skill can dispatch read-only area reviewers in parallel β security, architecture, technical debt, scalability, ops, testing, observability, and compliance β then merge their findings.
- Report & offer fixes. Findings as π΄/π‘/π’ with
file:line+ fix, then an offer to apply the free/mechanical ones (CI config, headers,.gitignore).
Two enforcement layers, deliberately split by what each is good at:
- Deterministic scanners (gitleaks,
npm audit, optional strict lint/typecheck/test gates) β the pre-commit hook. It runs real commands and can block. Reliable; needs no reasoning. - Smart, tier-aware review (authZ, tenant isolation, "is this PII in a log?") β an
instruction in
CLAUDE.md. A hook can't reason about your business logic; an AI agent can. Both are project-scoped, which is exactly the opt-in mechanism.
The plugin is security-first, and now includes a first production-readiness orchestrator that
keeps security-baseline as the security pillar and adds architecture, scalability, reliability,
testing, observability, maintainability, technical-debt, compliance, and release readiness
review.
The model is documented here:
reference/production-readiness-plan.mdexplains the implementation plan and guardrails.reference/production-readiness-spec.mddefines the review model.reference/examples/production-readiness-report.mdshows the expected report shape and severity calibration.reference/examples/github-actions-production-gates.ymlis a copyable CI template for deterministic gates in consuming projects.
The executable layer is skills/production-readiness/SKILL.md. It can fan out to the
area-specific read-only reviewers under agents/ in Claude Code. In Codex it uses the portable
security-reviewer skill plus project-scoped read-only custom agents installed by init, with a
generic read-only subagent fallback. The deterministic scanner also has an opt-in SBL_PROD=1
strict mode for discoverable lint/typecheck/test gates.
- A project opts in by running
security-baseline-initonce. - A project that never runs it is completely unaffected β no global hook, no forced review.
- Installing the plugin only makes the skills and agents available; it changes no project's behavior until you opt that project in.
- Not a pentest / SAST product. It orchestrates and right-sizes, surfacing the free high-value controls first β it doesn't replace dedicated tooling at T3.
- Not hard enforcement. On free private GitHub repos you can't enforce branch protection; the hook is a local gate and the review is advisory.
- CodeQL needs Code Scanning (GHAS) β free on public repos, not on free private ones; any emitted CI keeps it optional.
- In-memory rate limiting is per-instance only β use a shared store (e.g. Redis) for real distributed limits.
- The copied hook doesn't auto-update with the plugin. Re-run
initto refresh it. - Codex custom agents are project-scoped. Plugin installation distributes the skills; run
security-baseline-initin each consuming repo that should also receive.codex/agents/*.toml. - Upgrading from β€0.2.x: consumer assets moved from
.claude/hooks/to.security-baseline/. Re-runsecurity-baseline-init; it migrates the legacy layout.
Output is always "checked X against tier Y; out of scope: Z" β never a blanket "this is secure." Security is a moving target; the plugin tells you what it verified and what it didn't.
MIT.