CLAUDE.md · git:20260906.eccfc85 · 2026-09-06 · sha256 dce785c63b82b1c1
CLAUDE.md git:20260906.eccfc85A
Immutable. This exact content is served forever at /api/v1/blob/dce785c63b82b1c1.
# Shipwright SDLC Framework
## WHAT
- **Purpose**: AI-powered SDLC pipeline built on Claude Code — from user description to deployed, tested, secured application
- **Architecture**: Monorepo of Claude Code plugins (skills + hooks + scripts)
- **Stack**: Python 3.11+ scripts, Claude Code plugin system, uv package manager
## Structure
```
plugins/ # Claude Code plugins (one per SDLC phase)
shipwright-run/ # Orchestrator (entry point)
shipwright-project/ # Requirements decomposition (IREB)
shipwright-design/ # UI mockups from IREB specs (HTML)
shipwright-plan/ # Deep planning + external LLM review
shipwright-build/ # TDD implementation
shipwright-test/ # Testing (unit + smoke + Playwright E2E)
shipwright-security/ # Scanner chain + remediation loop
shipwright-deploy/ # Deployment (extensible flavors)
shipwright-changelog/ # Git sync + changelog + PR
shipwright-compliance/ # IREB traceability, RTM, SBOM, dashboard
shipwright-iterate/ # Daily iteration (complexity-adaptive)
shipwright-preview/ # Local browser preview
shipwright-adopt/ # Brownfield onboarding (analyze an existing repo)
shipwright-grade/ # Read-only Control Grade (A–F) for any repo (lead magnet)
# Command Center WebUI lives at github.com/svenroth-ai/shipwright-webui since v0.4.0
shared/ # Shared across all plugins
contracts/ # Cross-plugin public API (B8): compliance.py, iterate.py
profiles/ # Stack profile definitions (JSON) + deploy profiles
templates/ # CLAUDE.md, .shipwright/agent_docs, CI templates
prompts/ # Shared subagent prompts (code_reviewer, iterate_reviewer)
schemas/ # JSON schemas (run_config v2)
config/ # Shared config (external_review.json)
scripts/ # Shared Python utilities
tests/ # Tests for shared scripts and hooks
constitution.md # ALWAYS / ASK FIRST / NEVER rules for all agents
scripts/ # Top-level scripts (install.sh, verify-setup.sh)
docs/ # User-facing docs (guide.md, hooks-and-pipeline.md)
integration-tests/ # Cross-plugin integration tests
CHANGELOG-unreleased.d/ # Pending changelog drop files (aggregated at release)
```
## HOW
### Development
```bash
uv sync # Install dependencies
uv run pytest tests/ -v # Run tests for a plugin (from plugin dir)
uv run pytest integration-tests/ -v # Run integration tests (from root)
uvx ruff@0.15.15 check . # Bug-focused lint — GATING in CI (ci.yml)
uv run scripts/verify_local.py # The CI merge guards that run nowhere else
```
**Run `verify_local.py` before pushing.** It mirrors the three bespoke CI merge
guards that no other local step runs, so their failure is otherwise learned
about from a red CI run after the iterate reports done. It is a pre-flight, not
a substitute for CI — full rationale lives in the script's own docstring.
**F0 and F11 run it for you** inside an iterate; typing it yourself is how you
check a tree outside a run.
**Lint is a hard CI gate.** `.github/workflows/ci.yml` runs `uvx ruff@0.15.15
check .` with no `|| true` / `continue-on-error`, so a lint failure blocks merge.
The ruleset is deliberately curated (Pyflakes + a few bug-class pycodestyle
rules, cosmetic rules omitted) and lives in the root `pyproject.toml`
`[tool.ruff.lint]` — run it locally before pushing. ruff is pinned (not a project
dependency) so a new release can't silently change the gate.
### Plugin Structure (each plugin follows this pattern)
```
plugins/shipwright-{name}/
.claude-plugin/plugin.json # Plugin metadata
hooks/hooks.json # Claude Code hooks
agents/ # Subagent definitions (markdown)
skills/{name}/SKILL.md # Main skill definition (folder = slash command suffix)
scripts/ # Python scripts (checks, hooks, lib, tools)
tests/ # Plugin-specific tests
pyproject.toml # Plugin dependencies
```
### Conventions
- All scripts invoked via `uv run`; hooks resolve paths via `${CLAUDE_PLUGIN_ROOT}`
- Env var prefix `SHIPWRIGHT_` (`SHIPWRIGHT_SESSION_ID` = unified session id;
`SHIPWRIGHT_PLUGIN_ROOT` = active plugin dir); config-file prefix
`shipwright_` (`shipwright_*_config.json`, written to the target project)
### Hooks & Pipeline Reference
`docs/hooks-and-pipeline.md` is the single source of truth for what fires when:
the context-loading matrix (who reads what), the artifact-write matrix (who
writes what), the hooks registry, config data flow, and between-phase actions.
**ALWAYS read it first** when working on any plugin. **Rule:** modifying a hook
(`hooks.json`), adding/removing a pipeline phase, changing phase validators or
between-phase actions, or changing what a plugin reads at startup means you MUST
update it in the same diff.
### When editing plugin-side files
Changes under `plugins/*`, `shared/scripts/`, or any `SKILL.md` file do NOT
auto-sync to the plugin cache Claude Code uses at runtime — after `git push`,
run `bash scripts/update-marketplace.sh` then `uv run
scripts/check_plugin_cache_sync.py --strict`. Monorepo-only; end-users on the
installed plugins never need this. **Full procedure + rationale:**
`shared/prompts/writing-plugin.md`.
### Documentation Guide
`docs/guide.md` is the primary user-facing documentation (README.md is a
summary that links to it). **Rule:** a new skill, a changed skill
command/argument/flag, a pipeline-flow change, or a constitution change means
checking whether the guide needs an update — its Chapter 4 (phases),
Chapter 7.5 (constitution), Chapter 8 (quality gates) and Appendix B (command
reference) are the sections that go stale.
### Where documents live
**`docs/` holds hand-written instructions** — for users and for developers
alike. The test is not who reads it, but that someone *wrote* it and someone
*reads* it. `guide.md` and `hooks-and-pipeline.md` sit there as equals.
**`.shipwright/` holds the artifacts Shipwright itself keeps** — specs under
`.shipwright/planning/`, evidence under `.shipwright/compliance/`, architecture
and decision memory under `.shipwright/agent_docs/`. They come out of runs;
they are not composed by hand.
**A file that is neither belongs nowhere:**
- A **record of finished work** is deleted. Git history keeps it.
- A **generated file** is not filed among the hand-written ones. If it is
committed at all, it lives **next to the source it is generated from**, so
source and render are read together and the drift test has an obvious
subject. `shared/config/gate_catalog.json` + `gate_catalog.md` is the shape.
For neither case is the answer "then put it under `.shipwright/`". The
`agent_docs`, `planning` and `compliance` trees are read as well — they are not
a parking lot for files nobody reads. Relocating an unread file into a read
directory is filing, not deciding.
### Testing
```bash
cd plugins/shipwright-build && uv run pytest tests/ -v # single plugin
uv run pytest integration-tests/ -v # integration
```
**One test root per pytest process — a hard rule, enforced by the repo-root
`conftest.py` (exit 4).** Roots: `integration-tests`, `shared/tests`,
`shared/scripts/tests`, `shared/scripts/tools/tests`, each `plugins/*/tests`.
Each needs `scripts`/`lib`/`tools` to mean a *different* directory, and Python
caches whichever package loads first — `sys.path` order cannot fix it
(ADR-044). One root per invocation, one `--junitxml` per root; merge
afterwards. Why, plus the two gaps the guard does not cover:
`.shipwright/planning/iterate/iterate-2026-07-27-pytest-root-composition.md`.
## Context
- **Guide**: docs/guide.md (primary user-facing documentation)
- **Hooks & Pipeline**: docs/hooks-and-pipeline.md (context loading, hooks registry, between-phase actions)
- **Glossary**: shared/glossary.md (mandatory-read — shared vocabulary
used by hooks, agents, subagents, and compliance audits — Allowlist,
Ratchet, Anti-Ratchet, Producer, Action-Unit, Canon-Gate, …)
## Pre-commit hooks
Contributors must install the bloat anti-ratchet pre-commit hook
**once per clone**:
```bash
bash scripts/install-hooks.sh # POSIX / Git-Bash on Windows
.\scripts\install-hooks.ps1 # PowerShell on Windows
```
This sets `git config core.hooksPath scripts/hooks` (idempotent;
refuses to overwrite an existing different value without `--force`).
The hook only blocks commits that ratchet an existing entry in
`shipwright_bloat_baseline.json` — new crossings are surfaced by the
Group H detective audit post-merge. See `shared/glossary.md` for the
terminology and `shared/scripts/lib/anti_ratchet.py` for the rule.
## Review subagents: standing request. Workflows: ask every time.
**The review cascade is requested by default — spawn it, never pause to ask, and never record a review `not_run` citing a session policy.** That is `spec-reviewer` → `code-reviewer` → `doubt-reviewer` plus the review subagents other phase skills prescribe (build Step 6, campaign review). Claude Code withholds subagent spawning until the user asks; **this file is that request, and it stands for every session.** **The grant covers reviewers, not fan-out.** Dynamic workflows, deep-research, and parallel implementation subagents (build's `section-builder` loop) spend openly and stay the operator's call — ask explicitly, every time, and never infer them from the grant above. A project that does not want this can delete the section; it is deliberately plain and must not be compressed further, because it has to read as the user's request at runtime.
## Asking the user questions (plain language)
Every interactive question — clarification, choice, confirmation — must be
answerable by a **non-senior developer or a normal user** without decoding
jargon. The person answering may not know the internals.
- **Lead with the functional meaning:** what the choice changes about how the
app behaves, not the implementation. "Should a deleted item be recoverable,
or gone for good?" — not "soft delete with a tombstone flag, or hard delete?".
- **Gloss any unavoidable term** in parentheses (e.g. "idempotent — safe to run
twice without doubling the effect").
- **Make options concrete and comparable:** each in plain words with its
real-world trade-off ("A is simpler but slower to load; B is faster but adds
a setup step"), never a raw technical menu.
- **Rule of thumb:** a product owner should be able to answer without asking
"what does that mean?". If they couldn't, rewrite it.
This applies to every interactive question — clarifications, plan approvals,
design feedback, and remediation choices alike. It governs *phrasing only*;
the underlying rigor of the work is unchanged.