soloship 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +252 -0
- package/bin/soloship.js +2 -0
- package/dist/artifacts.d.ts +83 -0
- package/dist/artifacts.js +241 -0
- package/dist/ci.d.ts +2 -0
- package/dist/ci.js +184 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +63 -0
- package/dist/detect.d.ts +30 -0
- package/dist/detect.js +127 -0
- package/dist/doctor.d.ts +10 -0
- package/dist/doctor.js +205 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.js +477 -0
- package/dist/init.d.ts +5 -0
- package/dist/init.js +94 -0
- package/dist/manifest.d.ts +63 -0
- package/dist/manifest.js +90 -0
- package/dist/pkg.d.ts +1 -0
- package/dist/pkg.js +9 -0
- package/dist/rollback.d.ts +12 -0
- package/dist/rollback.js +129 -0
- package/dist/rules.d.ts +1 -0
- package/dist/rules.js +119 -0
- package/dist/scaffold.d.ts +7 -0
- package/dist/scaffold.js +138 -0
- package/dist/templates.d.ts +5 -0
- package/dist/templates.js +175 -0
- package/dist/upgrade.d.ts +12 -0
- package/dist/upgrade.js +62 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Soloship
|
|
2
|
+
|
|
3
|
+
> Ship solo, safely.
|
|
4
|
+
|
|
5
|
+
Soloship is guardrails for non-coders building software through AI agents. It's a Claude Code plugin that gives you three things a traditional engineering team would: **mechanical enforcement** that fires automatically (9 hooks, 4 rules, CI checks — no judgment calls required), **19 workflow skills** that guide you through the steps a professional would take (each with enforcement gates and anti-rationalization tables so the agent can't cut corners), and **a one-command setup** that detects your stack and wires everything into the project.
|
|
6
|
+
|
|
7
|
+
**Quick reference:** [aifoundationlevels.com/soloship-cheatsheet](https://aifoundationlevels.com/soloship-cheatsheet)
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Soloship is a [Claude Code](https://claude.com/claude-code) plugin. If you don't have Claude Code installed yet, install it first — then come back here.
|
|
12
|
+
|
|
13
|
+
Inside any Claude Code session, run these two commands **one at a time** — run the first, wait for it to finish, then run the second:
|
|
14
|
+
|
|
15
|
+
**1. Add the marketplace:**
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
/plugin marketplace add thedigitalorganizer/soloship
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**2. Install the plugin:**
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
/plugin install soloship@soloship
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
That's it. The plugin installs globally, so you only do this once on your machine. All 19 Soloship commands are now available as `/soloship:*` slash commands in every project you open.
|
|
28
|
+
|
|
29
|
+
### Using Soloship in a project
|
|
30
|
+
|
|
31
|
+
Open the project you want to use Soloship in — a brand-new empty folder or an existing codebase, either works — then run one of these in Claude Code:
|
|
32
|
+
|
|
33
|
+
**Brand-new project (no code yet):**
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
/soloship:bootstrap
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Bootstrap asks four questions about your project, then sets up the guardrails (hooks, rules, folder structure, `CLAUDE.md`). When it finishes, you're ready to build. Start your first feature with `/soloship:brainstorm`.
|
|
40
|
+
|
|
41
|
+
**Existing project (already has code):**
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
/soloship:audit
|
|
45
|
+
/soloship:bootstrap
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`/soloship:audit` investigates the codebase first (it dispatches 10 parallel agents to map architecture, conventions, quality, and risk). `/soloship:bootstrap` then reads what audit found and tailors the setup to your actual code instead of guessing. Takes a few minutes, but it's what keeps the guardrails from fighting your existing conventions.
|
|
49
|
+
|
|
50
|
+
After bootstrap, the daily loop is `/soloship:brainstorm` → `/soloship:plan` → `/soloship:implement` → `/soloship:shipthorough`.
|
|
51
|
+
|
|
52
|
+
## How we got here
|
|
53
|
+
|
|
54
|
+
Soloship didn't start as a project. It started as a frustration.
|
|
55
|
+
|
|
56
|
+
We had 40+ solution documents in `docs/solutions/` — real fixes to real problems we'd hit before. The kind of knowledge that should prevent you from making the same mistake twice. But the agents kept making the same mistakes. We finally stopped and asked why.
|
|
57
|
+
|
|
58
|
+
The answer: none of the tools in our stack were reading the solutions at the point of execution. [Compound Engineering](https://github.com/EveryInc/compound-engineering-plugin)'s planning workflow dispatches a `learnings-researcher` agent that searches `docs/solutions/` — but it runs once, during the research phase, and its results get compressed into a few bullet points in the plan doc. The execution workflow never touches the solutions directory. It reads the plan, follows the plan, and trusts the plan to carry everything forward. With 40+ solution docs, most get scored out during the research pass. What survives is a summary of a summary. And once execution starts, there's no retrieval — even when the agent is hitting the exact error a solution doc describes.
|
|
59
|
+
|
|
60
|
+
So we tried **rules** — a `solution-search` rule that told the agent to check solutions before planning, debugging, or reviewing. It helped, when the agent followed it. But rules are suggestions. The agent would rationalize past them: "this is a simple change, no need to search." We'd ask if the rules were followed, and the honest answer was usually no.
|
|
61
|
+
|
|
62
|
+
So we tried **hooks** — mechanical triggers that fire regardless of what the agent is paying attention to. Hooks can't be rationalized away. That worked better. But wiring up hooks, rules, solution docs, `AGENTS.md` files, and CI checks for each new project was its own overhead.
|
|
63
|
+
|
|
64
|
+
And the workflow skills we were routing through weren't quite right either. [gstack](https://github.com/garrytan/gstack) has a strong skill set — QA, design review, security, shipping — but its skills are verbose and try to cover too much surface area. The agent would get lost in instruction volume, or the skill would prescribe steps that didn't apply to a solo operator's workflow. So we started pulling the good parts out and writing our own versions: leaner, opinionated for the solo use case, with enforcement gates and solution-search wired in from the start. Where the upstream tools already do the job well, Soloship routes to them and adds enforcement on top rather than rewriting them.
|
|
65
|
+
|
|
66
|
+
That became Soloship.
|
|
67
|
+
|
|
68
|
+
## How it works
|
|
69
|
+
|
|
70
|
+
Three layers, from most mechanical to most guided:
|
|
71
|
+
|
|
72
|
+
**Hooks** fire automatically on git events. They can't be rationalized away. Dangerous command blocking, security scanning, auto-lint, CHANGELOG enforcement, plan validation, architecture fitness functions. If the agent forgets, the hook remembers.
|
|
73
|
+
|
|
74
|
+
**Rules** are injected into every agent session as always-on context. Solution search before planning, plan materialization after plan mode, plan rationale requirements, plan lifecycle enforcement. The agent can't not see them, even if a skill doesn't reference them.
|
|
75
|
+
|
|
76
|
+
**Skills** are guided workflows invoked as `/soloship:*` commands. Each adds enforcement gates (checklists the agent must complete), anti-rationalization tables (preemptive counters to the ways agents cut corners), and routing to the right underlying tool.
|
|
77
|
+
|
|
78
|
+
### Skill architecture
|
|
79
|
+
|
|
80
|
+
Some skills are fully self-contained — the logic lives entirely in the SKILL.md:
|
|
81
|
+
|
|
82
|
+
| Skill | What it does |
|
|
83
|
+
|-------|-------------|
|
|
84
|
+
| `/audit` | 10 parallel investigation agents, two-phase with human checkpoint |
|
|
85
|
+
| `/bootstrap` | Reads audit findings, generates governance infrastructure |
|
|
86
|
+
| `/spec` | Formal specification with acceptance criteria |
|
|
87
|
+
| `/onboard` | Reads all project docs, produces orientation briefing |
|
|
88
|
+
| `/shipfast` | Lint → test → build → commit → push → deploy |
|
|
89
|
+
| `/cleanup` | 5 audit agents → interactive proposals → atomic execution |
|
|
90
|
+
|
|
91
|
+
Others are routers — Soloship adds enforcement and routing logic, then dispatches to an external skill:
|
|
92
|
+
|
|
93
|
+
| Skill | Routes to | What Soloship adds |
|
|
94
|
+
|-------|-----------|-------------------|
|
|
95
|
+
| `/brainstorm` | `office-hours` (product) / `superpowers:brainstorming` (technical) | Product-vs-technical routing, mandatory design-first nudge |
|
|
96
|
+
| `/plan` | `superpowers:writing-plans` / `plan-eng-review` | Solution search before planning, 7-point enforcement gate, artifact contracts |
|
|
97
|
+
| `/implement` | `superpowers:subagent-driven-development` / `superpowers:dispatching-parallel-agents` | Plan-first enforcement, execution strategy routing |
|
|
98
|
+
| `/debug` | `superpowers:systematic-debugging` | Solution search for prior art, root-cause iron law |
|
|
99
|
+
| `/learn` | `compound-engineering:workflows:compound` (Step 1) | Solution doc via CE, then own protocols: JSONL logging, registry audit, AGENTS.md propagation + creation |
|
|
100
|
+
| `/review` | `plan-eng/ceo/design-review` (plans) / 3-pass agents (code) | Target detection (plan vs code), severity classification, synthesis |
|
|
101
|
+
| `/shipthorough` | Invokes `/review` internally | 12-step pipeline: preflight, merge, lint, test, coverage audit, review, registry, CHANGELOG, plan lifecycle, commits, PR, deploy |
|
|
102
|
+
| `/qa` | gstack `qa` / `qa-only` | Mode selection (fix vs report-only) |
|
|
103
|
+
| `/security` | gstack `cso` | Post-audit triage routing |
|
|
104
|
+
| `/design-review` | gstack `design-review` | Adds AI slop detection pass (visual/content/layout patterns) |
|
|
105
|
+
| `/autoplan` | gstack `autoplan` | Chains CEO + design + eng + DX reviews with auto-decisions |
|
|
106
|
+
| `/checkpoint` | gstack `checkpoint` | Session state snapshots for `/clear` recovery; pairs with `/onboard` |
|
|
107
|
+
| `/health` | gstack `health` | Composite 0-10 quality score with trend tracking; pre-ship gate |
|
|
108
|
+
|
|
109
|
+
## What you get
|
|
110
|
+
|
|
111
|
+
### What bootstrap installs into your project
|
|
112
|
+
|
|
113
|
+
When you run `/soloship:bootstrap` (or `/soloship:audit` → `/soloship:bootstrap` on an existing project), it detects your language, framework, and package manager, then installs:
|
|
114
|
+
|
|
115
|
+
- **Folder scaffolding** — `docs/plans/`, `docs/solutions/`, `docs/audit/`, `AGENTS.md` stubs
|
|
116
|
+
- **9 Claude Code hooks** — dangerous command blocking, security scanning, auto-lint, CHANGELOG check, plan validation, workflow navigator, handoff reminder, checkpoint/rollback, architecture fitness
|
|
117
|
+
- **4 workflow rules** — solution search, plan materialization, plan rationale, plan lifecycle
|
|
118
|
+
- **GitHub Actions CI** with architecture fitness functions
|
|
119
|
+
- **Generated docs** — `CLAUDE.md`, `AGENTS.md`, `CHANGELOG`, `SOLUTION_GUIDE`, sized to your stack
|
|
120
|
+
|
|
121
|
+
Run bootstrap once per project. For existing code, run `/soloship:audit` first so bootstrap can tailor the setup.
|
|
122
|
+
|
|
123
|
+
### The skills
|
|
124
|
+
|
|
125
|
+
19 Claude Code skills invoked as `/soloship:*` slash commands:
|
|
126
|
+
|
|
127
|
+
**Setup & orientation**
|
|
128
|
+
|
|
129
|
+
- `/soloship:audit` — Deep 2-phase codebase investigation. Phase 1 launches 4 parallel agents to map architecture, conventions, decisions, and infrastructure. Phase 2 launches 6 more to assess quality, entanglement, security, dependencies, gaps, and leverage points. Human checkpoint between phases prevents building assessment on wrong assumptions. Produces `docs/audit/AUDIT-YYYY-MM-DD.md` + `audit-findings.json`.
|
|
130
|
+
- `/soloship:bootstrap` — Configures governance from audit findings or interactive questions. Creates CLAUDE.md, AGENTS.md files (3+ source file threshold), installs 4 core rules, and wires up hooks. Never overwrites existing files. Anti-rationalization table blocks "I'll set up governance later."
|
|
131
|
+
- `/soloship:onboard` — Reads CLAUDE.md, AGENTS.md, audit reports, and recent git history to produce a 7-section orientation briefing. Flags stale audit reports. No external routing — fully self-contained.
|
|
132
|
+
- `/soloship:checkpoint` — Saves working state (git status, decisions, remaining work) so any future session can resume cleanly. Routes to gstack `checkpoint`. Pairs with `/soloship:onboard` for `/clear` recovery.
|
|
133
|
+
|
|
134
|
+
**Daily work**
|
|
135
|
+
|
|
136
|
+
- `/soloship:brainstorm` — Detects whether the question is product (demand, audience, wedge) or technical (approaches, trade-offs) and routes accordingly: `office-hours` for product questions, `superpowers:brainstorming` for technical ones. Ends with a mandatory design-first nudge — sketch before you plan.
|
|
137
|
+
- `/soloship:spec` — Writes formal specifications with numbered acceptance criteria, data models, API contracts, user flows (including error states), and explicit out-of-scope boundaries. 8-point verification checklist. Fully self-contained.
|
|
138
|
+
- `/soloship:plan` — Searches `docs/solutions/` for prior art, reads architecture context, then routes to `superpowers:writing-plans` for standard features or `plan-eng-review` for architectural work. 7-point enforcement gate validates: Why lines, Key Decisions, Execution Strategy, Handoff section, no unaddressed pitfalls.
|
|
139
|
+
- `/soloship:implement` — Finds the most recent plan in `docs/plans/`, assesses the execution strategy, and routes to `superpowers:subagent-driven-development` (sequential tasks) or `superpowers:dispatching-parallel-agents` (independent modules). Freshness check warns on stale plans.
|
|
140
|
+
- `/soloship:debug` — Iron law: no fixes without root cause investigation. Searches solutions for prior art first, then routes to `superpowers:systematic-debugging` for 4-phase discipline (Investigate → Analyze → Hypothesize → Implement). Nudges `/learn` for non-obvious fixes.
|
|
141
|
+
- `/soloship:learn` — Captures knowledge from non-obvious work. Step 1 routes to `compound-engineering:workflows:compound` for solution doc creation. Steps 2-3 are Soloship's own protocols: JSONL logging for cross-session search and architecture registry drift checking. Steps 4-5 adapt the distributed AGENTS.md concept — propagating pitfalls into existing AGENTS.md files and creating new ones for directories above the 3-file governance threshold. Anti-rationalization table blocks "this fix was straightforward, not worth documenting."
|
|
142
|
+
- `/soloship:cleanup` — Knowledge system maintenance. Launches 5 parallel audit agents (solution health, overlap detection, plan lifecycle, AGENTS.md staleness, index sync), presents findings interactively, then executes approved changes in a single atomic commit. Merge candidates require 2-of-3 signal threshold. Each merge dispatched as an independent subagent to prevent context bloat.
|
|
143
|
+
|
|
144
|
+
**Shipping**
|
|
145
|
+
|
|
146
|
+
- `/soloship:shipfast` — Emergency deploy pipeline. Lint (with auto-fix tolerance), test (pre-existing failures allowed), build (must pass), commit, push, deploy. Auto-detects platform. Minimum viable safety, maximum speed.
|
|
147
|
+
- `/soloship:shipthorough` — Full due diligence: preflight checks, base branch merge, lint, test, coverage audit, 3-pass code review (via `/review`), registry update, CHANGELOG enforcement, plan lifecycle cleanup, bisectable commits, PR with structured body, verification gate, deploy. 12-point checklist.
|
|
148
|
+
|
|
149
|
+
**Quality**
|
|
150
|
+
|
|
151
|
+
- `/soloship:review` — Detects whether the target is a plan or code. Plans route to `plan-eng-review`, `plan-ceo-review`, or `plan-design-review`. Code gets a 3-pass parallel review: structural (SQL safety, auth, types, tests), adversarial (load, bad input, state transitions), and design-lite (a11y, responsive, AI slop — only if frontend changed). Severity classification with file:line references.
|
|
152
|
+
- `/soloship:qa` — Routes to gstack `qa` (test and fix) or `qa-only` (report only). Uses accessibility checklist as baseline.
|
|
153
|
+
- `/soloship:security` — Routes to gstack `cso` for infrastructure-first security scanning: OWASP Top 10, STRIDE threat modeling, secrets archaeology, dependency supply chain, npm audit.
|
|
154
|
+
- `/soloship:design-review` — Two-pass visual audit. Pass 1 routes to gstack `design-review` for spacing, hierarchy, and consistency. Pass 2 is Soloship's own AI slop detection — flags generic gradients, default shadows, "Welcome to" copy, 3-column feature grids, and other patterns that mark AI-generated design. Each fix committed atomically with before/after screenshots.
|
|
155
|
+
- `/soloship:health` — Routes to gstack `health` for a composite 0-10 codebase quality score (type check, lint, tests, dead code) with trend tracking across runs. Intended as a pre-ship gate inside `/soloship:shipthorough`.
|
|
156
|
+
- `/soloship:autoplan` — Routes to gstack `autoplan` to run the full plan-review gauntlet (CEO, design, engineering, DX) in a single pass with auto-decisions. Use when you want every review lens applied without stepping through them individually.
|
|
157
|
+
|
|
158
|
+
## Quick start
|
|
159
|
+
|
|
160
|
+
See the [Install](#install) section above for the two commands to install the plugin. Once installed, the daily flow inside any project is:
|
|
161
|
+
|
|
162
|
+
**New project:**
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
/soloship:bootstrap # set up the guardrails
|
|
166
|
+
/soloship:brainstorm → /soloship:plan → /soloship:implement
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Existing project:**
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
/soloship:audit # understand what's there first
|
|
173
|
+
/soloship:bootstrap # set up guardrails tailored to what audit found
|
|
174
|
+
/soloship:plan → /soloship:implement → /soloship:shipthorough
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Prefer an npm installer?
|
|
178
|
+
|
|
179
|
+
If you'd rather set up the project scaffolding outside Claude Code (for example, in a scripted environment or CI), the npm CLI does the same thing bootstrap does:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npx soloship init
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Most people should use `/soloship:bootstrap` — it's the supported path and it can tailor setup to audit findings.
|
|
186
|
+
|
|
187
|
+
## Design decisions
|
|
188
|
+
|
|
189
|
+
1. **Audit before bootstrap on existing projects.** Don't impose governance on a codebase you haven't understood yet.
|
|
190
|
+
2. **Design-first principle.** `/soloship:brainstorm` nudges you toward visual design before `/soloship:plan`. Design catches problems text can't.
|
|
191
|
+
3. **Hooks for enforcement, skills for intelligence.** Hooks are mechanical and fire automatically. Skills are guided and require judgment. Rules sit underneath both — they're always on, even when the skill forgets.
|
|
192
|
+
4. **npm installer + Claude Code plugin.** Installer handles one-time infrastructure. Skills handle daily workflow. Different jobs, different tools.
|
|
193
|
+
5. **Routers, not rewrites.** Where [Superpowers](https://github.com/anthropics/superpowers), [Compound Engineering](https://github.com/EveryInc/compound-engineering-plugin), or [gstack](https://github.com/garrytan/gstack) already do the job well, Soloship routes to them and adds enforcement gates, routing logic, and solo-operator defaults on top. When upstream skills improve, Soloship benefits automatically.
|
|
194
|
+
|
|
195
|
+
## Status
|
|
196
|
+
|
|
197
|
+
| Phase | Status | What it delivered |
|
|
198
|
+
|-------|--------|-------------------|
|
|
199
|
+
| 1-2 | Done | Cleanup + `npx soloship init` with stack detection |
|
|
200
|
+
| 3-4 | Done | `/audit` + `/bootstrap` skills |
|
|
201
|
+
| 5-6 | Done | 17 more skills (19 total) + 9 hooks + 4 rules |
|
|
202
|
+
| 7 | Not started | Safety floor hardening, surface simplification, CLAUDE.md governance |
|
|
203
|
+
| 8 | Not started | Graduation system, methodology documentation |
|
|
204
|
+
|
|
205
|
+
Phases 1-6 are shipped and usable today. Phases 7-8 were restructured after a 3-round adversarial review that identified rationalization traps in the original design. Phase 7 adds mechanical safety enforcement (Semgrep scanning, automated rollback, phone-a-friend triggers) and consolidates the 19 skills into 3-4 meta-workflows. Phase 8 adds a graduation system with calibrated thresholds that tell you when your project has outgrown solo mode.
|
|
206
|
+
|
|
207
|
+
## Prior art & influences
|
|
208
|
+
|
|
209
|
+
Soloship builds on top of four Claude Code skill ecosystems rather than replacing them:
|
|
210
|
+
|
|
211
|
+
[Compound Engineering](https://github.com/EveryInc/compound-engineering-plugin) — `/learn` uses CE's `workflows:compound` to create solution documents with structured frontmatter. The multi-agent pattern in CE informs how `/audit` and `/review` dispatch parallel investigation agents.
|
|
212
|
+
|
|
213
|
+
[Superpowers](https://github.com/anthropics/superpowers) — `/brainstorm` routes to `superpowers:brainstorming` for technical exploration. `/plan` routes to `superpowers:writing-plans`. `/implement` routes to `superpowers:subagent-driven-development` or `superpowers:dispatching-parallel-agents`. `/debug` routes to `superpowers:systematic-debugging`.
|
|
214
|
+
|
|
215
|
+
[gstack](https://github.com/garrytan/gstack) — `/qa` routes to gstack's QA skill. `/security` routes to `cso`. `/design-review` routes to gstack's design-review checklist. `/brainstorm` routes to `office-hours` for product questions. `/plan` routes to `plan-eng-review` for architectural work. `/review` routes to `plan-eng-review`, `plan-ceo-review`, and `plan-design-review` for plan reviews.
|
|
216
|
+
|
|
217
|
+
[intent-layer](https://github.com/crafter-station/skills/tree/main/context-engineering/intent-layer) (crafter-station/skills, built on [The Intent Layer](https://www.intent-systems.com/learn/intent-layer) by Tyler Brandt) — `/learn` Steps 4-5 adapt the concept of distributed per-directory `AGENTS.md` files for codebase navigation. Soloship's version is continuous (updates on every `/learn` pass, not one-shot), threshold-gated (3+ source files before creating), append-only with dated attribution, and scoped to solution-doc evidence rather than speculative. `/bootstrap` and `/cleanup` also maintain the AGENTS.md network.
|
|
218
|
+
|
|
219
|
+
[Impeccable](https://github.com/pbakaus/impeccable) — `/design-review` adds an AI slop detection pass inspired by Impeccable's design quality philosophy, checking for generic AI-generated visual, content, and layout patterns.
|
|
220
|
+
|
|
221
|
+
[Serena](https://github.com/oraios/serena) — symbol-level LSP code navigation. Optional. Worth adding once a codebase outgrows file-level tools; see Serena's README for install instructions.
|
|
222
|
+
|
|
223
|
+
The broader design traces back to a research pass across: Ousterhout on strategic vs tactical programming (you are the architect, the agent implements), Hickey on simple vs easy, Metz on dependency awareness and sizing rules, Meadows on leverage points in systems, the BCG "AI Brain Fry" finding that productivity drops past three tools, Kathy Sierra on the collapse zone (only automated process survives when things break), and the Codified Context paper that validated the CLAUDE.md + AGENTS.md + docs/ three-tier pattern.
|
|
224
|
+
|
|
225
|
+
## Repo layout
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
.claude-plugin/ # Plugin manifest (plugin.json, marketplace.json)
|
|
229
|
+
bin/soloship.js # CLI entry point
|
|
230
|
+
src/ # TypeScript source for the installer
|
|
231
|
+
cli.ts # Commander CLI definition
|
|
232
|
+
init.ts # Main init orchestration
|
|
233
|
+
detect.ts # Stack detection
|
|
234
|
+
scaffold.ts # Folder + doc creation
|
|
235
|
+
hooks.ts # Claude Code hook configuration
|
|
236
|
+
rules.ts # Workflow rule installation
|
|
237
|
+
ci.ts # GitHub Actions + architecture fitness
|
|
238
|
+
templates.ts # CLAUDE.md / AGENTS.md / CHANGELOG / SOLUTION_GUIDE generators
|
|
239
|
+
skills/ # Claude Code skills shipped by the plugin
|
|
240
|
+
audit/ autoplan/ bootstrap/ brainstorm/ checkpoint/ cleanup/
|
|
241
|
+
debug/ design-review/ health/ implement/ learn/ onboard/
|
|
242
|
+
plan/ qa/ review/ security/ shipfast/ shipthorough/ spec/
|
|
243
|
+
references/ # Shared checklists (a11y, code review, perf, security, testing)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT.
|
|
249
|
+
|
|
250
|
+
## A note to anyone reading this
|
|
251
|
+
|
|
252
|
+
Soloship is opinionated and unfinished. It's the working toolkit of one person who builds software through AI agents and is trying to do it responsibly. If you find it useful, great. If you think a decision is wrong, open an issue — the adversarial-review phase of this project already taught me that the things I'm most confident about are the things most likely to need a second pair of eyes.
|
package/bin/soloship.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifact Schema Contracts
|
|
3
|
+
*
|
|
4
|
+
* Every generated artifact gets:
|
|
5
|
+
* - Frontmatter with version, producer, timestamp, content hash, freshness TTL
|
|
6
|
+
* - Schema validation on production and consumption
|
|
7
|
+
* - Freshness checking — consumers warn when artifacts exceed TTL
|
|
8
|
+
*
|
|
9
|
+
* These contracts validate STRUCTURE and FRESHNESS, not semantic correctness.
|
|
10
|
+
* A structurally valid, fresh artifact may still be semantically wrong.
|
|
11
|
+
* That's an accepted risk — see the plan's Accepted Risks section.
|
|
12
|
+
*/
|
|
13
|
+
export type ArtifactType = "audit-report" | "audit-findings" | "plan" | "solution" | "agents-md" | "brainstorm" | "spec";
|
|
14
|
+
export declare function computeContentHash(content: string): string;
|
|
15
|
+
export interface ArtifactFrontmatter {
|
|
16
|
+
[key: string]: string | number | string[] | undefined;
|
|
17
|
+
date?: string;
|
|
18
|
+
producer?: string;
|
|
19
|
+
version?: string | number;
|
|
20
|
+
content_hash?: string;
|
|
21
|
+
ttl_days?: number;
|
|
22
|
+
status?: string;
|
|
23
|
+
title?: string;
|
|
24
|
+
category?: string;
|
|
25
|
+
components?: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Generate artifact frontmatter block.
|
|
29
|
+
* Embeds provenance (producer, timestamp), integrity (content hash), and freshness (TTL).
|
|
30
|
+
*/
|
|
31
|
+
export declare function generateFrontmatter(type: ArtifactType, fields: Record<string, string | number | string[]>, content: string): string;
|
|
32
|
+
export interface ValidationResult {
|
|
33
|
+
valid: boolean;
|
|
34
|
+
errors: string[];
|
|
35
|
+
warnings: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parse frontmatter from a markdown artifact.
|
|
39
|
+
* Returns null if no frontmatter block is found.
|
|
40
|
+
*
|
|
41
|
+
* Limitation: handles simple key: value pairs only. Multi-line YAML values
|
|
42
|
+
* (| or > operators) and quoted strings with newlines are not supported.
|
|
43
|
+
* This is sufficient for Soloship's generated frontmatter, which is always
|
|
44
|
+
* single-line key-value pairs.
|
|
45
|
+
*/
|
|
46
|
+
export declare function parseFrontmatter(content: string): ArtifactFrontmatter | null;
|
|
47
|
+
/**
|
|
48
|
+
* Validate an artifact against its schema contract.
|
|
49
|
+
* Checks: frontmatter presence, required fields, required sections, content hash integrity.
|
|
50
|
+
*/
|
|
51
|
+
export declare function validateArtifact(content: string, type: ArtifactType): ValidationResult;
|
|
52
|
+
export interface FreshnessResult {
|
|
53
|
+
fresh: boolean;
|
|
54
|
+
ageDays: number;
|
|
55
|
+
ttlDays: number;
|
|
56
|
+
message: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Check if an artifact is within its freshness TTL.
|
|
60
|
+
* Returns a plain-language result the non-coder can understand.
|
|
61
|
+
*/
|
|
62
|
+
export declare function checkFreshness(content: string, type: ArtifactType): FreshnessResult;
|
|
63
|
+
/**
|
|
64
|
+
* Validate an artifact file from disk.
|
|
65
|
+
* Combines schema validation and freshness checking.
|
|
66
|
+
*/
|
|
67
|
+
export declare function validateArtifactFile(filePath: string, type: ArtifactType): {
|
|
68
|
+
validation: ValidationResult;
|
|
69
|
+
freshness: FreshnessResult;
|
|
70
|
+
} | null;
|
|
71
|
+
/**
|
|
72
|
+
* Detect artifact type from file path.
|
|
73
|
+
* Returns null if the path doesn't match a known artifact pattern.
|
|
74
|
+
*/
|
|
75
|
+
export declare function detectArtifactType(filePath: string): ArtifactType | null;
|
|
76
|
+
/**
|
|
77
|
+
* Generate a freshness warning message suitable for systemMessage output.
|
|
78
|
+
* Used by consuming skills to warn when artifacts exceed TTL.
|
|
79
|
+
*/
|
|
80
|
+
export declare function formatFreshnessWarnings(artifacts: Array<{
|
|
81
|
+
path: string;
|
|
82
|
+
type: ArtifactType;
|
|
83
|
+
}>): string | null;
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
const SCHEMAS = {
|
|
4
|
+
"audit-report": {
|
|
5
|
+
requiredFields: ["date", "producer", "version"],
|
|
6
|
+
requiredSections: ["Architecture", "Quality"],
|
|
7
|
+
ttlDays: 30,
|
|
8
|
+
},
|
|
9
|
+
"audit-findings": {
|
|
10
|
+
requiredFields: ["date", "producer", "version"],
|
|
11
|
+
requiredSections: [],
|
|
12
|
+
ttlDays: 30,
|
|
13
|
+
},
|
|
14
|
+
plan: {
|
|
15
|
+
requiredFields: ["date", "version", "status"],
|
|
16
|
+
requiredSections: ["Key Decisions"],
|
|
17
|
+
ttlDays: 14,
|
|
18
|
+
},
|
|
19
|
+
solution: {
|
|
20
|
+
requiredFields: ["title", "date", "category", "components"],
|
|
21
|
+
requiredSections: ["Problem", "Root Cause", "Solution", "Prevention"],
|
|
22
|
+
ttlDays: 90,
|
|
23
|
+
},
|
|
24
|
+
"agents-md": {
|
|
25
|
+
requiredFields: [],
|
|
26
|
+
requiredSections: ["Scope", "Owns", "Contracts"],
|
|
27
|
+
ttlDays: 60,
|
|
28
|
+
},
|
|
29
|
+
brainstorm: {
|
|
30
|
+
requiredFields: ["date", "version"],
|
|
31
|
+
requiredSections: [],
|
|
32
|
+
ttlDays: 14,
|
|
33
|
+
},
|
|
34
|
+
spec: {
|
|
35
|
+
requiredFields: ["date", "version", "status"],
|
|
36
|
+
requiredSections: ["Acceptance Criteria"],
|
|
37
|
+
ttlDays: 14,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
// --- Content Hash ---
|
|
41
|
+
export function computeContentHash(content) {
|
|
42
|
+
// Trim to normalize: callers may pass body with or without leading/trailing
|
|
43
|
+
// whitespace, and body extraction from files may include separator newlines.
|
|
44
|
+
return createHash("sha256").update(content.trim()).digest("hex").substring(0, 12);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate artifact frontmatter block.
|
|
48
|
+
* Embeds provenance (producer, timestamp), integrity (content hash), and freshness (TTL).
|
|
49
|
+
*/
|
|
50
|
+
export function generateFrontmatter(type, fields, content) {
|
|
51
|
+
const schema = SCHEMAS[type];
|
|
52
|
+
const hash = computeContentHash(content);
|
|
53
|
+
const now = new Date().toISOString().split("T")[0];
|
|
54
|
+
const frontmatter = {
|
|
55
|
+
date: now,
|
|
56
|
+
producer: "soloship",
|
|
57
|
+
version: 1,
|
|
58
|
+
content_hash: hash,
|
|
59
|
+
ttl_days: schema.ttlDays,
|
|
60
|
+
...fields,
|
|
61
|
+
};
|
|
62
|
+
const lines = ["---"];
|
|
63
|
+
for (const [key, value] of Object.entries(frontmatter)) {
|
|
64
|
+
if (Array.isArray(value)) {
|
|
65
|
+
lines.push(`${key}: [${value.join(", ")}]`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
lines.push(`${key}: ${value}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
lines.push("---");
|
|
72
|
+
return lines.join("\n");
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Parse frontmatter from a markdown artifact.
|
|
76
|
+
* Returns null if no frontmatter block is found.
|
|
77
|
+
*
|
|
78
|
+
* Limitation: handles simple key: value pairs only. Multi-line YAML values
|
|
79
|
+
* (| or > operators) and quoted strings with newlines are not supported.
|
|
80
|
+
* This is sufficient for Soloship's generated frontmatter, which is always
|
|
81
|
+
* single-line key-value pairs.
|
|
82
|
+
*/
|
|
83
|
+
export function parseFrontmatter(content) {
|
|
84
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
85
|
+
if (!match)
|
|
86
|
+
return null;
|
|
87
|
+
const fields = {};
|
|
88
|
+
for (const line of match[1].split("\n")) {
|
|
89
|
+
const colonIdx = line.indexOf(":");
|
|
90
|
+
if (colonIdx === -1)
|
|
91
|
+
continue;
|
|
92
|
+
const key = line.substring(0, colonIdx).trim();
|
|
93
|
+
let value = line.substring(colonIdx + 1).trim();
|
|
94
|
+
// Parse arrays: [a, b, c]
|
|
95
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
96
|
+
fields[key] = value
|
|
97
|
+
.slice(1, -1)
|
|
98
|
+
.split(",")
|
|
99
|
+
.map((s) => s.trim());
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
fields[key] = value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return fields;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Validate an artifact against its schema contract.
|
|
109
|
+
* Checks: frontmatter presence, required fields, required sections, content hash integrity.
|
|
110
|
+
*/
|
|
111
|
+
export function validateArtifact(content, type) {
|
|
112
|
+
const schema = SCHEMAS[type];
|
|
113
|
+
const errors = [];
|
|
114
|
+
const warnings = [];
|
|
115
|
+
// Check frontmatter exists
|
|
116
|
+
const frontmatter = parseFrontmatter(content);
|
|
117
|
+
if (!frontmatter) {
|
|
118
|
+
errors.push("Missing frontmatter block (--- ... ---)");
|
|
119
|
+
return { valid: false, errors, warnings };
|
|
120
|
+
}
|
|
121
|
+
// Check required fields
|
|
122
|
+
for (const field of schema.requiredFields) {
|
|
123
|
+
if (!frontmatter[field]) {
|
|
124
|
+
errors.push(`Missing required frontmatter field: ${field}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Check content hash integrity
|
|
128
|
+
if (frontmatter.content_hash) {
|
|
129
|
+
const bodyContent = content.replace(/^---\n[\s\S]*?\n---\n*/, "");
|
|
130
|
+
const currentHash = computeContentHash(bodyContent);
|
|
131
|
+
if (currentHash !== frontmatter.content_hash) {
|
|
132
|
+
warnings.push(`Content hash mismatch: artifact may have been modified without updating the hash`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Check required sections (markdown headings)
|
|
136
|
+
for (const section of schema.requiredSections) {
|
|
137
|
+
const sectionPattern = new RegExp(`^#{1,3}\\s+.*${escapeRegex(section)}`, "mi");
|
|
138
|
+
if (!sectionPattern.test(content)) {
|
|
139
|
+
errors.push(`Missing required section: ${section}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Check if an artifact is within its freshness TTL.
|
|
146
|
+
* Returns a plain-language result the non-coder can understand.
|
|
147
|
+
*/
|
|
148
|
+
export function checkFreshness(content, type) {
|
|
149
|
+
const schema = SCHEMAS[type];
|
|
150
|
+
const frontmatter = parseFrontmatter(content);
|
|
151
|
+
if (!frontmatter?.date) {
|
|
152
|
+
return {
|
|
153
|
+
fresh: false,
|
|
154
|
+
ageDays: -1,
|
|
155
|
+
ttlDays: schema.ttlDays,
|
|
156
|
+
message: `Cannot check age: no date found. This type of document expires after ${schema.ttlDays} days.`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// Use ttl_days from frontmatter if present, otherwise schema default
|
|
160
|
+
const ttlDays = typeof frontmatter.ttl_days === "string"
|
|
161
|
+
? parseInt(frontmatter.ttl_days, 10)
|
|
162
|
+
: typeof frontmatter.ttl_days === "number"
|
|
163
|
+
? frontmatter.ttl_days
|
|
164
|
+
: schema.ttlDays;
|
|
165
|
+
const dateStr = String(frontmatter.date);
|
|
166
|
+
const artifactDate = new Date(dateStr);
|
|
167
|
+
const now = new Date();
|
|
168
|
+
const ageDays = Math.floor((now.getTime() - artifactDate.getTime()) / (1000 * 60 * 60 * 24));
|
|
169
|
+
if (ageDays > ttlDays) {
|
|
170
|
+
return {
|
|
171
|
+
fresh: false,
|
|
172
|
+
ageDays,
|
|
173
|
+
ttlDays,
|
|
174
|
+
message: `Out of date: ${ageDays} days old (expires after ${ttlDays} days). Re-run the command that created this to get a fresh version.`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
fresh: true,
|
|
179
|
+
ageDays,
|
|
180
|
+
ttlDays,
|
|
181
|
+
message: `Up to date: ${ageDays} days old (expires after ${ttlDays} days).`,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// --- File-Level Helpers ---
|
|
185
|
+
/**
|
|
186
|
+
* Validate an artifact file from disk.
|
|
187
|
+
* Combines schema validation and freshness checking.
|
|
188
|
+
*/
|
|
189
|
+
export function validateArtifactFile(filePath, type) {
|
|
190
|
+
if (!existsSync(filePath))
|
|
191
|
+
return null;
|
|
192
|
+
const content = readFileSync(filePath, "utf-8");
|
|
193
|
+
return {
|
|
194
|
+
validation: validateArtifact(content, type),
|
|
195
|
+
freshness: checkFreshness(content, type),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Detect artifact type from file path.
|
|
200
|
+
* Returns null if the path doesn't match a known artifact pattern.
|
|
201
|
+
*/
|
|
202
|
+
export function detectArtifactType(filePath) {
|
|
203
|
+
if (/docs\/audit\/AUDIT-.*\.md$/i.test(filePath))
|
|
204
|
+
return "audit-report";
|
|
205
|
+
if (/audit-findings\.json$/i.test(filePath))
|
|
206
|
+
return "audit-findings";
|
|
207
|
+
if (/docs\/plans\/.*\.md$/i.test(filePath))
|
|
208
|
+
return "plan";
|
|
209
|
+
if (/docs\/solutions\/.*\.md$/i.test(filePath))
|
|
210
|
+
return "solution";
|
|
211
|
+
if (/AGENTS\.md$/i.test(filePath))
|
|
212
|
+
return "agents-md";
|
|
213
|
+
if (/spec\.md$/i.test(filePath))
|
|
214
|
+
return "spec";
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Generate a freshness warning message suitable for systemMessage output.
|
|
219
|
+
* Used by consuming skills to warn when artifacts exceed TTL.
|
|
220
|
+
*/
|
|
221
|
+
export function formatFreshnessWarnings(artifacts) {
|
|
222
|
+
const staleWarnings = [];
|
|
223
|
+
for (const { path, type } of artifacts) {
|
|
224
|
+
if (!existsSync(path))
|
|
225
|
+
continue;
|
|
226
|
+
const content = readFileSync(path, "utf-8");
|
|
227
|
+
const freshness = checkFreshness(content, type);
|
|
228
|
+
if (!freshness.fresh) {
|
|
229
|
+
staleWarnings.push(` - ${path}: ${freshness.message}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (staleWarnings.length === 0)
|
|
233
|
+
return null;
|
|
234
|
+
return ("OUT OF DATE — These documents are older than their expiration:\n\n" +
|
|
235
|
+
staleWarnings.join("\n") +
|
|
236
|
+
"\n\nRe-run the commands that created them to get fresh versions before relying on their content.");
|
|
237
|
+
}
|
|
238
|
+
// --- Utility ---
|
|
239
|
+
function escapeRegex(s) {
|
|
240
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
241
|
+
}
|
package/dist/ci.d.ts
ADDED