Symbolon spec pack format, v1¶
A spec pack is a product contract packaged for building: what the product is for, what may be assumed about the world, and the decisions a builder must keep, each tied to the checks that pin it down. Its components are ordinary capability contracts (CONTRACT_FORMAT.md).
A pack is meant to be minimal. AI builders fill gaps well, so a pack does not spell out what any good builder would do anyway. It holds the points where good builders would choose differently and the publisher would reject one choice, the facts about the world no builder can infer, and a check for each. See design v0.5, section 4.
What a pack specifies¶
What the product does at the surfaces people use (API, file formats, command line, results), not how it is built. Drive the product as a user does rather than through internal seams; check properties rather than exact output unless the exact output is the product; leave codebase-only choices to the codebase's own guidance.
Layout¶
packs/<namespace>/<product>/versions/<version>/
symbolon-pack.toml manifest: pack id, version, license, component digests (required)
BRIEF.md purpose, non-goals, priorities, who resolves gaps (required)
PRODUCT.md the whole product a build delivers (optional; makes it a product pack)
obligations.toml the decisions a build must keep (required)
assumptions/*.toml what must hold about the world, one file each
components/<name>/versions/<version>/ capability contracts
AGENTS.md short guide for coding agents
Selling: [listing]¶
An optional table in symbolon-pack.toml prices the pack:
See Pack registry.
BRIEF.md¶
Prose for people and agents. It must have these headings (any level, any case):
- Non-goals: what the product deliberately does not do.
- Priorities: the order in which goals win when they conflict.
- Who resolves gaps: who answers questions the pack does not settle.
PRODUCT.md¶
The components are the parts of a product whose behaviour must come out exactly;
they are not the product. A coding agent asked to build the product from components
alone invents everything around them (the first lightkone field test built a demo
page, not the app). PRODUCT.md says what a build of the whole product is, for
people and agents. It must have these headings (any level, any case):
- Shape: what kind of program it is, where it runs, what it needs, and the choices users would notice (a static web app with no server, a CLI, a service).
- Surfaces: every screen, command, endpoint and file users touch, one line each.
- Flows: the main things users do, each as steps and the outcome they see, naming the components each step uses.
Optional headings such as Interfaces (outside services, plugin or storage
interfaces) and Order (what to build first when a build cannot do it all)
help. Like the rest of the pack it is minimal: what a good builder could not
guess, not layout or styling. Requirements in it that a build must keep and no
check covers yet can be unchecked obligations.
A pack with PRODUCT.md is a product pack: its build is the product, with the
components as its core, and it is done when every flow works and every component
passes. A pack without it is a component library: its build is the components.
symbola replicate always builds the components only, so it costs the same either way.
assumptions/<name>.toml¶
id = "K-single-writer" # K-<lowercase-name>
statement = "At most one client writes a given library at a time."
basis = "Sync is manual and libraries are personal."
monitor = "none" # how a deployment can watch it, or "none"
Assumptions tell builders what they need not handle, and they scope the evidence: a build that passes the pack is correct under these assumptions.
obligations.toml¶
[[obligation]]
id = "search.year-last-wins" # dot-separated lowercase words
statement = "Only the last year: term in a query applies, whatever its form."
status = "decided" # decided | default | open
kind = "behaviour" # behaviour | constraint | security | audit (default behaviour)
source = "replication" # extract | oracle | replication | counterexample | publisher
reason = "..." # required when kind = "constraint"
exactness = "exact" # exact | statistical (default exact)
assumes = ["K-..."] # optional
checks = ["search-query#test_only_the_last_year_filter_counts", "search-query#example:40"]
unchecked = "" # see "Unchecked obligations" below
| Status | Meaning | Checks |
|---|---|---|
decided |
Required | At least one |
default |
Chosen by the publisher; a fork may change it if it says so | At least one |
open |
Deliberately undecided; builds may differ | None, since a check would decide it |
Unchecked obligations¶
A required behaviour no example or property can express yet is decided (or
default) with no checks and an unchecked reason naming the check it would need,
such as unchecked = "a session check: run to t1 then t2, compared with one run to t2".
Builders treat it as required; pack validate counts it as debt and fails above
[pack] max_unchecked (a share of decided and default obligations, default 0.1).
A check is <component>#example:<line> (a 1-based line of that component's
examples.jsonl) or <component>#<test function> (a property in its
properties.py). Obligation ids are the single id scheme for tracing checks to
requirements; a standalone contract can adopt the same [[obligation]] table later.
source records where the obligation's current binding came from. The share that
came from replication (builders disagreed) rather than extract is a measure of
how much a pack needed to say beyond the obvious, so an obligation that extraction
left open and replication then decided counts as replication.
Exact and statistical obligations¶
exactness says how an obligation constrains outputs, independently of its status:
| Exactness | Meaning | Extra fields |
|---|---|---|
exact |
Every output must satisfy it; one violating output fails it | None |
statistical |
The output distribution must satisfy it, for software that is random by design, such as a summarizer that calls a model | samples (runs per check), alpha (accepted false-alarm rate), tolerance (its share of the disagreement budget) |
An open obligation is the free case: it constrains nothing, so it takes no
exactness. The terms follow the kit paper (The Probabilistic Minimal Reproduction
Kit, section 5.4). The runner does not yet repeat statistical checks; until it
does, the fields record what a check must do.
What symbola pack validate checks¶
symbolon-pack.toml,BRIEF.mdandobligations.tomlexist.- Every component listed in the manifest is present with the same digest, and none is unlisted.
BRIEF.mdhas the three required sections, andPRODUCT.md, if present, has its three.- Every assumption file is well-formed, with a unique id.
- Every obligation is well-formed, with a unique id.
- Every
decidedordefaultobligation has checks or anuncheckedreason (not both), everyopenone has neither, every constraint has a reason, every check exists, and every assumption it names exists. - A
statisticalobligation is notopenand givessamples,alphaandtolerance; an exact one gives none of them. - Unchecked obligations are at most
max_uncheckedof the decided and default ones.
It then reports obligations by status, source and exactness, assumptions and how many are
monitored, and how many of the components' checks trace to an obligation. It does
not run contract code; use symbola validate on each component for that.