Metadata-Version: 2.4
Name: jaunt
Version: 1.4.2
Summary: Spec-driven code generation framework: write intent as decorated Python stubs, generate implementations and tests with LLMs.
Project-URL: Homepage, https://github.com/creatorrr/jaunt
Project-URL: Repository, https://github.com/creatorrr/jaunt
Project-URL: Issues, https://github.com/creatorrr/jaunt/issues
Keywords: cli,code-generation,developer-tools,llm,testing
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Software Development :: Testing
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: anyio>=4.1
Requires-Dist: pytest-asyncio>=1.0
Requires-Dist: pytest>=8
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich<15,>=13
Requires-Dist: watchfiles>=1.0.0
Description-Content-Type: text/markdown

# Jaunt

<div align="center">
  <img src="docs-site/public/images/tyger-blake-1794.jpg" alt="William Blake, 'The Tyger' from Songs of Experience (1794). The Metropolitan Museum of Art, Open Access." width="280" />
  <br/>
  <sub>William Blake, <em>The Tyger</em>, plate 42 from <em>Songs of Experience</em> (1794).
  <a href="https://www.metmuseum.org/art/collection/search/347983">The Metropolitan Museum of Art, Open Access.</a></sub>
</div>

<br/>

> *Tyger Tyger, burning bright,*
> *In the forests of the night;*
> *What immortal hand or eye,*
> *Could frame thy fearful symmetry?*
>
> -- William Blake, via Alfred Bester's *The Stars My Destination*

Jaunt is a small Python library + CLI for **spec-driven code generation**. You
write the intent — a signature and a docstring — and Jaunt writes the
implementation under `__generated__/` using the OpenAI Codex CLI (`codex exec`).

Call `jaunt.magic_module(__name__)` once at the top of a file and every top-level
stub below it becomes a spec, with no per-symbol decorators:

```python
import re
import jaunt

jaunt.magic_module(__name__, prompt="All parsers are RFC 5322 strict.")

EMAIL_RE = re.compile(r"...")           # real body → handwritten, kept as-is

class Email:
    """Email with from_, to, subject, body. Validates on construction."""
    # docstring-only class → Jaunt designs and writes the whole class

def parse_email(raw: str) -> Email:
    """Parse an RFC 5322 payload into an Email. Raise ValueError on malformed
    input, naming the first offending header."""
    raise NotImplementedError

def _debug(email: Email) -> str:        # real body → handwritten helper
    return f"<{email.from_} -> {email.to}>"
```

`jaunt build` fills in `Email` and `parse_email` and leaves `EMAIL_RE` and
`_debug` alone. The scan governs only top-level stubs — a `def` or `class` whose
body is `...`, a bare docstring, `pass`, or `raise NotImplementedError`. The
examples use `raise NotImplementedError` because strict type checkers (ty,
Pyright) reject an empty body under a concrete return annotation outside stub
files; the forms digest identically, so switching between them is free. Anything
with a real body, or carrying a non-jaunt decorator like `@property` or
`@dataclass`, is handwritten context the model reads but never regenerates.

### The precision layer: `@jaunt.magic`

Reach for the decorator when you want per-symbol control. `@jaunt.magic(deps=...,
prompt=...)` overrides the module defaults for one symbol — the module defaults
still merge in key by key, and the per-symbol value wins. The decorator is also
how you opt a symbol in against the scan: a stub carrying `@property`, or an
intentionally-empty function marked `@jaunt.preserve`, stays handwritten until
you add `@jaunt.magic`.

```python
@jaunt.magic(deps=[parse_email], prompt="Reuse parse_email per line.")
def parse_mbox(raw: str) -> list[Email]:
    """Split an mbox payload on `From ` lines and parse each message."""
    raise NotImplementedError
```

## What you get

- **Module-level magic** — `jaunt.magic_module(__name__)` turns every top-level
  stub in a file into a spec. Mixed files (specs plus handwritten helpers) are
  first-class. Decorate individual symbols with `@jaunt.magic` / `@jaunt.test`
  when you want per-symbol overrides.
- **Whole-class specs** — a class-level spec can be docstring-only (Jaunt designs
  the API), stub methods only, or a mix. Each method sits in one of three tiers:
  `@jaunt.preserve` keeps it verbatim, `@jaunt.sig` locks its signature while
  Jaunt writes the body, and an unmarked guidepost stub lets the model adapt the
  signature.
- **Parallel, DAG-scheduled builds** — modules build over the dependency graph
  with a critical-path-first ready queue. A module starts generating the instant
  its dependencies finish, with no wave barriers, up to `[build] jobs` workers at
  once. A failed module skips only its dependents; the rest of the graph keeps
  building.
- **Smart change detection** — freshness is a SHA-256 digest over the
  AST-normalized contract, so reformatting, comment edits, and quote-style churn
  never trigger a rebuild. Staleness is dependency-aware: changing a module's
  exported API restales its dependents, while a body-only rebuild does not. A
  behaviorally-equivalent docstring edit gets re-frozen by the semantic gate
  instead of paying for a full rebuild.
- **Async, tests, and contracts** — `async def` specs build and test through
  `build.async_runner`, `@jaunt.test` specs generate pytest batteries, and
  `@jaunt.contract` pins hand-written code with a derived, committed battery.

## Two Modes

Jaunt has two authoring modes that coexist in the same project:

- **Magic mode** (`jaunt.magic_module` / `@jaunt.magic` / `@jaunt.test`): the
  docstring is canonical and Jaunt generates implementations under
  `__generated__/`.
- **Contract mode** (`@jaunt.contract`): committed code is canonical and Jaunt
  derives a committed pytest battery under `tests/contract/`. Covers top-level
  functions (sync or async) and whole classes; derived cases may use pytest
  fixtures resolved from `tests/contract/conftest.py`.

See `examples/contract_slugify/` for a Contract-mode walkthrough.

## Installation

```bash
pip install jaunt

# The base install is batteries-included (rich, watchfiles, pytest,
# pytest-asyncio, anyio) — no optional extras.

# Jaunt drives the external OpenAI Codex CLI, which you install and
# authenticate separately:
#   1. Install the `codex` CLI (see the Codex docs).
#   2. Authenticate it: `codex login`.
```

## Codex Engine

Codex is the sole code-generation engine: Jaunt drives `codex exec` for
all build/test/skill workflows. It requires the external `codex` binary on your
PATH, authenticated via `codex login`. Multi-provider routing is deferred.

## Quickstart (This Repo)

Prereqs: `uv` installed.

```bash
uv sync
codex login                 # authenticate the Codex engine
uv run jaunt --version
```

For your own project, run tests with the source root importable, e.g. `PYTHONPATH=src`.

See `docs-site/` for rendered docs, or `DOCS.md` for a plain-text walkthrough.

All examples live under `examples/`. See `examples/README.md` for the full list.

### Your First Spec

`jaunt init` scaffolds a starter `src/specs.py` in module-magic style — one stub
Jaunt implements:

```python
import jaunt

jaunt.magic_module(__name__)


def greet(name: str) -> str:
    """Return a friendly greeting for `name`.

    Includes the name verbatim and ends with an exclamation mark.
    """
    raise NotImplementedError
```

```bash
uv run jaunt build
PYTHONPATH=src uv run jaunt test
```

### Hackathon Demo (JWT Auth)

Headline demo: **JWT auth** (the "wow gap" example: short spec, real generated glue + tests).

```bash
# Generate implementations for @jaunt.magic specs.
uv run jaunt build --root examples/jwt_auth

# Generate pytest tests for @jaunt.test specs and run them.
PYTHONPATH=examples/jwt_auth/src uv run jaunt test --root examples/jwt_auth
```

## For Coding Agents

Point any coding agent (Claude Code, Codex, Cursor, a bare shell, CI) at Jaunt
with one command:

```bash
jaunt instructions          # a tight, project-aware primer to load into context
jaunt instructions --json   # {command, ok, text, project} for tooling/MCP
```

It prints the framework rules (the two modes, the build/test loop, how to write a
good spec, the command + exit-code reference) followed by a live snapshot of the
current project (resolved paths, engine/model, and which modules are stale). It
ships with the package, so the briefing always matches the installed version. Run
it before you start working.

## Background Daemon

`jaunt daemon start` runs background codegen with commit-triggered isolated jobs
and auto-commit on green. `jaunt daemon stop|status` stops or inspects it.
Use `jaunt jobs` for job records, would-rebuild previews, `show <id> [--full]`,
and `retry <id>`. `jaunt log` tails `JAUNT_LOG` (`-n N`, `--module X`), and
`jaunt guard` warns when agents touch `__generated__` via the PreToolUse hook.

## Freshness Model

- The full cleaned docstring is part of the spec contract, not just the first summary line.
- For whole-class `@jaunt.magic` specs, Jaunt treats the class signature plus declared members and method signatures as exported API.
- Jaunt's freshness model uses that dependency API too, so an upstream contract change can mark downstream modules stale even if their own source file did not change.

## Eval Suite

`jaunt eval` is deferred under the Codex engine (rework pending).

Prompt snapshots:

```bash
uv run pytest tests/test_prompt_snapshots.py --snapshot-update
```

## Auto-Generate PyPI Skills (Build)

`jaunt build` includes a best-effort pre-build step that auto-generates “skills” for external libraries your project imports and injects them into the build prompt.

What happens:

- Scan `paths.source_roots` for `import ...` / `from ... import ...` (ignores stdlib, internal modules, and relative imports).
- Resolve imports to installed PyPI distributions + versions from the current environment.
- Ensure a skill exists per distribution at:
  - `<project_root>/.agents/skills/<dist-normalized>/SKILL.md`
- If missing/outdated, fetch the exact PyPI README for `<dist>==<version>` and generate `SKILL.md` using the Codex engine.
- Inject the concatenated skills text into the build LLM prompt.

Overwrite rules:

- Jaunt only overwrites a skill if it was previously Jaunt-generated (it has a `<!-- jaunt:skill=pypi ... -->` header) and the installed version changed.
- If the header is missing, the file is treated as user-managed and will never be overwritten.

Failure mode: warnings to stderr, and the build continues without missing skills.

## Docs Site (Fumadocs)

The repository includes a Fumadocs (Next.js) documentation site under `docs-site/`.

```bash
cd docs-site
npm run dev
```

## Publish to PyPI

If you keep your token in `.env` as `UV_PUBLISH_TOKEN=...`, load it into your shell first:

```bash
set -a
source .env
set +a
```

Build and validate artifacts:

```bash
uv build
uvx twine check dist/*
```

Upload to PyPI:

```bash
uv publish --check-url https://pypi.org/simple/
```

## Dev

```bash
uv run ruff check --fix .
uv run ruff format .
uv run ty check
uv run pytest
```

Final verification before pushing:

```bash
uv run ruff check .
uv run ruff format --check .
uv run ty check
uv run pytest
```

## Why "Jaunt"?

Named after *jaunting* -- teleportation by thought alone -- from Alfred
Bester's 1956 novel [*The Stars My Destination*](https://en.wikipedia.org/wiki/The_Stars_My_Destination)
(originally published as *Tiger! Tiger!*). You think about where you want to
be, and you're there.

Jaunt works the same way: describe your intent, and arrive at working code.

The forge-and-furnace imagery you'll find scattered through the codebase
comes from William Blake's poem "The Tyger," which Bester used as the
novel's epigraph and alternate title. The poem's vision of creation --
hammer, chain, furnace, anvil -- mirrors the act of forging code from pure
specification.
