# What generated code looks like

This page shows the code `truewire generate` writes, so you can decide whether to depend on it before you run anything. Every block below is quoted verbatim from `examples/github`, the GitHub REST client that CI keeps green in both languages, and every block is marked **generated** or **hand-written**. Where a file is trimmed, the commentary says what was left out.

The shape is the same in both languages. A spec directory becomes one module per endpoint, one router class per directory, one root class, and one module of shared record types. The generated code carries the HTTP method, the path template, the request and response types and the docstrings. Everything that touches the network lives in a core you write once, and the generated code reaches it through one call.

## One endpoint, Python

`src/github/repos/list_commits.py`, complete. **Generated.**

```python
# Generated by truewire — do not edit by hand.
from truewire_core import PaginatedResponse
from truewire_core.types import TimestampIso
from typing_extensions import Any, Literal, NotRequired, TypedDict, overload
from github.core import Endpoint
from github.schemas import Commit


class Request(TypedDict):
  """Which repository, an optional filter, and which page."""

  owner: str
  """Account owner of the repository, case-insensitive."""
  repo: str
  """Repository name without the `.git` extension, case-insensitive."""
  sha: NotRequired[str]
  """Branch name or commit sha to start from; the default branch when omitted."""
  path: NotRequired[str]
  """Only commits touching this file path."""
  author: NotRequired[str]
  """Only commits by this GitHub login or email."""
  since: NotRequired[TimestampIso]
  """Only commits after this instant."""
  until: NotRequired[TimestampIso]
  """Only commits before this instant."""
  per_page: NotRequired[int]
  """Results per page, at most 100."""
  page: NotRequired[int]
  """Page number of the results to fetch, starting at 1."""


Commits = list[Commit]


class ListCommits(Endpoint):
  """List commits reachable from a branch or sha, newest first. Pages are joined by `page`/`per_page`; the generated `list_commits_paged` walks them until a short page."""

  @overload
  def list_commits_paged(
    self,
    *,
    owner: str,
    repo: str,
    sha: str | None = None,
    path: str | None = None,
    author: str | None = None,
    since: TimestampIso | None = None,
    until: TimestampIso | None = None,
    per_page: int | None = None,
    validate: Literal[False],
  ) -> PaginatedResponse[Any, int]: ...
  @overload
  def list_commits_paged(
    self,
    *,
    owner: str,
    repo: str,
    sha: str | None = None,
    path: str | None = None,
    author: str | None = None,
    since: TimestampIso | None = None,
    until: TimestampIso | None = None,
    per_page: int | None = None,
    validate: bool | None = None,
  ) -> PaginatedResponse[Commit, int]: ...
  def list_commits_paged(
    self,
    *,
    owner: str,
    repo: str,
    sha: str | None = None,
    path: str | None = None,
    author: str | None = None,
    since: TimestampIso | None = None,
    until: TimestampIso | None = None,
    per_page: int | None = None,
    validate: bool | None = None,
  ) -> PaginatedResponse[Commit, int]:
    """List commits reachable from a branch or sha, newest first. Pages are joined by `page`/`per_page`; the generated `list_commits_paged` walks them until a short page.

    Paged variant of `list_commits`: Awaitable (flattens every page) or async-iterable (one page at a time).

    Args:
      owner: Account owner of the repository, case-insensitive.
      repo: Repository name without the `.git` extension, case-insensitive.
      sha: Branch name or commit sha to start from; the default branch when omitted.
      path: Only commits touching this file path.
      author: Only commits by this GitHub login or email.
      since: Only commits after this instant.
      until: Only commits before this instant.
      per_page: Results per page, at most 100.
      validate: Override this call's response validation; falls back to the client-level default when omitted. `False` returns the parsed body as it came, typed `Any`.

    References:
      - [Official docs](https://docs.github.com/en/rest/commits/commits#list-commits)
    """

    async def next(page: int) -> tuple[list[Commit], int | None]:
      response = await self.list_commits(
        owner=owner,
        repo=repo,
        sha=sha,
        path=path,
        author=author,
        since=since,
        until=until,
        per_page=per_page,
        page=page,
        validate=validate,
      )
      rows = response
      rows = list(rows) if rows is not None else []
      if not rows or len(rows) < (per_page if per_page is not None else 30):
        return rows, None
      return rows, page + 1

    return PaginatedResponse(1, next)

  @overload
  async def list_commits(
    self,
    *,
    owner: str,
    repo: str,
    sha: str | None = None,
    path: str | None = None,
    author: str | None = None,
    since: TimestampIso | None = None,
    until: TimestampIso | None = None,
    per_page: int | None = None,
    page: int | None = None,
    validate: Literal[False],
  ) -> Any: ...
  @overload
  async def list_commits(
    self,
    *,
    owner: str,
    repo: str,
    sha: str | None = None,
    path: str | None = None,
    author: str | None = None,
    since: TimestampIso | None = None,
    until: TimestampIso | None = None,
    per_page: int | None = None,
    page: int | None = None,
    validate: bool | None = None,
  ) -> Commits: ...
  async def list_commits(
    self,
    *,
    owner: str,
    repo: str,
    sha: str | None = None,
    path: str | None = None,
    author: str | None = None,
    since: TimestampIso | None = None,
    until: TimestampIso | None = None,
    per_page: int | None = None,
    page: int | None = None,
    validate: bool | None = None,
  ) -> Commits:
    """List commits reachable from a branch or sha, newest first. Pages are joined by `page`/`per_page`; the generated `list_commits_paged` walks them until a short page.

    Args:
      owner: Account owner of the repository, case-insensitive.
      repo: Repository name without the `.git` extension, case-insensitive.
      sha: Branch name or commit sha to start from; the default branch when omitted.
      path: Only commits touching this file path.
      author: Only commits by this GitHub login or email.
      since: Only commits after this instant.
      until: Only commits before this instant.
      per_page: Results per page, at most 100.
      page: Page number of the results to fetch, starting at 1.
      validate: Override this call's response validation; falls back to the client-level default when omitted. `False` returns the parsed body as it came, typed `Any`.

    References:
      - [Official docs](https://docs.github.com/en/rest/commits/commits#list-commits)
    """
    request: Request = Request(owner=owner, repo=repo)
    if sha is not None:
      request['sha'] = sha
    if path is not None:
      request['path'] = path
    if author is not None:
      request['author'] = author
    if since is not None:
      request['since'] = since
    if until is not None:
      request['until'] = until
    if per_page is not None:
      request['per_page'] = per_page
    if page is not None:
      request['page'] = page
    return await self.request(
      request,
      method='GET',
      path='/repos/{owner}/{repo}/commits',
      meta={'public': True},
      validate=validate,
      request_type=Request,
      response_type=Commits,
    )
```

`Request` is the spec's request schema as a `TypedDict`: required fields are plain, optional ones are `NotRequired`, and every field keeps the description the spec gave it. `Commits` is the response type, a list of the shared `Commit` record. The `since` and `until` fields are `TimestampIso`, the runtime's alias for an aware `datetime` that dumps to the wire as an ISO string.

`list_commits` takes keyword arguments only, builds the request from the arguments that were passed, and hands one call to `self.request`: the method, the path template with its `{owner}` and `{repo}` placeholders, the endpoint's declared `meta`, and the two types. The response comes back as `Commits` and is validated against that type by default; `validate=False` on a call, or `validate=False` on the client, returns the parsed JSON as it came. The two `@overload` stubs above the method are what make the annotation honest about that: see [`validate=False` returns the raw body](#validatefalse-returns-the-raw-body) below.

`list_commits_paged` exists because `endpoint.json` declares a `pagination` block: strategy `page`, index parameter `page` starting at 1, size parameter `per_page`, done on a short page. The generator renders that declaration as a `next(page)` closure that calls the plain method and returns the rows plus the next index, or `None` when the page came back shorter than `per_page` (30 when omitted, the spec's default). `PaginatedResponse(1, next)` is the runtime's walker. Awaited, it flattens every page into one list. Iterated with `async for`, it yields one page at a time. `next` depends on nothing but its `page` argument, so a page can be retried and a walk resumed.

The docstrings are the spec's `description` fields: the endpoint's on the class and both methods, each property's under `Args`, and the endpoint's `docs` URL under `References`. Nothing in the docstrings was written by hand, and nothing in them can drift from the spec without `truewire generate` rewriting it.

## The same endpoint, TypeScript

`src/github/repos/list_commits.ts`, complete. **Generated.**

```ts
// Generated by truewire — do not edit by hand.
import { type CallOptions, type Codec, type HttpEndpoint, PaginatedResponse, type TimestampIso, t } from '@truewire/core'
import type { DefaultMeta } from '../meta.js'
import { Commit } from '../types/index.js'

/** Which repository, an optional filter, and which page. */
export interface Request {
  /** Account owner of the repository, case-insensitive. */
  owner: string
  /** Repository name without the `.git` extension, case-insensitive. */
  repo: string
  /** Branch name or commit sha to start from; the default branch when omitted. */
  sha?: string
  /** Only commits touching this file path. */
  path?: string
  /** Only commits by this GitHub login or email. */
  author?: string
  /** Only commits after this instant. */
  since?: TimestampIso
  /** Only commits before this instant. */
  until?: TimestampIso
  /** Results per page, at most 100. */
  per_page?: number
  /** Page number of the results to fetch, starting at 1. */
  page?: number
}

export const Request: Codec<Request> = t.object({
  owner: t.string,
  repo: t.string,
  sha: t.optional(t.string),
  path: t.optional(t.string),
  author: t.optional(t.string),
  since: t.optional(t.dateTime),
  until: t.optional(t.dateTime),
  per_page: t.optional(t.integer),
  page: t.optional(t.integer),
})

export type Commits = Commit[]

export const Commits: Codec<Commits> = t.array(Commit)

/** `listCommitsPaged`'s request: `Request` without `page`, which the walk advances. */
export type ListCommitsPagedRequest = Omit<Request, 'page'>

/** List commits reachable from a branch or sha, newest first. Pages are joined by `page`/`per_page`; the generated `list_commits_paged` walks them until a short page. */
export class ListCommits {
  constructor(readonly core: HttpEndpoint<DefaultMeta>) {}

  /** With `validate: false`: the parsed body as it came, typed `unknown`. */
  listCommitsPaged(request: ListCommitsPagedRequest, options: CallOptions & { validate: false }): PaginatedResponse<unknown, number>
  /**
   * List commits reachable from a branch or sha, newest first. Pages are joined by `page`/`per_page`; the generated `list_commits_paged` walks them until a short page.
   *
   * Paged variant of `listCommits`: awaitable (flattens every page) or async-iterable (one page at a time).
   *
   * @see https://docs.github.com/en/rest/commits/commits#list-commits
   */
  listCommitsPaged(request: ListCommitsPagedRequest, options?: CallOptions): PaginatedResponse<Commit, number>
  listCommitsPaged(request: ListCommitsPagedRequest, options?: CallOptions): PaginatedResponse<Commit, number> {
    const next = async (page: number): Promise<[Commit[], number | null]> => {
      const response = await this.listCommits({ ...request, page }, options)
      const rows = response
      if (rows.length === 0 || rows.length < (request.per_page ?? 30)) return [rows, null]
      return [rows, page + 1]
    }
    return new PaginatedResponse(1, next)
  }

  /** With `validate: false`: the parsed body as it came, typed `unknown`. */
  listCommits(request: Request, options: CallOptions & { validate: false }): Promise<unknown>
  /**
   * List commits reachable from a branch or sha, newest first. Pages are joined by `page`/`per_page`; the generated `list_commits_paged` walks them until a short page.
   *
   * @see https://docs.github.com/en/rest/commits/commits#list-commits
   */
  listCommits(request: Request, options?: CallOptions): Promise<Commits>
  async listCommits(request: Request, options?: CallOptions): Promise<Commits> {
    return this.core.request({
      method: 'GET',
      path: '/repos/{owner}/{repo}/commits',
      request,
      requestCodec: Request,
      responseCodec: Commits,
      meta: { public: true },
      ...options,
    })
  }
}
```

The request is an `interface` and, under the same name, a codec. `Codec<Request>` on the constant makes `tsc` prove that the two agree, so the type and the validator cannot diverge. The response is `Commits = Commit[]` beside `t.array(Commit)`. Keys the API named stay verbatim (`per_page`, `html_url`), so the request object is the wire object and a recorded `request.json` is a valid argument as it stands. Names Truewire invents are camelCase: `listCommits`, `listCommitsPaged`, `ListCommitsPagedRequest`.

The class takes its core as a constructor argument typed `HttpEndpoint<DefaultMeta>`, an interface from `@truewire/core` that anything with a matching `request` method satisfies by shape. `listCommits` passes the method, the path, the request, both codecs and the `meta`, and spreads the caller's options (`validate`, `signal`) over them. The two signatures above each method are overloads, `validate: false` first; the section below says why. The paged variant is the same walker as in Python, with the same short-page rule and the same `PaginatedResponse`, which is awaitable and async-iterable.

## `validate=False` returns the raw body

A generated method returns the parsed record: `datetime`s, `Decimal`s, literal unions, in both languages. That is true only when the reply was validated. `validate=False` on a call skips validation and returns the body as the wire sent it, so a single annotation of `-> Commits` would lie for that call. The generator says so instead, with one overload per outcome, and the runtime is unchanged.

In Python, every request/reply method and every `_paged` walker carries two `@overload` stubs above its implementation. `validate: Literal[False]` returns `Any` (a walker returns `PaginatedResponse[Any, int]` or `AsyncIterator[Any]`, its state type kept). `validate: bool | None = None`, the default, returns the declared type: `None` defers to the client, and a flag decided elsewhere is the caller's own decision, which is also what lets the walkers forward one. The implementation keeps the same header.

```python
repo = await client.repos.get(owner='truewire-dev', repo='truewire')                  # Repository
raw = await client.repos.get(owner='truewire-dev', repo='truewire', validate=False)   # Any
rows = client.repos.list_commits_paged(owner='truewire-dev', repo='truewire', validate=False)  # PaginatedResponse[Any, int]
```

In TypeScript, the same method carries two overload signatures, `validate: false` first because declaration order decides and `CallOptions` would otherwise match it. `options: CallOptions & { validate: false }` returns `Promise<unknown>` (a walker `PaginatedResponse<unknown, number>`); `options?: CallOptions` returns the declared type, so `true`, an omitted option or a `boolean` variable resolve to it. Routers delegate both.

```ts
const repo = await client.repos.get(where)                       // Repository
const raw = await client.repos.get(where, { validate: false })   // unknown
```

`examples/github/test/typing_usage.py` and `typing_usage.ts` hold these assertions (`reveal_type(..., expected_text=...)` for pyright, `expectTypeOf` for `tsc`), and are checked, never run.

## The router and the root

`src/github/repos/__init__.py`, complete. **Generated.**

```python
# Generated by truewire — do not edit by hand.
from .get import Get
from .get_commit import GetCommit
from .list_commits import ListCommits
from .list_releases import ListReleases
from .list_tags import ListTags


class Repos(Get, GetCommit, ListCommits, ListReleases, ListTags):
  """Repositories: metadata, commits, tags and releases.

  References:
    - [Upstream docs](https://docs.github.com/en/rest/repos)
  """
```

`src/github/main.py`, complete. **Generated.**

```python
# Generated by truewire — do not edit by hand.
from functools import cached_property
from .issues import Issues
from .repos import Repos
from github.core import ClientBase


class GitHub(ClientBase):
  """GitHub REST API, repository-scoped endpoints: repositories, commits, tags, releases and issues. Every recorded example is a live capture from api.github.com against truewire-dev/truewire.

  References:
    - [Upstream docs](https://docs.github.com/en/rest)
  """

  @cached_property
  def issues(self) -> Issues:
    """Issues and, through the same list, pull requests.

    References:
      - [Upstream docs](https://docs.github.com/en/rest/issues)
    """
    return Issues(client=self.client)

  @cached_property
  def repos(self) -> Repos:
    """Repositories: metadata, commits, tags and releases.

    References:
      - [Upstream docs](https://docs.github.com/en/rest/repos)
    """
    return Repos(client=self.client)
```

`ClientBase.new`, from `src/github/core/__init__.py`. **Hand-written.**

```python
@dataclass(kw_only=True)
class ClientBase:
  """Root client: owns the transport every endpoint shares."""
  client: Transport

  @classmethod
  def new(cls, *, base_url: str = 'https://api.github.com', api_key: str | None = None, validate: bool = True) -> Self:
    """Create a client against `base_url`."""
    return cls(client=Transport(base_url=base_url, api_key=api_key, validate=validate))

  async def __aenter__(self) -> Self:
    return self

  async def __aexit__(self, exc_type, exc_value, traceback):
    await self.client.http.__aexit__(exc_type, exc_value, traceback)
```

A Python router is a class that inherits every endpoint class in its directory, so `client.repos.list_commits` is ordinary method resolution and there is no delegation code to read. The root class holds one `Transport` and gives it to each router through a `cached_property`. `new` is not generated. It is a classmethod on the hand-written base, so the default `base_url`, the credential parameter and the validation default are the project's decisions, and `GitHub.new(base_url=...)` is how the tests point the same client at the mock.

`src/github/repos/index.ts`, trimmed to the constructor and the two `listCommits` delegates; the `get`, `getCommit`, `listReleases` and `listTags` delegates have the same shape. **Generated.**

```ts
// Generated by truewire — do not edit by hand.
import type { CallOptions, HttpEndpoint, PaginatedResponse } from '@truewire/core'
import type { DefaultMeta } from '../meta.js'
import type { Commit } from '../types/index.js'
import * as get from './get.js'
import * as getCommit from './get_commit.js'
import * as listCommits from './list_commits.js'
import * as listReleases from './list_releases.js'
import * as listTags from './list_tags.js'

/**
 * Repositories: metadata, commits, tags and releases.
 *
 * @see https://docs.github.com/en/rest/repos
 */
export class Repos {
  private readonly get_: get.Get
  private readonly getCommit_: getCommit.GetCommit
  private readonly listCommits_: listCommits.ListCommits
  private readonly listReleases_: listReleases.ListReleases
  private readonly listTags_: listTags.ListTags

  constructor(readonly core: HttpEndpoint<DefaultMeta>) {
    this.get_ = new get.Get(core)
    this.getCommit_ = new getCommit.GetCommit(core)
    this.listCommits_ = new listCommits.ListCommits(core)
    this.listReleases_ = new listReleases.ListReleases(core)
    this.listTags_ = new listTags.ListTags(core)
  }

  /** With `validate: false`: the parsed body as it came, typed `unknown`. */
  listCommitsPaged(request: listCommits.ListCommitsPagedRequest, options: CallOptions & { validate: false }): PaginatedResponse<unknown, number>
  /**
   * List commits reachable from a branch or sha, newest first. Pages are joined by `page`/`per_page`; the generated `list_commits_paged` walks them until a short page.
   *
   * Paged variant of `listCommits`: awaitable (flattens every page) or async-iterable (one page at a time).
   *
   * @see https://docs.github.com/en/rest/commits/commits#list-commits
   */
  listCommitsPaged(request: listCommits.ListCommitsPagedRequest, options?: CallOptions): PaginatedResponse<Commit, number>
  listCommitsPaged(request: listCommits.ListCommitsPagedRequest, options?: CallOptions): PaginatedResponse<Commit, number> {
    return this.listCommits_.listCommitsPaged(request, options)
  }

  /** With `validate: false`: the parsed body as it came, typed `unknown`. */
  listCommits(request: listCommits.Request, options: CallOptions & { validate: false }): Promise<unknown>
  /**
   * List commits reachable from a branch or sha, newest first. Pages are joined by `page`/`per_page`; the generated `list_commits_paged` walks them until a short page.
   *
   * @see https://docs.github.com/en/rest/commits/commits#list-commits
   */
  listCommits(request: listCommits.Request, options?: CallOptions): Promise<listCommits.Commits>
  listCommits(request: listCommits.Request, options?: CallOptions): Promise<listCommits.Commits> {
    return this.listCommits_.listCommits(request, options)
  }
}
```

`src/github/main.ts`, complete. **Generated.**

```ts
// Generated by truewire — do not edit by hand.
import type { HttpEndpoint } from '@truewire/core'
import { Issues } from './issues/index.js'
import type { DefaultMeta } from './meta.js'
import { Repos } from './repos/index.js'

/**
 * GitHub REST API, repository-scoped endpoints: repositories, commits, tags, releases and issues. Every recorded example is a live capture from api.github.com against truewire-dev/truewire.
 *
 * @see https://docs.github.com/en/rest
 */
export class GitHub {
  /** Issues and, through the same list, pull requests. */
  readonly issues: Issues
  /** Repositories: metadata, commits, tags and releases. */
  readonly repos: Repos

  constructor(readonly core: HttpEndpoint<DefaultMeta>) {
    this.issues = new Issues(core)
    this.repos = new Repos(core)
  }
}
```

`CoreOptions` and the `Core` constructor, from `src/github/core/index.ts`. **Hand-written.**

```ts
export interface CoreOptions {
  /** Defaults to `https://api.github.com`; point it at `truewire mock` in tests. */
  baseUrl?: string
  /** A token, sent as `Authorization: Bearer` (public endpoints accept it too, and it raises the rate limit). */
  token?: string
  /** Validate responses by default; a call's own `validate` option overrides it. */
  validate?: boolean
  /** The `fetch` wrapper to send through; one is made when omitted. */
  http?: HttpClient
}

/** The shared HTTP transport: base URL, GitHub's headers, the optional token and error mapping. */
export class Core implements HttpEndpoint<DefaultMeta> {
  readonly baseUrl: string
  readonly token: string | undefined
  readonly validate: boolean
  readonly http: HttpClient

  constructor(options: CoreOptions = {}) {
    this.baseUrl = (options.baseUrl ?? 'https://api.github.com').replace(/\/+$/, '')
    this.token = options.token
    this.validate = options.validate ?? true
    this.http = options.http ?? new HttpClient()
  }
```

TypeScript has no multiple inheritance, so a router holds one instance per endpoint and delegates, repeating each method's signature and docstring so the editor shows them at the call site. The root class takes the core in its constructor: `new GitHub(new Core({ token }))`. There is no `new` to generate because the core's constructor is that function, and it is yours.

## The hand-written core

`Endpoint`, from `src/github/core/__init__.py`. `Transport`, above it in the file, holds the base URL, the headers and `send`; `ClientBase` is quoted above. **Hand-written.**

```python
@dataclass(kw_only=True, frozen=True)
class Endpoint:
  """Base for every generated endpoint class: one shared transport."""
  client: Transport

  async def request(
    self, request: Any = None, *, method: str, path: str,
    validate: bool | None = None,
    request_type: type[Any] | UnionType | None = None,
    response_type: type[T] | UnionType | None = None,
    meta: Meta = {},
  ) -> T:
    """Send one request and validate the reply against `response_type`."""
    params = {k: v for k, v in dict(request or {}).items() if v is not None}
    body = None
    if method.upper() in ('POST', 'PUT', 'PATCH') and request_type is not None and request is not None:
      body = validator(cast(type, request_type)).dump(request)
      params = {}
    raw = await self.client.send(method, path, params=params, body=body, public=bool(meta.get('public')))
    if response_type is None:
      return None  # type: ignore[return-value]
    check = self.client.validate if validate is None else validate
    if check:
      return validator(cast(type, response_type)).json(raw)
    import json
    return json.loads(raw)
```

`Core.request`, from `src/github/core/index.ts`. The `headers` method and the `query` and `mapError` helpers are omitted. **Hand-written.**

```ts
  /** Send one request; the decoded reply, validated unless `validate` is off. */
  async request<Req, Res>(call: HttpCall<Req, Res, DefaultMeta>): Promise<Res> {
    const wire: Record<string, unknown> =
      call.request !== undefined && call.requestCodec !== undefined
        ? (call.requestCodec.dump(call.request) as Record<string, unknown>)
        : {}
    let path = call.path
    const params: Record<string, unknown> = {}
    for (const [name, value] of Object.entries(wire)) {
      if (value === undefined) continue
      const placeholder = `{${name}}`
      if (path.includes(placeholder)) path = path.split(placeholder).join(encodeURIComponent(String(value)))
      else params[name] = value
    }
    const method = (call.method ?? 'GET').toUpperCase()
    const withBody = method === 'POST' || method === 'PUT' || method === 'PATCH'
    const response = await this.http.request(method, `${this.baseUrl}/${path.replace(/^\/+/, '')}`, {
      query: withBody ? undefined : query(params),
      json: withBody ? params : undefined,
      headers: this.headers(call.meta),
      signal: call.signal,
    })
    const text = await response.text()
    if (response.status >= 400) throw mapError(method, path, response, text)
    if (call.responseCodec === undefined) return undefined as Res
    if (call.validate ?? this.validate) return parseJson(call.responseCodec, text)
    return JSON.parse(text) as Res
  }
```

This is the only place that knows how to reach GitHub: the media type header, the API version, the bearer token, the placeholder filling, the query encoding, and which statuses become which errors. The generated code never imports it in TypeScript; it names an interface and receives an object. In Python, `truewire.toml` says which class each generated class extends (`[python.cores.default] base = "github.core:Endpoint"`, `[python.cores.root] base = "github.core:ClientBase"`), and the generator never imports your package to find out (ADR 0011). Validation happens here too: the core reads the per-call `validate`, falls back to its own default, and runs the runtime's validator over the raw bytes against the type the generated call passed.

Ownership is explicit. `.truewire/python-files.json` lists the ten files the generator wrote; `core/` is not among them, so regeneration never touches it. `truewire init` scaffolds this core for a new project, and the example's differs from the scaffold in two places: the `headers` method and the default `base_url`.

## One shared record

`GitActor` and `Commit`, from `src/github/schemas.py`. **Generated.**

```python
class GitActor(TypedDict):
  """The author or committer recorded in the git object."""

  name: str
  """Name recorded in the commit."""
  email: str
  """Email recorded in the commit."""
  date: TimestampIso
  """When the commit was authored or committed."""


class Commit(TypedDict):
  """A commit on the repository, as listed."""

  sha: str
  """Commit sha."""
  node_id: NotRequired[str]
  """GraphQL node id."""
  html_url: NotRequired[str]
  """Web page of the commit."""
  commit: GitCommit
  author: NotRequired[SimpleUser | None]
  """GitHub account matched to the author, when known."""
  committer: NotRequired[SimpleUser | None]
  """GitHub account matched to the committer, when known."""
  parents: list[CommitRef]
  """Parent commits."""
```

The same two, from `src/github/types/index.ts`. **Generated.**

```ts
/** The author or committer recorded in the git object. */
export interface GitActor {
  /** Name recorded in the commit. */
  name: string
  /** Email recorded in the commit. */
  email: string
  /** When the commit was authored or committed. */
  date: TimestampIso
}

export const GitActor: Codec<GitActor> = t.object({
  name: t.string,
  email: t.string,
  date: t.dateTime,
})

/** A commit on the repository, as listed. */
export interface Commit {
  /** Commit sha. */
  sha: string
  /** GraphQL node id. */
  node_id?: string
  /** Web page of the commit. */
  html_url?: string
  commit: GitCommit
  /** GitHub account matched to the author, when known. */
  author?: SimpleUser | null
  /** GitHub account matched to the committer, when known. */
  committer?: SimpleUser | null
  /** Parent commits. */
  parents: CommitRef[]
}

export const Commit: Codec<Commit> = t.object({
  sha: t.string,
  node_id: t.optional(t.string),
  html_url: t.optional(t.string),
  commit: GitCommit,
  author: t.optional(t.nullable(SimpleUser)),
  committer: t.optional(t.nullable(SimpleUser)),
  parents: t.array(CommitRef),
})
```

Both come from `spec/schemas.json`, which holds the shapes two or more endpoints share. A field that may be absent is `NotRequired` or `?`; a field that may be `null` says `| None` or `| null`; the two are distinct because the wire distinguishes them. An enum is a `Literal` or a union of string literals. `date: TimestampIso` is an aware `datetime` in Python and a `Date` in TypeScript, parsed from the ISO string the API sends, and the paging tests assert exactly that on every commit they walk. In TypeScript, a codec's `parse` names the JSON pointer of the first field that does not match, and `dump` renders the typed value back to the recorded payload; `codecs.test.ts` checks both against the recordings, the pointer being `/owner/id` when a repository's owner carries a string id.

## What the tests replay

The `list_commits` examples are one real walk recorded from `api.github.com`: `page1` through `page4` with `per_page: 3`, pinned through `sha` to the 0.1.0 release commit so that re-recording yields the same eleven commits. `test/test_paging.py` drives the generated walker against `truewire mock` serving those four files. **Hand-written.**

```python
RELEASE_0_1_0 = '934a718509b0cfd1244db90821201afbbb728797'
"""The walks start from a fixed commit so re-recording them yields the same pages."""


@pytest.mark.asyncio
async def test_commits_walk_ends_on_the_short_fourth_page(client):
  """Eleven commits at three per page: three full pages, then a page of two."""
  async with client:
    pages = [
      page
      async for page in client.repos.list_commits_paged(
        owner='truewire-dev', repo='truewire', sha=RELEASE_0_1_0, per_page=3,
      )
    ]
  assert [len(page) for page in pages] == [3, 3, 3, 2]
  shas = [commit['sha'] for page in pages for commit in page]
  assert len(set(shas)) == 11
  for page in pages:
    for commit in page:
      assert commit['commit']['author']['date'].tzinfo is not None


```

The mock serves page N only for the exact `page` and `per_page` the walk sends, so a walker that computed the wrong next index would get a 422, not a quietly short list. `test/paging.test.ts` runs the same walk through the TypeScript client. `test/test_examples_replay.py` and `test/replay.test.ts` replay every recorded example in `spec/endpoints/**/examples/` through the real generated method, with validation on, so the types are proven against the responses the API actually sent.

## Reproduce it

```sh
pip install truewire
truewire init github
cd github
truewire import registry github     # spec/, examples and the [cores.default] meta declaration
truewire generate python            # src/github/**/*.py
truewire generate typescript        # src/github/**/*.ts, after adding [typescript] to truewire.toml
```

`truewire init` names the root class `Github`; the example sets `name = "GitHub"` under `[python]` and `[typescript]`. `truewire init` also writes the scaffold core; edit `headers` and the default `base_url` as the example does, and for TypeScript write `src/github/core/index.ts` against `HttpEndpoint<DefaultMeta>`. The example's `truewire.toml`, `package.json` and `test/` are what to copy. The two test suites run from `examples/github`, against the repository's own environment:

```sh
PYTHONPATH=src ../../.venv/bin/python -m pytest -q
yarn test
```

The second needs `packages/core-ts` built (`yarn build`) and the example installed (`yarn install`), because `@truewire/core` is a `file:` dependency until it is on npm.
