Spec defines task contracts, acceptance criteria, expected outputs, and agent-readable work instructions for AI-native development.
A .spec.yml file turns human instructions into a clear, reviewable task contract.
Prioritize copyable examples over tests: examples should model the most token-efficient idioms we want agents to imitate.
Spec 1.0 is stable for local development, CI, monorepos, and regulated automation environments where the verification suite is run against the target runtime and trust boundaries. It includes path-boundary checks, symlink escape protection, safe-write controls, strict validation mode, generated command inventory checks, completion parity checks, fuzz coverage, benchmark gates, and release quality gates.
No CLI can be universally production-ready without being validated against the target organization's runtime, CI runner, trust boundaries, and release process. For enterprise adoption, run the verification suite in your environment, pin KUJO_BIN, enable SPEC_SAFE_WRITE=on, and set SPEC_TEMPLATE_SOURCE_POLICY=project-only in CI.
Most agent failures start with vague requirements, not code generation.
Spec gives Kujo a native task-contract format before implementation starts:
- Goal — the primary objective
- Background — context and motivation
- Scope — what's in and out of scope
- Acceptance criteria — verifiable conditions for completion
- Eval requirements — automated checks that validate outcomes
- Risks — known risks with severity and mitigations
- Dependencies — what must be available before starting
- Review expectations — how the work will be reviewed
- Human approval points — where humans must sign off
export PATH="/path/to/kujo-spec/scripts:$PATH"
mkdir -p specs
cat > specs/dark-mode.spec.yml <<'YAML'
name: "Add dark mode"
goal: "Add a theme toggle and persist the selected color scheme."
priority: "medium"
acceptance_criteria:
- "Users can switch between light and dark themes"
- "The selected theme persists after reload"
YAML
spec validate specs/dark-mode.spec.yml
spec render specs/dark-mode.spec.yml
spec export-agent-context specs/dark-mode.spec.ymlExpected validation output:
Validating: specs/dark-mode.spec.yml
PASS: Spec is valid
- Kujo language runtime v0.1.0+ (set
KUJO_BINenv var or ensure it's at the default path) - Python 3 (for YAML/TOML parsing; JSON specs work without it)
- No API keys or external services needed
The authoritative command inventory is generated from spec help:
docs/COMMAND_INVENTORY.md
Regenerate it after command-surface changes:
bash scripts/generate_command_inventory.sh writeVersion note:
- Use
spec versionfor version output. --versionis not implemented.
| Option | Description |
|---|---|
--format yaml|toml|json |
Spec file format (default: yaml) |
--output <path> |
Output file path |
--name <name> |
Spec name (for init) |
--from <source> |
Import spec from external source (init) |
--strict-template-source |
Restrict init template lookup to project templates only |
--unsafe-write |
Allow writes outside project root when safe-write mode is active |
--payload-format agent|dispatch |
Envelope payload format for spec export --format envelope |
--json |
Machine-readable JSON output (validate, version, info, list) |
--quiet |
Suppress output on success (validate) |
--strict |
Treat warnings as errors (validate) |
--max-files <n> |
Limit spec ci scan count for large repos |
--fail-fast |
Stop spec ci on first failure |
--jobs <n> |
Run spec ci validation in parallel workers |
Safe-write mode:
SPEC_SAFE_WRITE=auto|on|offcontrols output-path restrictions.auto(default) enables restrictions forspec cicommand context.- Use
--unsafe-writeto explicitly override per command.
Template source policy:
SPEC_TEMPLATE_SOURCE_POLICY=allow-home|project-onlycontrols whetherspec init --from template:<name>can load templates from$HOME/.config/kujo-spec/templates.- Use
--strict-template-sourcefor one-off project-only resolution.
CI scaling controls:
spec ci --max-files <n>bounds scan time in very large repositories.spec ci --fail-fastexits early on first invalid spec to shorten feedback loops.spec ci --jobs <n>enables deterministic parallel validation for enterprise-scale trees.- Flags can be combined with any argument order, for example:
spec ci --format json ./specs --max-files 200 --jobs 4.
| Source | Example | Description |
|---|---|---|
- |
cat spec.json | spec init --from - |
Read JSON spec from stdin |
json:<file> |
spec init --from json:input.json |
Import from a JSON file |
template:<name> |
spec init --from template:feature |
Use a template from specs/templates/ |
github:<o/r/n> |
spec init --from github:kujolang/spec/1 |
Fetch a GitHub issue (requires gh CLI) |
Use spec export --format envelope when automation needs payload + metadata in one JSON object.
Spec pairs well with Eval when you want the work to be verifiable, not just described.
Metadata fields:
source_fileschema_versionchecksum_sha256generated_atpayload_format
Example:
spec export spec.yml --format envelope --payload-format dispatch --output artifacts/spec.envelope.jsonSpec supports three formats:
name: "Add user avatar upload"
goal: "Implement avatar upload endpoint for user profiles."
version: "0.1.0"
background: "Users have requested this feature since Q1."
scope: "POST /api/users/:id/avatar with JPEG/PNG support up to 5MB."
non_goals:
- "Animated GIF support"
- "Avatar cropping UI"
acceptance_criteria:
- "POST returns 201 with avatar URL"
- "Uploads >5MB return 413"
priority: "high"
tags:
- "api"
- "users"{
"name": "Add user avatar upload",
"goal": "Implement avatar upload endpoint for user profiles.",
"version": "0.1.0",
"priority": "high",
"tags": ["api", "users"]
}name = "Add user avatar upload"
goal = "Implement avatar upload endpoint for user profiles."
version = "0.1.0"
priority = "high"
tags = ["api", "users"]The full JSON Schema is at schema/spec.schema.json.
| Field | Type | Description |
|---|---|---|
name |
string | Short, human-readable task name (max 200 chars) |
goal |
string | Primary objective (max 5000 chars) |
| Field | Type | Description |
|---|---|---|
version |
string | Spec version (default: "0.1.0") |
background |
string | Context and motivation |
scope |
string | What is in scope |
non_goals |
string[] | What is explicitly out of scope |
relevant_systems |
string[] | Systems relevant to this task |
likely_files |
string[] | Files likely to be created/modified |
acceptance_criteria |
string[] | Verifiable completion conditions |
eval_requirements |
object[] | Eval hooks (description, check_type, params) |
risks |
object[] | Risks with risk, mitigation, severity |
dependencies |
string[] | Required dependencies |
review_expectations |
string[] | Review requirements |
human_approval_points |
string[] | Where human sign-off is needed |
estimated_effort |
string | Effort estimate (e.g., "3 days") |
priority |
string | critical / high / medium / low |
assignee |
string | Who is assigned |
tags |
string[] | Categorization tags |
The export-agent-context command produces a structured prompt for AI agents:
## Task: Add user avatar upload
### Goal
Implement avatar upload endpoint for user profiles.
### Acceptance Criteria (Definition of Done)
Your work is complete ONLY when ALL of these are true:
1. POST returns 201 with avatar URL
2. Uploads >5MB return 413
### Priority
**high** priority
---
**Instructions:** Read context before starting. Understand goal and scope.
Verify acceptance criteria. Stop at approval points.
Use --format dispatch to export a Dispatch-compatible work unit summary.
Spec is designed to integrate with the Kujo ecosystem:
- kujo-eval — eval requirements map to eval checks
- kujo-dispatch — specs export as dispatch work units
- kujo-scout — specs become scoutable work items
- kujo-mcp — agent tools can consume spec context
- YAML parsing: complex YAML features (anchors, multi-document, tags) are not supported. Use the subset documented above.
- TOML parsing: basic key=value only. Nested tables and arrays of tables are not yet supported.
- Kujo runtime: The
specCLI uses a shell script wrapper for YAML/TOML parsing. The Kujo validate/render/export modules use JSON internally. Cross-module imports (from src.common import ...) are supported as of Kujo v1.0.0+. - The
KUJO_BINenvironment variable must point to the Kujo language runtime (not the Python linter). - File size limit: 1MB maximum per spec file. Larger files are rejected before parsing.
- When
SPEC_SAFE_WRITEis enabled, output paths are restricted to the current project root unless--unsafe-writeis provided. spec changelogdefaults to the latest tag when present and falls back to the repository root commit when no tags exist.
| Component | Supported | Notes |
|---|---|---|
| Shell | Bash 3.2+ | macOS default Bash is supported |
| Kujo runtime | Kujo language runtime | Set KUJO_BIN if runtime is not on PATH |
| Python | Python 3.8+ | Required for YAML/TOML conversion helpers |
| YAML | pyyaml preferred |
Fallback parser supports documented subset |
| TOML | stdlib tomllib or fallback parser |
Nested tables are currently out of scope |
Runtime source lives in src/, CLI orchestration lives in scripts/, and generated/user-facing documentation lives in docs/. The root intentionally keeps package, release, policy, and ecosystem control files because external tooling expects them there.
Keep these root files in place unless the corresponding release or package tooling is updated first:
VERSIONRUNTIME_VERSIONkennel.tomlkujo.tomlpackage.jsonDockerfileLICENSESECURITY.mdCONTRIBUTING.mdCHANGELOG.md
There are no duplicate root-level Kujo source modules to move into src/; the active Kujo modules are src/common.kujo, src/convert.kujo, src/export.kujo, src/render.kujo, and src/validate.kujo.
tests/benchmark.sh uses a stable, single-pass methodology:
- Generate
NYAML specs with valid minimal content. - Time one
spec validate-allrun over that directory. - Compare wall-clock runtime to an environment budget.
- Enforce trend budget using
ci_runtime_msfrom machine-readable benchmark summary output.
Supported benchmark profiles:
| Profile | Default count | Default budget |
|---|---|---|
local |
100 | 30s |
ci-linux |
30 | 60s |
ci-macos |
30 | 90s |
stress |
300 | 120s |
Examples:
# Local developer baseline
bash tests/benchmark.sh
# CI Linux profile (same defaults used by release gates)
SPEC_BENCH_PROFILE=ci-linux bash tests/benchmark.sh
# Explicit override
bash tests/benchmark.sh 100 60 ci-linux# Pin Kujo runtime for deterministic local runs
export KUJO_BIN=/path/to/kujo/target/release/kujo
# Run test suite
bash tests/run_tests.sh
# Performance benchmark
bash tests/benchmark.sh
# Release quality gates
bash scripts/release_quality_gates.sh
# Supply chain policy check
bash scripts/supply_chain_policy_check.sh
# Doc command parity check
bash scripts/verify_docs_command_parity.sh
# Shell completion parity check
bash scripts/verify_completion_parity.sh
# Runtime parity check
bash scripts/verify_test_runtime_parity.shIf KUJO_BIN is unset or points to the wrong binary, validation/render/export tests can fail with empty output.
docs/ENTERPRISE_USAGE_GUIDE.mddocs/RELEASE_NOTES_TEMPLATE.md
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Validation failure or usage error |
MIT