lava-harness
Lava
The code is lava. Specs are where problems get solved — code is just the output.
A Spec-Driven Development framework built on top of OpenSpec. Drop it into any project and your AI coding agent gets a full workflow: think → spec → design → implement — with a human checkpoint between every step.
What is this?
Most AI workflows go straight to code. This one doesn't.
Lava enforces a discipline: before any line of code gets written, there's a proposal (what & why), delta specs (behavior), a design (how), and a task breakdown (what steps). The AI generates each artifact one at a time. You review and approve. Only then does implementation start.
idea → /lava:new → proposal ──[you review]──▶ /lava:continue
│
specs ◀────────────────┘
│
[you review]
│
▼
/lava:continue
│
design ◀─────────── technical plan
│
[you review]
│
▼
/lava:continue
│
tasks ◀─────────── implementation plan
│
[you review]
│
▼
/lava:apply ──────▶ code
│
[manual QA]
│
/lava:feedback ─┘ (if QA finds issues)
The human is the checkpoint between every artifact. Not a rubber stamp — an actual review moment where you shape direction before the AI runs.
Setup
1. Install OpenSpec CLI
npm install -g @fission-ai/openspec
Lava's workflow commands (/lava:new, /lava:continue, /lava:apply, etc.) depend on the OpenSpec CLI to manage changes and artifacts.
2. Add Lava to your project
npx lava-harness init
Copies .claude/ and .opencode/ into your project. Smart copy behavior:
- Workflow files (agents, commands,
openspec-*skills) — always written, always up to date - Capability skill (
core/capabilities) — copied only if missing, because projects may customize capability strategy - Your skill files (
core/,ui/) — only copied if they don't exist yet, never overwritten - OpenCode skills (
.opencode/skills) — not created when.claude/skillsis the canonical source, unless already present or explicitly requested settings.json— only copied if not present; comes pre-configured with OpenSpec permissions
If OpenSpec isn't installed, the CLI will warn you.
To overwrite existing framework files (e.g. when upgrading):
npx lava-harness init --force
To also install .opencode/skills in a project that uses them as a separate canonical skill source:
npx lava-harness init --with-opencode-skills
3. Run setup inside Claude Code
/lava:setup
The agent reads your AGENTS.md if you have one, asks how capabilities should be organized, then explores the codebase to infer tech stack, conventions, and existing domains. Generates all skill files with real content and upserts Lava-managed sections in your CLAUDE.md. No duplicate setup blocks.
Commands
| Command | What it does |
|---|---|
/lava:setup |
One-time setup — infers project context and generates skill files |
/lava:add-skill <name> |
Creates a new skill (core, ui, or domain) from existing code |
/lava:refresh-skills |
Detects stale skills via git history and refreshes them |
/lava:refactor-skills |
Migrates existing skills to current structure (one-time) |
/lava:explore |
Thinking partner before starting a change |
/lava:new <change> |
Full pipeline — spec author writes all artifacts to files, stops for review |
/lava:quick <change> |
Fast pipeline — skips proposal, specs + design + tasks, stops for review |
/lava:continue |
Signal that review is done — leader advances to next phase |
/lava:apply |
Force implementation phase (artifacts already approved) |
/lava:feedback |
Capture manual QA feedback and re-run implementation/review |
/lava:amend |
Amend specs/design/tasks when QA shows the plan was wrong |
/lava:archive |
Closes and archives a completed change |
/lava:propose |
Fast-forward — all artifacts in one shot, no checkpoints |
The Skill System
The AI reads your project context before generating every artifact. Context lives in CLAUDE.md — the single source of truth.
CLAUDE.md
├── Core skills → syntax conventions, folder structure, patterns
├── UI skills → component library, design system, visual conventions
└── Domain skills → one skill per feature domain
Each skill is a markdown file the AI reads to understand how your project works — not just "what exists" but also "how we do things here" and "what not to do."
.claude/skills/
core/
syntax/SKILL.md ← TypeScript conventions, naming, patterns
structure/SKILL.md ← Folder layout, module boundaries
capabilities/SKILL.md ← OpenSpec capability naming strategy
ui/
components/SKILL.md ← Reusable component library
design-system/SKILL.md ← Tokens, spacing, typography
domain/
auth/
SKILL.md ← Auth flow, JWT, session patterns
references/
types.md ← Detailed type definitions
payments/
SKILL.md ← Stripe integration, checkout flow
Artifact policy — what gets loaded when generating each artifact:
| Artifact | Core | UI | Domain |
|---|---|---|---|
| Proposal | — | — | relevant |
| Specs | capabilities | if UI | relevant |
| Design | always | if UI | relevant |
| Tasks | structure | — | relevant |
Relevance is semantic, not keyword matching. The AI reads skill descriptions in CLAUDE.md and decides what to load for the change at hand.
Capability policy
OpenSpec stores canonical behavior by capability under openspec/specs/<capability>/spec.md. Lava asks during /lava:setup how your project wants to divide capabilities:
frontend-feature— user-facing features, screens, or flowsbackend-domain— domains, bounded contexts, or business resourcesfullstack-product— product behavior domains spanning UI, API, and persistencecustom— your own project-specific rule
The decision is written to CLAUDE.md under ## Capability Policy, and core/capabilities/SKILL.md teaches spec_author to reuse stable capabilities instead of naming specs after one-off changes.
/lava:setup updates Lava-managed sections by heading instead of appending duplicate blocks. Managed sections are ## Skills, ## Artifact Policy, ## Capability Policy, and ## Workflow. Manual content inside those sections should be preserved while missing Lava rows or commands are added in place.
Adding skills
/lava:add-skill works for any category. The command infers the right one from the name — or asks if it's not obvious:
/lava:add-skill syntax # → core (inferred from name)
/lava:add-skill buttons # → ui (inferred from name)
/lava:add-skill auth # → domain (inferred from name)
/lava:add-skill payments domain # → domain (explicit)
/lava:add-skill testing core # → core (explicit)
The agent explores the relevant code, generates the skill with real content, and registers it in CLAUDE.md under the right section.
Skills keep SKILL.md under 500 lines — detailed reference material lives in references/ and gets loaded on demand.
AGENTS.md support
If your project has an AGENTS.md, /lava:setup reads it first and uses it as the primary source of project context. Less code exploration, more accurate skills — the AI trusts what you already documented.
Lava never modifies AGENTS.md. Read only.
A typical workflow
# 1. Explore the problem space
/lava:explore
# 2. Start a new change
/lava:new add-checkout-flow
# → AI reads relevant skills (payments, ui/components) from CLAUDE.md
# → AI generates proposal.md, stops
# → You read it, tweak it, approve
# 3. Generate the design
/lava:continue
# → AI reads proposal + core + UI skills
# → AI generates design.md, stops
# → You review the technical approach
# 4. Generate the tasks
/lava:continue
# → AI generates tasks.md broken into implementable steps, stops
# → You confirm the task breakdown
# 5. Implement
/lava:apply
# 6. Close it out
/lava:archive
Passing a Prompt
/lava:new accepts a change name, a free-form prompt, or both. The more context you give it, the less the agent has to infer from the name alone.
Name only:
/lava:new edit-notes
Free-form prompt only:
/lava:new "allow users to edit the title and body of an existing note from the CLI"
Name plus prompt:
/lava:new edit-notes allow users to edit the title and body of an existing note from the CLI
Use --draft-lang es when you want review drafts in Spanish. Keep the flag at the end so Lava can remove it cleanly before using the prompt as context:
/lava:new edit-notes allow users to edit the title and body of an existing note from the CLI --draft-lang es
This creates Spanish review drafts first, then Lava normalizes the artifacts back to English before implementation or archive. English remains the canonical language for final specs.
Project structure
your-project/
├── AGENTS.md ← Your existing project context (read by Lava, never modified)
├── CLAUDE.md ← Lava skills manifest + policies (upserted by /lava:setup)
├── .claude/
│ ├── commands/lava/ ← Slash commands
│ └── skills/
│ ├── core/ ← Technical conventions
│ ├── ui/ ← UI patterns
│ ├── domain/ ← Feature domain context
│ └── openspec-*/ ← Workflow skill definitions
├── .opencode/ ← OpenCode equivalents
└── openspec/
├── changes/ ← Active and archived changes
└── specs/ ← Project-level specs (OpenSpec native)
Philosophy
Specs are the product. A well-written spec is a decision record, a communication artifact, and an implementation contract — all at once. Code that comes out the other end is a consequence of good spec work, not the goal itself.
The AI is a collaborator in the spec process, not just a code generator. It brings context (existing patterns, domain knowledge, technical constraints) into every artifact it generates. You bring judgment, product sense, and the final say.
The checkpoint is the feature. Pausing between artifacts isn't overhead — it's where you actually think about whether you're building the right thing before it becomes code that has to be maintained.
Built on OpenSpec by Fission-AI.