How It Works
The mental model: target discovery, DAG builds, prompts, validation, and freshness.
Jaunt has one loop: you write specs, Jaunt generates modules, you review, you tighten the spec, you rebuild. Once you can picture that loop, the rest of the tool follows from it.
The Flow
You write specs
-> Jaunt discovers them (source_roots / test_roots)
-> routes them through the Python or TypeScript target
-> builds a dependency graph
-> for each module:
- build prompt = target template + contract + project context
- Jaunt drives `codex exec` to propose an implementation
- the target validates the complete candidate
- Jaunt writes the artifact transaction
-> Python imports forward from the spec module
-> TypeScript consumers import the committed facadePython discovery imports prescreened spec modules and uses Python ASTs, ty, and
pytest. TypeScript discovery does not execute application or spec modules: the
project-local @usejaunt/ts worker parses private *.jaunt.ts[x] inputs with the
owning TypeScript compiler. It validates candidates in an in-memory compiler overlay
before any implementation, API mirror, or sidecar is replaced.
What the model sees
At build time Jaunt sends the model a prompt built from a few pieces:
- A target-specific system template (packaged under
src/jaunt/prompts/). - Your spec's source segment: the Python signature/docstring/decorator options, or the TypeScript declaration/TSDoc and marker options.
- Optional per-spec context, such as
prompt="...". - A repo map rendered from
treedocs.yaml, on by default (see Repo Context).
Library and tooling skills are not prompt text. Jaunt seeds them into the
Codex workspace under .agents/skills/, where Codex discovers them on its own.
The job the model is handed is narrow: implement the contract the spec implies, nothing more.
The Codex engine
Jaunt has a single generation engine, the OpenAI Codex CLI. For each module
Jaunt spawns one codex exec subprocess and hands it the rendered prompt. Python
validates the proposed module before writing it. TypeScript composes the proposed
internal bindings with its deterministic public boundary, then checks the complete
overlay through the owning project and affected project references before writing.
Everything around that step — discovery, staleness, validation, file locations, and runtime integration — belongs to Jaunt, not to Codex. See Codex Engine.
Incremental rebuilds
Jaunt hashes the spec source for each module and writes the digest into the generated file's header. On the next run it skips modules whose digest still matches. Change a spec and only what depends on it regenerates.
The digest covers more than the spec text. Jaunt also fingerprints the generation runtime and the prompt templates, so switching models or editing the preamble can mark files stale too. Change Detection covers exactly what counts as a change and what does not.
Dependency ordering
Jaunt builds a spec-level DAG, so dependencies generate before the specs that
use them, and a change to a dependency propagates staleness to its dependents.
You declare edges with deps=..., and Jaunt infers the rest best-effort. See
Dependencies.
Parallel builds
Jaunt does not build modules in level-synchronous waves. It runs a single ready queue over the dependency graph and keeps every worker busy.
When a build starts, Jaunt takes the stale modules, computes each one's indegree (how many of its dependencies are also stale and still unbuilt), and assigns a priority equal to its critical-path length — the longest chain of dependents that has to wait on it. Modules with no unbuilt dependencies seed a ready heap, ordered longest-critical-path first, so the work that unblocks the most other work goes first.
From there the loop is continuous. Jaunt starts modules off the ready heap until
[build] jobs are in flight, then waits for the first one to finish rather
than the whole batch. The moment a module completes, every dependent whose last
dependency just landed drops onto the ready heap and can start immediately —
there is no barrier between "levels." A module that fails marks only its
dependents failed (recursively); the rest of the graph keeps building. You get
the partial result plus a precise list of what was skipped and why.
Python runtime forwarding
TypeScript does not use runtime forwarding or a loader hook. Production code imports
the ordinary facade next to the private spec; normal tsc, bundler, and Node
resolution take over from there. See the
TypeScript target guide.
A spec module does not generate code when you call it. It forwards your call
into the generated module under __generated__/. If that module exists, your
call delegates to it. If it does not, you get JauntNotBuiltError and a nudge
to run jaunt build. Either way you import the spec module in normal code:
the spec module is the stable API surface, and the generated body behind it is
free to change on every rebuild.
The @jaunt.magic decorator forwards per symbol — the decorated function or
class is a wrapper that resolves the generated object on first call.
magic_module forwards per module with a lighter touch. On the first attribute
access to any governed spec name, Jaunt imports the generated counterpart,
rebinds every spec name in the module to its generated object (functions and
classes alike), and then swaps the module back to a plain module. After that
first access the module is ordinary: attribute lookups hit the generated objects
directly, at zero overhead. It intercepts once, rebinds, and vanishes.
Two-phase registration
magic_module has to register its specs before the stubs below it exist as
runtime objects, because the call runs while the module is still executing. It
does this in two phases. At call time Jaunt parses the module source, classifies
the top-level stubs, and registers each one from the AST alone — signature and
docstring are enough to compute digests, so the spec object can be None for
now. Once the module finishes importing, a finalize step backfills every entry
with its real function or class and runs the same analysis a decorated spec
gets. By the time the builder, tester, or jaunt specs looks at the registry, a
module-governed spec is indistinguishable from a decorated one — same signature
rendering, same digest inputs. Converting a decorated spec to module style is
digest-neutral as long as you leave the stub body form alone.
PyPI skills
On jaunt build, Jaunt can generate "skills" from PyPI READMEs for the external
libraries you import, best-effort. Those skills, plus Jaunt's bundled builtins,
land in the Codex workspace at .agents/skills/ for Codex to read. It tends to
improve correctness on unfamiliar libraries without bloating your prompt. See
Auto-Generated PyPI Skills.
Where to go deeper
Internals
The design notes behind all of this live in the repository, not on this site.
Two are worth reading if you want to know why Jaunt draws the lines where it
does. A design-principles doc
writes down the rules Jaunt's own generator is held to. And Jaunt is built with
itself: the docs/superpowers/
directory holds the written specs and plans behind each Jaunt feature, in the
same spec-first style this page describes.