Literate AI

Repository documentation

Source to specification

The litai spec workflow turns existing source into a reviewable OpenSpec draft. It is an inverse authoring workflow: source observations are evidence, not automatic authority.

Safety model

Both derivation modes inventory source without importing or executing it. Instruction-like text found in source remains untrusted evidence and cannot select skills, grant review authority, or enable execution. Unsigned source may be analyzed, but its result is quarantined and cannot be accepted.

The default static translator is deterministic, local, and deliberately shallow. It is useful for safe inventory, trust-envelope, review, and conformance exercises. The coding-cli translator is unavailable. Model-backed inverse translation that required graph evidence is not part of the product; use the static translator. The static translator inventories an inert temporary mirror of only admitted UTF-8 source, test, configuration, and documentation files. It requires explicit source-egress consent. Sensitive, binary, generated, minified, and oversized content never enters that mirror or prompt.

The built-in reviewed skill set covers architecture, public API, behavior and state, operations, security, and tests. Inert inventory also selects separate, exact Python, C++, Rust, and JavaScript/TypeScript translators when those languages are present. Each translator produces reviewable language-Flavor evidence; source text cannot select or rewrite the translator:

litai spec skills

For a case descriptor inside a project, the workflow loads the source-to-specification/ subcatalog from every skill_roots entry declared in literate.project.json. Differently named and multiple roots work; a nearby undeclared skills/ directory has no authority. --skills-root (--skills is an alias) selects an explicit catalog for case-driven conformance work. Arbitrary-source classification accepts only exact reviewed built-in skill identities, including when an explicit root is supplied.

flowchart LR
    S[Exact source snapshot] --> C[Classify and redact]
    C --> M[Inert temporary mirror]
    M --> G[Source inventory and symbol queries]
    G --> P{Canonical byte-bounded batches per language}
    K[Exact reviewed common + language skill pins] --> P
    P --> A[Selected coding CLI]
    A --> J[Complete prompt and response journal]
    A --> O[Evidence-bound observations]
    O --> B[Base OpenSpec + Flavor drafts]
    J --> B
    B --> R[Human review and signed acceptance]

1. Attest exact source

Keep the local bootstrap key and generated envelopes outside the source tree:

head -c 32 /dev/urandom > local-source.key
litai spec attest path/to/source \
  --signer local-user \
  --machine local-host \
  --key local-source.key > attestation.json

This HMAC flow is a local bootstrap mechanism, not a replacement for organizational PKI or signed release provenance.

2. Derive and inspect

litai spec derive path/to/source \
  --attestation attestation.json \
  --trust-key local-source.key > bundle.json
litai spec coverage bundle.json

To perform semantic translation through the selected coding agent:

litai spec derive path/to/source \
  --translator coding-cli \
  --allow-model-egress \
  --attestation attestation.json \
  --trust-key local-source.key > bundle.json

CODING_CLI may select codex, claude, cursor-agent, or opencode; otherwise the first available command in that order is used. --model MODEL pins a model for every inverse language call. Before an OpenCode inverse call, the exact executable must pass LitAI's bounded, prompt-free --pure run --help capability probe; incompatible releases fail before source evidence or a prompt can leave the process. --model-evidence-byte-budget N sets the positive UTF-8 evidence-byte ceiling for each call; it defaults to 262,144. An individual evidence record above the ceiling is an explicit error, not a truncation. For an npm installation, the command is only a package locator: Literate AI bypasses its scripts and executes the bundled native Node as the configured runtime. Index evidence binds those direct inputs; complete reachable package-graph evidence belongs to dependency/SBOM observation, not to the index executable identity alone. Omit --model to use the selected CLI's configured default. Missing or expired login state is reported as an explicit authentication prerequisite.

The bundle includes the exact source inventory, attributed observations, provider-valid draft artifacts, a coverage map, an uncertainty ledger, skill-stage provenance, proposed Flavor drafts, and security metadata. Model mode additionally records runtime, executable and frozen-database identities, exact counts and queries, plus the complete coding-CLI command, prompt, response, stdout/stderr, isolation claims, selected skills, model, egress policy, batch plan, and exact batch membership for every language call. Acceptance keeps that versioned translation record in a content-addressed provenance/source-promotion/ directory; it does not keep generated application source. For semantic promotion it also retains a compact inverse-custody document containing the exact source inventory, behavioral inventory, path dispositions, and byte-bounded batch plan. Before writing it, acceptance re-hashes every transcript field, replays strict evidence/skill admission, re-derives the Flavor proposals, and verifies that the journal call IDs reproduce the reviewed draft request identity.

Run litai spec audit --baseline accepted.json path/to/source when comparing the derived result with a prior accepted baseline. Run litai spec diff left.json right.json for a deterministic bundle comparison.

For the default static translator, author one complete Component graph JSON document after inspecting the bundle's component_definition_draft, observations, and evidence. The graph must use the exact source snapshot, the same root coordinate/title/capability set, one reviewed library, cli, or service kind, non-empty profiles and build needs, a public contract for every capability, evidence-backed entrypoints for CLI or service Components, every observation exactly once, and only source paths/evidence IDs present in the bundle. Static review intentionally supports one Component per promotion; repeat the process for another independently bounded source tree instead of inventing a multi-Component split from inventory.

A reviewed library graph deliberately carries an empty entrypoint set. On forward generation, the selected language Flavor projects its public capabilities into an exact package/module/symbol import surface; generated source must implement that surface and a framework-only generated-test adapter, not invent a CLI application.

3. Review uncertainty

Blocking uncertainty IDs are listed in bundle.json. Resolve each one explicitly:

litai spec review bundle.json \
  --actor local-user \
  --reason 'reviewed against current source and tests' \
  --component-graph reviewed-component-graph.json \
  --resolve uncertainty:first \
  --resolve uncertainty:second \
  --key local-source.key > review.json

Do not treat a suspected defect or contradictory test as desired behavior merely to clear the gate. Update source, scope, evidence, or the review disposition deliberately. The signed review binds the Component graph identity. Editing, replacing, or omitting that graph after review invalidates acceptance.

4. Accept into a complete spec-driven project

litai spec accept path/to/source bundle.json \
  --review review.json \
  --target path/to/new-spec-root \
  --project-target path/to/new-project \
  --qualification-target host \
  --flavor=+flavor://literate-ai/lang-python \
  --qualification-profile qualification-profile.json \
  --trust-key local-source.key

Acceptance verifies the source and review envelopes again. The output becomes intent authority through this explicit review decision. The acceptance record binds the exact source snapshot and says release_implementation_authority: source-baseline; review alone does not claim that a from-scratch regeneration is feature complete.

--project-target additionally creates a canonical project, copies no implementation source, installs the provider-neutral onboarding files plus exact portable-generation skill/workflow/routing inputs, and turns each reviewed inverse Flavor draft into a selectable Flavor. It writes readable component.md as the Component authority and never creates welded component.json; the migration-only reader remains through the documented 0.2.x compatibility series and is removed in 0.3.0. Acceptance then folds the ordered --flavor additions and removals into the promoted project's default Flavor selectors and runs the deterministic lock resolver for --qualification-target. This prevents template-machine defaults from leaking into the recovered application and avoids replaying an already-effective selector as a no-op. If every recovered Flavor axis has exactly one reviewed candidate, the selectors may be omitted and acceptance selects those unique candidates. Ambiguous axes require an explicit selection. Locking reads no generated source, invokes no coding model, and leaves no implementation source in the project. A one-node inverse writes one complete Component definition. A multi-node ComponentGraphDraft writes one Component per evidence-backed logical node and capability requirements for its reviewed dependency edges; every node keeps only its own accepted specification roots and remains independently generatable. Each node's reviewed kind (library, cli, or service), profiles, public capability contracts, entrypoints, and build Flavor axes become that node's manifest. Libraries retain no runnable entrypoint. CLIs and services require an evidence-backed entrypoint; unknown semantics block project promotion instead of becoming a fabricated portable-application/run.

For incremental conversion of an existing retained adopted project, use --integrate-project path/to/adopted-root instead of --project-target. Acceptance creates the same source-free project beneath .literate/native-projects/ and atomically registers its exact path, project identifier, and project-definition identity in the adopted root. The conversion-stage gate reopens every registered child, rejects registry drift and duplicate Component coordinates, and verifies each projection in the child that owns its promotion evidence. The adopted root can therefore advance to drafted without copying generated authority files across project boundaries or rewriting the retained project configuration.

To revise a still-unqualified registered child, derive and sign a new current review, then plan its replacement using the same acceptance arguments:

litai spec accept SOURCE BUNDLE --review REVIEW --trust-key KEY \
  --target accepted-next --integrate-project ADOPTED_ROOT \
  --plan-native-child-replacement > replacement-plan.json
# Review the old registration, complete child-tree identities, and new review binding.
litai spec accept SOURCE BUNDLE --review REVIEW --trust-key KEY \
  --target accepted-next --integrate-project ADOPTED_ROOT \
  --replace-native-child replacement-plan.json

Repeat any qualification-profile, target and Flavor options in both commands. Planning changes neither the child nor the accepted specification set. Apply rechecks the signed source, review, parent registration and complete prior child tree. It preserves the project identifier, retains the old promotion and registration beneath the parent's .literate/native-updates/ directory, and restores both on failure. Concurrent edits are preserved and reported as a rollback conflict. Retention is bounded to 4,096 nodes, 64 MiB per file and 256 MiB total; unsafe or oversized trees refuse before replacement.

Replacement accepts parents at retained or drafted, and refuses qualified children, qualified parents, stale inputs, symlinks and reparse points. A prior coordinated Standard rebind can supply exact historical manifest custody for checking the original promotion audit. That history never makes the live audit or test receipt current. The revised child still needs its own verifier-owned oracle and qualification.

When a reviewed local-regenerative-qualification-profile is supplied, acceptance content-pins it as the Component's independent acceptance contract. Every case has a stable ID, a positional argument array, and an exact verifier-owned expected result. The profile is withheld from generation prompts and generated implementation tests, then supplied only to the independent packaged-application acceptance boundary. Profiles from the earlier unreleased v1 shape are rejected because they did not contain expected results and cannot be upgraded without inventing verification authority. Omit the profile when authoring intent only; qualification then remains unavailable until a reviewer adds such a contract.

5. Qualify regenerative authority

Moving release authority above the original implementation is a second promotion. For each required target, repeatedly generate from only the accepted specification, selected Flavors, and pinned forward skills in a new empty workspace; bypass the generated-source cache; build the exact tree; run its freshly generated test suite; and compare it through an independent parity verifier with the original source baseline.

The original source may be compiled or run as that parity oracle under explicit host execution authorization. It must never be included in a coding-model prompt, generation workspace, generated-test input, or source-cache hit. Every required behavioral surface must pass in the configured minimum number of clean runs on every required target before a regenerative-qualification-decision can name specification as release implementation authority. Otherwise the decision remains source-baseline with explicit blockers.

Before it authorizes any host execution, qualify independently reopens semantic inverse custody and reconstructs the complete path-disposition and model batch plan. Missing, substituted, blocking-omitted, or over-budget evidence fails closed. The same check repeats immediately before a lifecycle-backed authority transition. Deterministic static translations are explicitly exempt because no model egress occurred.

Admitted test source remains valuable evidence for examples, boundaries, and expected behavior, but test classes, fixtures, and test functions are not public product surfaces. The independent collector excludes conventional language test paths and filenames from its required surface set while retaining their bytes in the evidence partition. Product source must still supply at least one independently detected surface.

The independent surface inventory treats recognized language sorting and selection constructs as required ordering surfaces. An inverse statement must name the comparison direction and domain—such as Python Unicode code-point order, JavaScript UTF-16 code units, Rust UTF-8 byte order, or the evidenced C++ comparator—and say whether encounter order can affect the result. Merely calling output "sorted" or "lexicographic" is not a complete mapping.

Recognized trimming, case conversion, and pattern-rewrite constructs are likewise required normalization surfaces. The inverse draft must state the transformation order and map each normalized value to every observable consumer and returned field. Mentioning that a trimmed value is used for grouping or an identifier does not establish that the returned value is also trimmed.

The local-host command first requires the canonical component.lock.json for --target and the ordered --flavor selectors. It rejects stale authoring, Flavor, specification, or lock bytes before host execution. Historical v1 decisions remain readable but always retain effective_authority: source-baseline and qualification-v2-required. New runs that satisfy every policy condition produce a v3 current qualification record binding the exact Component revision, lock, generation closure, inverse custody, provider identities, and both complete runs. The record is content-addressed under the promoted project's provenance/qualification/ directory; locked admission then appends the regeneratively-qualified-fungible authority successor.

There is no command-line option that accepts caller-authored qualification evidence. The CLI constructs VerifiedSourcePromotionEvidence only from the trusted providers it invoked; callers cannot inject it as JSON. Missing, partial, stale, cached, failed, or drifted facts fail closed. Reopening qualified authority also re-hashes the persisted qualification record and checks its source, specification, revision, lock, promotion, inverse-custody, verifier, and policy bindings.

Write the historical qualification record outside both the original source baseline and the promoted project. The CLI rejects either overlap and rechecks the source snapshot, Component revision, authority head, and promotion audit immediately before persisting the record.

See source promotion and regenerative qualification for the complete flow, public wire records, trust boundary, and language-skill matrix. The framework exposes the pure decision rule, run_regenerative_qualification, concrete local-host providers, and a safe CLI integration:

litai spec qualify path/to/new-project/components/APP \
  --source path/to/exact-source-baseline \
  --profile path/to/new-project/components/APP/qualification/profile.json \
  --target host \
  --output /tmp/literate-ai-qualification.json \
  --key local-source.key \
  --signer local-user \
  --allow-host-execution

Use --model MODEL to select the pipeline model explicitly for qualification. The public plan and every clean runtime receive the same selector, with normal Component and lexical model-scope rules still applied. Select the configured coding CLI through CODING_CLI. Omitting --model keeps the CLI-configured default; LITAI_LIVE_MODEL by itself does not replace this command's pipeline selector.

For an already-qualified library whose original run predates retained archive capture, repeat the same command with an immutable evidence store and explicit current-authority mode:

litai spec qualify path/to/new-project/components/LIBRARY \
  --source path/to/exact-source-baseline \
  --profile path/to/new-project/components/LIBRARY/qualification/profile.json \
  --target host \
  --output /tmp/literate-ai-qualification-capture.json \
  --retained-evidence-store path/to/evidence-store \
  --recertify-current-qualified \
  --allow-host-execution

This performs fresh generation, build, test, and independent parity runs. It records the required invalidation and new qualification as immutable successors, then moves the current pointer atomically from the old qualified projection to the fresh qualified projection; retained-source authority is never exposed as current. Use the returned archive reference for the reviewed retained-library binding. Archive publication alone does not authorize importer admission.

If the capture command was introduced by a newer Standard wheel, preserve the exact pre-rebind literate.project.json before applying the reviewed Standard rebind. Pass that file with --prior-project-configuration PATH. Literate AI requires its bytes to match the historical promotion audit, requires the current manifest to differ only in the Standard lifecycle binding and its derived test-receipt runner, and records the bridge as immutable authority evidence. Any Component, Flavor, skill, workflow, routing, policy, receipt contract, or other project-configuration change refuses the migration. The prior file is evidence input; it is not restored or made current.

qualify independently resolves the exact forward recipe, creates at least two empty workspaces, forces real litai generate calls, runs the profile's build and current-test commands, executes baseline and generated applications on the profile's JSON probes, compares their parsed values, and HMAC-signs every measured run payload. The profile is a content-pinned execution plan inside the project, not precomputed evidence. The CLI does not accept caller-supplied evidence, passed flags, result identities, or attestations. Local execution is explicitly authorized and unsandboxed; organizational integrations may replace these providers and the local HMAC root with their own trusted execution and signing services.

Each successful clean run is checkpointed under BUILD_DIR/qualification-checkpoints/. This is signed evidence caching, not generated source caching: every measured run still requires a source-cache miss. If a later run is interrupted or rejected, repeat the same command. Literate AI verifies the prior run against the exact source, spec, Flavor lock, recipe, target, source-exclusion audit, and provider identities and executes only the missing run. Changing any of those inputs—or the signing key—prevents reuse. litai really-clean deliberately removes the checkpoints.

How this path is tested

The test ladder keeps network variability out of the mandatory gate while still making the real integration reproducible:

Layer What it proves Normal command
Strict adapter tests Four language partitions, exact skills, evidence admission, model-output parsing, complete journals, tamper rejection, and pre-egress pin checks make validate
Installed source-inventory test A real temporary mirror is inventoried and content-bound make validate
Regenerative parity Two empty, cache-bypassed source generations per language compile/run through Python, C++, Rust, and JavaScript and match independently observed baseline output, including invalid input make validate
Live model integration Unavailable; coding-cli inverse translation fails closed n/a
Live bidirectional promotion One stable application spec generates, builds, tests, and runs in Python, C++, Rust, JavaScript, and Elixir; every generated tree is translated back and compared against the complete normalized requirement graph; every inverse spec is promoted and completes two new spec-only build/test/parity runs to reach fungible authority LITERATE_AI_RUN_LIVE_ROUNDTRIP=1 CODING_CLI=codex PYTHONPATH=src python -m unittest tests.conformance.test_live_bidirectional_roundtrip
Live composed promotion The invoice sample generates, reverses into three evidence-bound Components and two capability edges, promotes the full graph, composes it normally, regenerates, builds, tests, and matches known output LITERATE_AI_RUN_LIVE_COMPOSED_ROUNDTRIP=1 CODING_CLI=codex PYTHONPATH=src python -m unittest tests.conformance.test_live_composed_roundtrip

The live commands spend coding-agent calls and require the selected CLI to be installed and authenticated, so they are explicit rather than part of credential-free CI. CODING_CLI may instead name claude, cursor-agent, or opencode; set LITERATE_AI_LIVE_MODEL only when the integration must pin a particular model.

These tests are deliberately host-scoped. Literate AI does not require every application to implement both directions or repeat inverse translation on every OS/Flavor. The separate make samples-platform-regression target fans one representative forward sample, or a configured glob, across macOS, Linux, and Windows.

What the four-language round trip established

The regenerative-roundtrip application is intentionally richer than a symbol inventory. Its contract includes bounds, whitespace normalization, aggregation, integer discount arithmetic, stable ordering, tie-breaking, exact output fields, and invalid-input behavior. The inverse translator performs an exhaustive contract-coverage audit over those facets before it may claim a draft is complete. Semantic comparison is therefore based on separately attributable behavioral anchors, not prose similarity or byte equality with the original specification.

OpenSpec emission preserves that structure mechanically: every recovered statement has one unique Requirement heading keyed by its statement ID, and all of that statement's scenarios remain beneath it. Multiple scenarios never duplicate a Requirement name. This matters because strict provider validation is part of derivation, not a cleanup step after review.

The same accepted contract generated working Python, C++, Rust, and JavaScript programs. Each portable executable receives one JSON array of positional arguments as its first application argument; language launchers decode that array and call the generated application contract. This avoids shell-specific quoting and gives the forward generator, baseline runner, promoted project, and independent verifier one cross-platform ABI.

The live test also exposed conversion technique that belongs in skills, not product intent. The Bazel skill now pins known-compatible rule-set baselines, requires explicit Bazel 9 rule loads, requires the root MODULE.bazel to begin with one keyword-only literal module(name = "<valid_module_name>", version = "<exact_component_version>") before every bazel_dep, places shared C++ headers in cc_library, sets every Python main, and uses entry_point plus data for JavaScript launchers. Those details can change with a skill revision without changing what the application means.

Incremental refresh

Preserve reviewed statements when possible and invalidate only affected surfaces:

litai spec refresh path/to/source \
  --previous bundle.json \
  --changed-path src/changed.py > refreshed.json

For deterministic tutorial fixtures, derive, refresh, and conformance also accept the case descriptors under tests/fixtures/source_to_specification.

Dynamic observation is a separate, explicit authorization path. It fails closed unless sandbox-exec is available on macOS or bwrap is available on Linux; missing sandbox tooling never means execute source directly.

Forward-generated tests are not authoring authority

Tests found in an independently maintained existing checkout can be useful inverse-flow evidence: the reviewed tests skill attributes their assertions and records conflicts or gaps. That does not make all test-shaped files durable intent.

A forward major rebuild generates source/tests/manifest.json beside its disposable implementation. That suite is derived from the same current specs, selected Flavors, and exact skills as the code. Do not copy it into a specification project, feed it into the next inverse-authoring run, or preserve it as a baseline. Change accepted specs or Flavor requirements, review exact skills when technique changes, then regenerate the implementation and suite together. The separate verifier oracle remains independent acceptance evidence.

Elixir .ex and .exs files have inert inventory, behavioral-surface discovery and an independent language skill. The live roundtrip selector accepts elixir. The public coding-CLI inverse translator is currently unavailable for every language; selecting Elixir does not bypass that gate or count fixture observations as live inverse qualification.

Read the Markdown sourceConference homePublished 1.3.0 · Patch 1.3.1 in progress · Development 1.4