Metadata-Version: 2.5
Name: laconic
Version: 0.14.0
Summary: A context-loop codec for coding agents
Project-URL: Documentation, https://github.com/Mathews-Tom/Laconic/tree/main/docs
Project-URL: Repository, https://github.com/Mathews-Tom/Laconic
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.12
Requires-Dist: tree-sitter-go==0.23.4
Requires-Dist: tree-sitter-javascript==0.23.1
Requires-Dist: tree-sitter-python==0.23.2
Requires-Dist: tree-sitter-rust==0.23.2
Requires-Dist: tree-sitter-typescript==0.23.2
Requires-Dist: tree-sitter==0.23.2
Requires-Dist: zstandard>=0.25.0
Description-Content-Type: text/markdown

# Laconic

**Carry less context. Keep every byte.**

Laconic sits at your agent's tool boundary and replaces bulky tool results with a structural outline plus the lines that were actually asked for — while keeping the exact original bytes on disk, addressable, until you say otherwise.

[![PyPI](https://img.shields.io/pypi/v/laconic)](https://pypi.org/project/laconic/)
[![Python](https://img.shields.io/pypi/pyversions/laconic)](https://pypi.org/project/laconic/)
[![CI](https://github.com/Mathews-Tom/laconic/actions/workflows/ci.yml/badge.svg)](https://github.com/Mathews-Tom/laconic/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)

[Product showcase](https://mathews-tom.github.io/laconic/) · [Frozen self-use evidence](https://mathews-tom.github.io/laconic/evidence/) · [Methodology and limitations](https://mathews-tom.github.io/laconic/methodology/)

**Source release:** `v0.14.0` (Beta). Ordinary-use evidence collection continues; generic MCP runtime support remains on HOLD under its frozen evidence gate.

```bash
uv tool install laconic
laconic setup
```

Done. No provider configuration, no proxy, no API key, no account.

## See it work

Your agent reads a 745-line file and wants the `Record` class. Here is what actually lands in its context — real output from Laconic's own codec on its own ledger module:

```text
[laconic 01a0f3c2-.../F1 | full: laconic_expand({"reference":"01a0f3c2-.../F1"})]
src/laconic/ledger.py  745 lines
  outline: UnknownHandleError:150-159  __str__:153-159  InvalidSpanError:162-163
    _select_lines:166-179  ObservationKind:182-189  Record:193-212
    raw_chars:207-208  encoded_chars:211-212  [+30 more]
  span 193-212:
    class Record:
        """One observation, stored whole, surfaced partially."""

        handle: str
        kind: ObservationKind
        subject: str
        content_sha: str
        raw: str
        encoded: str
        created_at: float
        turn: int
        resident: bool

        @property
        def raw_chars(self) -> int:
            return len(self.raw)
```

**29,186 characters in, 810 out — 97% fewer characters at the tool boundary.** The agent still sees the shape of the whole file, gets the exact lines it asked for verbatim, and can pull any other part back by itself, mid-task, without asking you. The handle is right there on the first line.

With no requested span, the complete recovery-bearing envelope is 313 characters and contains only the structural outline.

## How it works

Laconic is closer to a claim ticket than a trash compactor. The model carries a short handle and the useful part of a result; the complete original stays in a private local ledger.

```mermaid
flowchart TB
    RESULT["Successful text tool result"] --> ADAPTER["Host adapter"]
    ADAPTER --> RUNTIME["Canonical Python runtime"]
    RUNTIME --> CODEC["Tool-shaped encoder"]
    CODEC --> LEDGER[("Private session ledger")]
    LEDGER --> CHECK{"Exact recovery succeeds and the full envelope is smaller"}
    CHECK -->|"yes"| ENVELOPE["Model sees the envelope and handle"]
    CHECK -->|"no"| ORIGINAL["Model sees the original result"]
    ENVELOPE --> EXPAND["Agent expands exact full text or a line span"]
```

1. The host adapter intercepts an eligible successful text result. Tool errors, mixed content, unsupported tools and malformed responses remain unchanged.
2. The shared runtime selects a file, command or search encoder. File results retain structure and requested lines; command and search results retain boundaries and salient errors.
3. The encoder commits the exact raw result to the session ledger before returning a candidate.
4. The runtime immediately expands the reference and compares the complete envelope with the original. Recovery mismatch or no size win means pass-through.
5. The model receives either the smaller envelope or the untouched original. Any omitted content remains available through the handle.

OMP and Claude Code use different host adapters but share this decision path. Compression policy, reference minting, recovery and storage are not reimplemented per host.

## What you get

### Nothing is ever lost

The raw result commits to a local ledger **before** a replacement is allowed to exist. Every reference expands exactly — byte for byte, including code points a strict encoder would reject.

```bash
laconic expand '<session>/X1'          # the whole thing, exactly
laconic expand '<session>/X1:40-90'    # just those lines
```

This is why reducing a file read is safe here at all. Headroom's default coding profile, for instance, deliberately protects reads from compression — its own source explains that an agent needs exact bytes to patch a file. Laconic stores those exact bytes first and then reduces what the model carries, which is a different answer to the same constraint rather than a claim to be the only one. [`docs/headroom-comparison.md`](docs/headroom-comparison.md) sets out where each fits.

### Structure, not truncation

File reads come back as a tree-sitter outline plus the span that was requested, so the agent sees the file's shape rather than a guillotined prefix.

Command and search output take the other route — head and tail are kept, the middle is elided, and **lines that look like errors are lifted out of the elided region and preserved**, because a traceback buried in the middle of ten thousand lines of build log is the last thing you want silently dropped.

### It only fires when it wins

A replacement is emitted only when the complete envelope — handle, header and all — is strictly smaller than the original. In qualification it passed **90 of 162** eligible observations straight through untouched. Small results stay small. Nothing is compressed to look busy.

### It fails open, in every direction

Engine missing, spawn failure, crash, malformed response, deadline breach, storage error — you get your original tool result. There is a 250 ms steady-state deadline and a three-consecutive-failure circuit breaker. **A crash costs compression, never correctness.**

### Fast enough to forget about

**p50 2.16 ms. p95 19.87 ms.**

### Entirely yours

No telemetry. No hosted service. No beacon. Raw observations never leave your machine, and exactly one command in the whole tool touches the network — `laconic pricing update` — only when you type it.

Reports are content-free by construction and re-checked by an independent privacy gate before anything is written: a new field that cannot be certified fails loudly rather than shipping.

### You stay in control

```bash
laconic status                 # decisions, counts, storage, recovery ledger
/laconic pause                 # mid-session, from inside your agent
/laconic resume
laconic uninstall omp          # restore native behaviour; keeps your ledgers
laconic purge --older-than 30d # deleting data is a separate, deliberate act
```

## Works with your agent

```bash
laconic setup
```

`setup` detects what you actually have, installs what each host supports, and then tells you whether the codec has recorded a real decision — because installing a file is not proof anything ran.

| Host | Codec | Diagnostics | Covers |
| --- | :---: | :---: | --- |
| **OMP** | yes | yes | Native extension over `read`, `bash`, `grep`, `glob` |
| **Claude Code** | yes | yes | Transforming `PostToolUse` hook over `Bash` and `Read` |
| Codex | — | — | No adapter ships, and Laconic tells you so |

Both adapters are thin. They drive the same Python engine, so the strictly-smaller rule, the ledger, reference minting and exact recovery are shared — not reimplemented per host.

```bash
laconic setup --verify-only    # did it actually run?
```

## Know what your context costs

```bash
laconic savings
```

The command reads your local session billing metadata and reports:

- spend composition across uncached input, cache reads, cache writes and output;
- codec decisions joined to the sessions that carry priced turns;
- the modelled total for those same sessions; and
- a modelled avoided-cost band when the underlying pricing coverage is sufficient.

The result changes as your local session history grows, so this README does not freeze a sample dollar amount. `laconic savings` writes the complete assumptions and current figures to `.laconic/spend/` as canonical JSON, Markdown, and self-contained HTML.

### Offline evidence dashboard

`laconic savings` writes the same validated evidence as canonical JSON, Markdown, and a self-contained HTML dashboard. The HTML contains inline CSS and SVG only: no script, font, CDN, network request, telemetry, or server.

[![Synthetic Laconic evidence ledger preview](docs/demo/dashboard-preview.svg)](docs/demo/spend-composition.html)

The preview and linked dashboard are a **synthetic fixture**, not production evidence. They are generated from [`docs/demo/fixtures/evidence-ledger.json`](docs/demo/fixtures/evidence-ledger.json), carry the canonical JSON digest, and keep the modelled band adjacent to its `modelled_not_measured` basis and single-arm limitation. See [`docs/demo/README.md`](docs/demo/README.md) for regeneration and verification.

The avoided-cost result is deliberately a band and deliberately labelled. It is modelled from token counters, never billed by a provider, and every assumption remains attached to the report. When more than a quarter of the underlying cost comes from models with no published price, Laconic withholds the dollar figures and leads with the percentage instead. **We would rather show you less than show you something we cannot stand behind.**

## Commands

| Command | What it does |
| --- | --- |
| `laconic setup` | Detect hosts, install what each supports, verify the codec ran |
| `laconic status` | Content-free health: decisions, storage, expansions, last cost band |
| `laconic savings` | Spend composition plus the modelled avoided-cost band |
| `laconic expand REF[:A-B]` | Recover an elided observation exactly, whole or by line span |
| `laconic pricing show` \| `update` | Inspect or refresh model list prices |
| `laconic install` \| `uninstall HOST` | Manage a single host adapter |
| `laconic purge` | Delete recovery ledgers, explicitly |
| `laconic research ...` | Offline measurement, replay, evaluation |
| `laconic diagnostics observe ...` | Content-free local diagnostics |

## Documentation

| Document | What's in it |
| --- | --- |
| [`docs/omp-runtime.md`](docs/omp-runtime.md) | OMP install, interception boundary, recovery, controls, uninstall, purge |
| [`docs/claude-code-codec.md`](docs/claude-code-codec.md) | The Claude Code hook, its shape-fidelity constraint, measured limits |
| [`docs/system-design.md`](docs/system-design.md) | Architecture: engine, ledger, codec, price registry, protocol boundaries |
| [`docs/grounding.md`](docs/grounding.md) | What Laconic is, what it deliberately is not, and its invariants |
| [`docs/headroom-comparison.md`](docs/headroom-comparison.md) | Version-pinned comparison with Headroom, including where Headroom fits better |
| [`docs/overview.md`](docs/overview.md) | The measurement behind the design, and the positioning it forces |
| [`docs/research-disposition.md`](docs/research-disposition.md) | How Laconic got here: evidence, shipped tranches, and what stays unproven |
| [`docs/results/mcp-opportunity-disposition.json`](docs/results/mcp-opportunity-disposition.json) | Binding aggregate-only HOLD disposition for generic MCP runtime support |
| [`docs/observe-cli.md`](docs/observe-cli.md) | `laconic diagnostics observe`: content-free local diagnostics |
| [`docs/runtime-beta-report.md`](docs/runtime-beta-report.md) | The qualification campaign's generated report, committed verbatim |

Upgrading from 0.8.0 or earlier? Offline research commands moved under an explicit namespace: `laconic measure` and `laconic gates` are now `laconic research measure` and `laconic research gates`.

## What we don't claim

Laconic reduces characters at the tool boundary, and that is what it reports. It does not claim a general token, cost, cache, or behaviour saving, because the conversion from characters to tokens to money is lossy and workload-dependent and we do not have the paired evidence that would license it. Every session Laconic has recorded ran with the codec on, so there is no counterfactual to subtract.

What *is* measured is in [`docs/runtime-beta-report.md`](docs/runtime-beta-report.md), generated and committed verbatim: ten sessions, three repositories, 162 eligible observations, all 26 required failure and lifecycle scenarios exercised, every safety counter at zero, and 51.77% character reduction on that workload.

## Contributing

Read [`docs/grounding.md`](docs/grounding.md) first. It defines the product boundary and the invariants every change must preserve.

### Repository map

| Boundary | Responsibility | Start here |
| --- | --- | --- |
| CLI and setup | Detect hosts, install adapters, expose status, expansion and purge | `src/laconic/cli.py`, `src/laconic/setup.py` |
| Host adapters | Normalize supported tool results and fail open to native host behavior | `src/laconic/runtime/omp/laconic.ts`, `src/laconic/runtime/claude_code.py` |
| Runtime decision | Enforce tool eligibility, exact recovery and the strictly-smaller rule | `src/laconic/runtime/engine.py`, `src/laconic/runtime/protocol.py` |
| Observation codecs | Dispatch by tool shape and build file, command or search presentations | `src/laconic/codec/observe.py`, `src/laconic/codec/encoders/` |
| Recovery storage | Store exact raw observations, mint handles and expand full or ranged references | `src/laconic/ledger.py`, `src/laconic/runtime/storage.py` |
| Local reporting | Join content-free runtime decisions with usage and offline model prices | `src/laconic/spend/`, `src/laconic/pricing/` |

Keep host adapters thin. A decision that changes what reaches the model belongs in the canonical Python runtime or codec, not in a second host-specific implementation.

The repository also contains qualification and research infrastructure under `src/laconic/beta/`, `src/laconic/gates/`, `src/laconic/replay/` and `src/laconic/study/`. These packages measure or validate the product; they are not alternate runtime paths.

### Prove behavior at the consumer boundary

Trace changes through the layer that consumes them. For example, extending error-line recognition starts in `src/laconic/codec/encoders/_elision.py`, requires positive and negative classifier cases, and finishes with a consumer-visible `elide_middle` test proving that a matching line survives from the omitted middle. A regex-only assertion does not prove the user-visible contract.

### Run the local gate

```bash
uv sync --locked
bun install --frozen-lockfile
bun run typecheck
bun test
uv run ruff check .
uv run ruff format --check .
uv run mypy --strict src
uv run pytest -q
uv run laconic --help
uv run laconic --version
```

Development requires Python 3.12+, `uv` and Bun. CI also evaluates the committed recorded-response research fixtures; those checks make no live provider calls.

## License

Apache License 2.0 — see [LICENSE](LICENSE).
