Upgrading
Per-version migration notes. Version churn lives only here.
The rest of the reference is versionless. This page collects what changes between releases and what you have to do about it. For the complete log, see the GitHub releases.
Compatibility promise: patch releases (1.3.0 → 1.3.1) do not normally invalidate built modules. The exception is a correctness repair for artifacts whose provenance was previously marked fresh incorrectly; that safety migration is called out explicitly below.
1.7.0
Jaunt 1.7 adds the first alpha TypeScript target. The Python package is now
1.7.0; the project-local worker and marker package use their own prerelease
version under @usejaunt/ts.
-
Existing Python projects do not need a migration. Version-1
jaunt.tomlfiles and generated Python artifacts keep their current layout. The release does not intentionally stale an otherwise fresh Python module; upgrade and runjaunt checkas usual. -
A TypeScript target uses version-2 configuration. Install the Python CLI, then add the worker, a supported compiler, and the protected test runtime to the package named by
tool_owner:npm install -D @usejaunt/ts@next 'typescript@^5.9' vitest fast-check @types/nodeThe worker supports Node 20 through 24 and TypeScript 5.8 through 6.x. Start with the TypeScript target guide, then run
jaunt sync --language tsbefore the first model-backed build. -
Adding TypeScript to a version-1 Python project is mechanical. Preview
jaunt migrate --config-v2, review the version-2 target layout, and apply it withjaunt migrate --config-v2 --apply. The migration moves Python-specific settings under[target.py]without changing their loaded values or calling a model. -
Alpha artifact formats can still change. Preview upgrades with
jaunt migrate --language ts. Compatible mirrors, facades, placeholders, sidecars, and fingerprints are repaired deterministically; an incompatible protocol, IR, route, or contract change is reported asmodel-rebuildrather than guessed. -
Mixed workspaces operate on both targets by default. Use
--language pyor--language tsto narrow a command. TypeScript target IDs are qualified asts:path/to/spec#symbol; existing dotted Python IDs keep their meaning.
1.6.3
- Removing a magic or generated-test spec now rebuilds its module instead of re-stamping the old body. This prevents deleted implementations and pytest functions from surviving as dead generated text.
- Generated artifacts last stamped by 1.0.0rc7 through 1.6.2 rebuild once on upgrade because those releases could overwrite the evidence needed to detect an earlier removal-only re-stamp. This is an intentional safety exception to the usual patch-release freshness promise.
- Context-only rebuilds stay local, while removal and public-API changes still propagate to affected dependents. Pure fingerprint changes and semantically equivalent prose edits retain the free re-stamp path.
1.6.2
- A single
jaunt.tomlcan now route modules across several packages and mixed flat/srclayouts.source_rootsandtest_rootsaccept globs; unmatched globs fail during config loading. - Generated implementations, stubs, tests, contract batteries, ty checks, and
dependency validation follow each module's nearest owning
pyproject.toml. Root-levelstatus,check,clean,watch, and daemon jobs cover the full workspace. - Run
jaunt migrate --merge-projectsto prove that existing child projects can be consolidated without changing module names, digests, fingerprints, or artifact paths. Add--applyafter reviewing the plan. - The semantic gate now defaults to
gpt-5.6-lunaat medium reasoning. Semantic gate settings remain outside generation fingerprints, so this does not stale generated modules.
1.5.1
Patch release from the sixth adoption-feedback wave, focused on uv workspaces. No generated body changes, and the one restale it causes costs nothing to clear.
- Modules read
stale (fingerprint)after the upgrade — the next build re-stamps them all for free. The build prompt's import rule changed, and the prompt is a fingerprint input, so every built module reports stale once. Their spec sources are unchanged, sojaunt buildresolves each through the re-stamp path: it writes the new fingerprint over the existing body with no semantic-gate call and nogpt-5.6-solcall.jaunt checkcounts fingerprint staleness as drift and exits4until you run that one build and commit the re-stamped headers.--jsonlists the modules underrefrozen. - Specs that span source roots now stop at a config error instead of building
into the wrong package. Under 1.5.0, a multi-root project (
source_rootswith more than one entry) routed every generated file to the first existing root, which quietly broke packages under the others —statusandcheckread through the same wrong path, so the tree looked fresh while runtime was broken. 1.5.1 makes that a hard config error (exit2) onbuild,check,status, andmigrate: it fires when governed specs span more than one root, or when they all live under a root that is not the first existing one (the message tells you to reorder). The adopter-verified fix is one jaunt project per package: put ajaunt.tomlwithsource_roots = ["."]at each package's import root and run jaunt from there. Nested default roots (["src", "."]) with specs undersrc/resolve by longest path and pass untouched. - Generated code may import third-party packages plainly. The build prompt
now sanctions the standard library and any installed distribution that the
spec module imports or the owning package declares — imported from its real
module, not smuggled in through a duck-typed stand-in or a dynamic import.
Paired with it, the undeclared-import validator resolves declared dependencies
from the pyproject that owns the spec's source file, not just the config-root
one. A workspace dependency declared in its own package's pyproject now passes
without an entry in
build.generated_import_allowlist; see the allowlist.
1.5
Minor release that closes the adoption-feedback backlog: a codex advisories
channel, jaunt migrate, an orphaned-artifact gate, and clearer status labels.
No built module restales on the upgrade.
- Nothing restales when you upgrade. The advisories prompt instruction lives
in backend code, outside the generation fingerprint, so it cannot invalidate a
built module.
_STUB_FORMAT_VERSIONis unchanged, so committed.pyistubs stay fresh. Upgrade, runjaunt status, and every module reports fresh. jaunt checknow blocks on orphaned artifacts. An orphan is a generated module,.pyistub, or contract battery whose spec no longer exists.checkexits4and names the fix. On upgrade this fires only if you already have orphans on disk from a deleted or renamed spec. Clear them once withjaunt clean --orphans(preview with--dry-run), or restore the spec. Hand-authored files are never candidates: only files carrying a jaunt provenance header, plus the.contract.jsonsidecar next to an orphaned module, can be classified.jaunt migrateretires two upgrade chores. It rewrites legacyraise RuntimeError("spec stub")bodies to...and re-stamps the header so the change costs no model call, and it re-emits.pyistubs left stale by a past_STUB_FORMAT_VERSIONbump. It plans by default and prints what it would change; pass--applyto write. This closes the 1.4.2 caveat wherejaunt checkstayed red until you ran a fulljaunt build.- Advisories are additive. Codex ends its final message with any logical
issues it noticed while implementing: a spec ambiguity, a spec that
contradicts a dependency's documented API, or a suspected bug in code it read.
Fresh builds and test runs print them,
--jsoncarries anadvisoriesmap, andjaunt logreplays them. They never touch digests, staleness, or exit codes. - The
context_statsskills key is renamed.skills_workspacebecomesskills_workspace_seededto say what it measures: the bytes of skill files seeded on disk and available to the agent, not bytes the agent read. The oldskills_workspacekey stays as a--jsonalias for this release. - Two new status labels. A module the next build resolves through the free
re-stamp path now reads
stale (re-stamp: free)instead ofstale (structural), and a module-origin spec with no artifact yet is flaggednewly governed by module scanbefore you spend anything. - Docs and the
jaunt initscaffold lead with...again. 1.4.2 had switched the example stub body toraise NotImplementedErrorto satisfy strict type checkers;...reads plainer, never runs, and carries no runtime risk, so it is the default once more. All stub forms still digest identically. If ty or Pyright flags...under a concrete return annotation,raise NotImplementedErrorworks just as well and switching between the two never restales a module.
1.4.2
Patch release from the fourth adoption-feedback wave. No built module is
invalidated and re-emitting stubs makes no model calls — but note the CI
caveat: the stub format version changed, so jaunt check reports committed
stubs stale (exit 4) until you run jaunt build once and commit the
re-emitted .pyi files.
importlib.reload()works on governed modules. Re-executing the samemagic_module(__name__)call (same file, same line) is now treated as a reload: the prior registration is replaced instead of raising "already called". Reload-dependent test idioms (monkeypatch.setenv+reload) no longer force a module back to decorator style. A second call at a different line in the same module is still an error.- Scaffold and docs lead with
raise NotImplementedError. Strict type checkers (ty, Pyright) reject a...body under a concrete return annotation outside stub files. All stub forms digest identically, so switching your existing...bodies over is free. (1.5 reverted the scaffold default back to...; the type-checker note still holds, and either form works.) - Emitted
.pyistubs are lint-clean. The unusedimport jauntis no longer copied from the spec; names inside string annotations ("Chunker | None") resolve like plain ones (from the generated module's imports, includingif TYPE_CHECKING:blocks, with anAnyfallback for optional-dependency guards); and whenruffis on PATH the emitted stub is formatted with it. You can drop per-file lint exemptions for jaunt stubs. - Refreeze no longer blanks
tool_version. Re-stamped generated headers (the free path that resolves digest-scheme migrations and gate-equivalent edits) now record the jaunt version that wrote them, preserving provenance.
1.4.1
Patch release: three post-merge review fixes for magic_module. No built
module is invalidated.
- A handwritten helper reached first no longer runs raw stubs. In 1.4.0,
if the first external access to a governed module was a handwritten helper
(not a spec name), the helper's calls into sibling specs hit the pre-rebind
stubs and silently returned stub results (
None). Resolution now fires on the first access to any non-dunder attribute. - Circular imports are detected exactly. The mid-execution guard now keys
on importlib's
__spec__._initializingflag, so a circular importer probing the module — even after the last stub is defined — sees plain stubs instead of triggering eager resolution. The 1.4.0 known-limitation window is closed. - A stub shadowed by a later real definition is handwritten. The scan now
classifies the last top-level
def/classper name, matching Python's last-binding-wins semantics. If you relied on an early stub being governed despite a later real redefinition (unlikely), the real definition now wins. - Finalize errors exit structurally. A governed module that fails post-import finalize (for example a spec class with a custom metaclass) now reports as a discovery error (exit 2) instead of an uncaught traceback.
1.4.0
jaunt.magic_module(__name__) — module-level magic — becomes the primary
authoring style. Nothing about decorator mode changes; the new call is additive.
- Converting a decorated spec to
magic_moduleis digest-neutral, as long as the stub body form is unchanged. The@jaunt.magicline never entered the digest, and a module-governed spec renders its signature through the same path a decorated one does, so dropping the decorator does not restale the module. - Rewriting
raise RuntimeError("spec stub")to...restales once. That older body is not a recognized stub form — in a governed module it would classify as handwritten, not a spec — so its text is part of the current digest. Standardizing on...during conversion costs one rebuild per module. - Module-level kwargs restale their governed specs. A
magic_module(prompt=…)default is part of every governed spec's contract, so adding or editing one restales the file, as any contract change should. - Eject, don't hand-strip, in a governed module. Removing a
@jaunt.contractor@jaunt.magicmarker by hand from a still-stub-shaped function inside amagic_modulefile silently flips that function to module-magic governance — the scan now picks it up. Usejaunt eject, which leaves committed real code that classifies as handwritten, instead of deleting the marker yourself.
1.3.1
Patch release from the second adoption-feedback wave.
-
Migrating inner
@jaunt.magicto@jaunt.sigis free. (Corrected in 1.4.2 — this note originally said to budget one rebuild; adopter reports showed the rename resolves through the re-stamp path with zero model calls.jaunt statusmay label the module stale until the nextjaunt buildre-stamps it.) -
[codex] fingerprint_cli_versionnow defaults tofalse. Embeddingcodex --versionin the generation fingerprint coupledjaunt checkto environments with the codex binary installed: a CI runner without it restaled a byte-identical tree. If you relied on CLI-version churn triggering rebuilds, set it back totrueexplicitly. Projects that built with the old default will see a one-timestale (fingerprint)on the next build after upgrading. -
Fingerprint-only staleness is now labeled.
statusandcheckreportstale (fingerprint)instead ofstale (structural)when specs are byte-identical but the generation fingerprint differs, and print a hint when the cause is a missing codex binary withfingerprint_cli_version = true. -
.pyistubs no longer containfrom __future__ import annotations. The emitter could place a future import mid-file (a syntax error for ruff and ty). Stale stubs re-emit on the next build; no action needed.
1.3.0
Adoption-feedback release: strict config, .pyi stubs, a CI-grade check, and
the @jaunt.sig vocabulary.
- Generated layout for top-level modules changed. A bare module
timingunder a source root now generates to__generated__/timing.pyinstead of the oldtiming/__generated__/__init__.py, which shadowed the module name. Package members (pkg.mod→pkg/__generated__/mod.py) are unchanged. If you have a top-level-module project, runjaunt clean && jaunt buildonce to migrate. See Output Locations. - Config validation is strict. Unknown sections and keys are now errors
(exit
2) with a did-you-mean suggestion. Upgrading can surface a latent typo that was previously ignored and silently left a setting at its default. Fix the reported key. See Strict validation. emit_stubsdefaults on. Builds now write a.pyibeside each spec module, and a missing or stale stub marks the module stale. Set[build] emit_stubs = falseto opt out. See.pyistubs.jaunt checkgates magic drift.checknow fails on an unbuilt or stale@jaunt.magicmodule, not just contract drift, so it is the single CI gate for both modes. Scope it with--contracts-onlyor--magic-only. See the CI guide.@jaunt.sigfor sealed methods. In a whole-class spec, mark a method@jaunt.sigto seal its signature (exact params, defaults, annotations, and return type enforced). See writing magic specs.- Repo-map drift is decoupled from magic freshness.
statusandchecktracktreedocs.yamldrift separately;--magic-onlyskips it entirely.
1.2.0
- The daemon parks green jobs by default.
[daemon] auto_commitnow defaults tofalse: a green job becomes a reviewable proposal you land withjaunt jobs land, rather than an automatic commit. This is the one behavior change existing daemon users feel. To restore the pre-1.2 auto-commit-on-green loop, setauto_commit = true. See the Background Daemon guide.
Next: back to CLI.