A spec-driven harness
Architecture in.
Software out.
An open-source framework that turns architectural specs into working code.
$ uvx ossature
- api.spec · db.spec → ui.spec Spec DAG (UI depends on API & DB)
- Validate ✓ Check constraints
- Audit ✓ audit-report.md
- plan.toml T1: api · T2: db → T3: ui
- Build Tasks in dependency order
- api.ts · db.ts · ui.ts Output files
From Spec to Software
Building Qoizig — a QOI image codec in Zig, from a single spec file to a working encoder and decoder, generated in 9 tasks.
$ ossature init creates the project config.
Set the output language, pick your LLM model, then
$ ossature new QOI_CODEC scaffolds a blank spec.Write the spec
Describe what the module does in a .smd file —
what it accepts, what it returns, and every error case.
This spec defines the QOI header structure, the pixel hash
function, and both the encode and decode commands.
Run ossature validate to check structure.
# Qoizig
@id: QOI_CODEC
@status: draft
@priority: high
@depends: []
## Overview
A high-performance, zero-dependency command-line tool
and library implemented in Zig for the QOI (Quite OK
Image) format.
## Requirements
### QOI Format Fundamentals
**Header Structure:**
- `char[4]` magic: "qoif"
- `u32` width: image width in pixels (BE)
- `u32` height: image height in pixels (BE)
- `u8` channels: 3 = RGB, 4 = RGBA
- `u8` colorspace: 0 = sRGB, 1 = linear
…
### Encode Command (`qoizig encode`)
**Accepts:**
- `input` (positional, required): Path to source file
- `output` (positional, required): Path for QOI output
**Errors:**
- Input file not found -> print error and exit code 1
- Invalid PPM/PAM header -> print error and exit code 1
…Audit catches the gaps
Before any code is written, ossature audit sends
your specs to an LLM for review. Here it found that
the encode command's examples show two positional arguments,
but only one was documented. You fix the spec, re-run audit,
and move on only when it's clean.
### WARNING: Encode Command
The encode command CLI example shows two positional
arguments (input and output path), but the requirement
only specifies one positional argument.
**Suggestion:** Add `output` (positional) to the
Accepts list for the encode command, and clarify
the default behavior if omitted.Review the plan
The audit produces a build plan — a topologically ordered list of tasks with dependency tracking. Each task generates 1–3 files and includes a verification command. You review and edit this before anything gets built.
# …tasks 001–002: scaffold, types…
[[task]]
id = "003"
spec = "QOI_CODEC"
title = "QOI Encoder Implementation"
outputs = ["src/encoder.zig"]
depends_on = ["001", "002"]
verify = "zig build --summary all"
[[task]]
id = "004"
spec = "QOI_CODEC"
title = "QOI Decoder Implementation"
outputs = ["src/decoder.zig"]
depends_on = ["001", "002"]
verify = "zig build --summary all"
# …tasks 005–009: tests, CLI, integration…Build generates code
Each task gets a narrow context window — only the spec sections,
types, and source files it needs. The encoder task sees the QOI
format spec, the types module, and the build config. Nothing else.
After generation, zig build verifies each step.
/// Encode raw pixel data into a complete QOI byte stream.
pub fn encode(
allocator: std.mem.Allocator,
pixels: []const u8,
width: u32,
height: u32,
channels: Channels,
colorspace: Colorspace,
) error{ InvalidPixelDataLength, OutOfMemory }![]u8 {
// …validation, buffer allocation…
// Write header
const header = QoiHeader{
.width = width,
.height = height,
.channels = channels,
.colorspace = colorspace,
};
const header_bytes = header.encode();
@memcpy(output[pos .. pos + qoi.QOI_HEADER_SIZE], &header_bytes);
pos += qoi.QOI_HEADER_SIZE;
// Encoder state
var index: [qoi.QOI_INDEX_SIZE]Pixel = // …
var prev_px: Pixel = Pixel.default;
var run: u8 = 0;
// …chunk compression, end marker…
}Explore complete projects
Each example includes the specs, the full build plan, every prompt sent to the LLM, and the generated code — so you can trace every decision from spec to output.
Browse examples on GitHub →Every decision is yours.
Spec dependency graph
Specs form a DAG. Build ordering, interface contracts, and cascade invalidation all derive from it. Change one spec and only its dependents rebuild.
Narrow context per task
Each task gets ~2–5K tokens — only the spec sections, types, and source files it actually needs. Focused context produces better output than dumping everything.
Incremental builds
Every input is SHA-256 checksummed. Only rebuild what changed. Cascades stop at interface boundaries. Resume from any task.
Full audit trail
Every prompt sent, every response received, every file written with checksums. When something breaks at task 14, open the directory and see exactly what happened.