Jaunt

jaunt, dont code.

Spec-driven code generation: write Python stubs, get real implementations from an LLM.

William Blake, 'The Tyger' (1794)

Blake, The Tyger, 1794. Met Open Access.

Tyger Tyger, burning bright, / In the forests of the night -- William Blake, via Alfred Bester's The Stars My Destination

Jaunt is a Python library + CLI for spec-driven code generation.

Named after jaunting -- teleportation by thought alone -- from Bester's 1956 novel. You think about where you want to be, and you're there.

You write specs — real Python stubs with types and docstrings. Jaunt sends them to an LLM and generates real implementations + tests under __generated__/. You review, iterate, and ship. The spec is the contract — everything flows from it.

The Wow Gap

A tiny spec on the left. Real code on the right.

Spec (you write)
from datetime import timedelta

import jaunt
from pydantic import BaseModel


class Claims(BaseModel):
    """Decoded token payload."""

    sub: str
    iat: float
    exp: float


@jaunt.magic()
def create_token(user_id: str, secret: str, *, ttl: timedelta = timedelta(hours=1)) -> str:
    """
    Create an HS256-signed JWT.

    - base64url encoding must omit "=" padding.
    - Use HMAC-SHA256 with `secret` as the key.
    - Raise ValueError if user_id is empty or ttl is not positive.
    """
    raise RuntimeError("spec stub (generated at build time)")
Generated (Jaunt writes)
import base64
import hmac
import hashlib
import json
import time
from datetime import timedelta


def _b64url_encode_no_pad(data: bytes) -> str:
    return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")


def create_token(user_id: str, secret: str, *, ttl: timedelta = timedelta(hours=1)) -> str:
    if not isinstance(user_id, str) or user_id == "":
        raise ValueError("user_id must not be empty")
    if ttl.total_seconds() <= 0:
        raise ValueError("ttl must be positive")

    header_obj = {"alg": "HS256", "typ": "JWT"}
    now = int(time.time())
    payload_obj = {"sub": user_id, "iat": now, "exp": now + int(ttl.total_seconds())}

    header_b64 = _b64url_encode_no_pad(json.dumps(header_obj, separators=(",", ":"), sort_keys=True).encode("utf-8"))
    payload_b64 = _b64url_encode_no_pad(json.dumps(payload_obj, separators=(",", ":"), sort_keys=True).encode("utf-8"))

    signing_input = f"{header_b64}.{payload_b64}"
    sig = hmac.new(secret.encode("utf-8"), signing_input.encode("utf-8"), hashlib.sha256).digest()
    sig_b64 = _b64url_encode_no_pad(sig)

    return f"{signing_input}.{sig_b64}"

Why Not Just Prompt An LLM Directly?

  • Specs are versionable: real Python in your repo, not ephemeral chat history.
  • Incremental rebuilds: Jaunt hashes specs and only regenerates what's stale.
  • Dependency ordering: specs can depend on other specs; Jaunt builds a DAG and generates in the right order.
  • Runtime forwarding: import your spec module and call it like normal Python; the @jaunt.magic decorator handles the rest.

Start Here

Next: Quickstart.

On this page