Metadata-Version: 2.4
Name: tilth
Version: 0.2.0
Summary: Tilth — minimal long-running agent harness against any OpenAI-compatible endpoint. Brain/Hands/Session split, Ralph loop, four memory channels.
Project-URL: Homepage, https://github.com/AlteredCraft/tilth
Project-URL: Documentation, https://alteredcraft.github.io/tilth/
Project-URL: Repository, https://github.com/AlteredCraft/tilth
Project-URL: Issues, https://github.com/AlteredCraft/tilth/issues
Author-email: Sam Keen <sam@alteredcraft.com>
License-Expression: MIT
License-File: LICENSE
Keywords: agent,agent-harness,autonomous-agents,llm,long-running-agents,openai-compatible,openrouter,ralph-loop
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Code Generators
Requires-Python: >=3.12
Requires-Dist: openai>=1.40
Requires-Dist: pydantic>=2.6
Requires-Dist: python-dotenv>=1.0
Requires-Dist: rich>=13.7
Provides-Extra: docs
Requires-Dist: mkdocs-glightbox>=0.4; extra == 'docs'
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocs>=1.6; extra == 'docs'
Description-Content-Type: text/markdown

# Tilth

> *Prepare the ground, let the agent grow the work.*

A minimal long-running agent harness against an **OpenAI-compatible** LLM endpoint. Tested today against [OpenRouter](https://openrouter.ai); the OpenAI SDK underneath means other OpenAI-flavour gateways should work, but support for them is on the roadmap rather than validated. Built to learn (and demonstrate) the Brain/Hands/Session split, the Ralph loop, and the file-backed memory channels described in Addy Osmani's [long-running agents](https://addyosmani.com/blog/long-running-agents/) and [agent harness engineering](https://addyosmani.com/blog/agent-harness-engineering/) posts.

![Brain / Hands / Session split — three boxes connected by flow arrows, with the files that implement each piece](https://raw.githubusercontent.com/AlteredCraft/tilth/main/docs/assets/brain-hands-session.png)

**Audience:** This is an active research project for my work in [Altered Craft](https://alteredcraft.com). I do actively use it for real work, so I'd suggest it for single-dev / few-dev teams who want to *understand* what a long-running agent harness actually does. That's today (June 2026); the future, we shall see.

**Target run:** 10–60 minutes of autonomous work against an open model (default `deepseek/deepseek-v4-flash` on OpenRouter for the worker; the evaluator defaults to `deepseek/deepseek-v4-pro`), completing a short task list against a small project on a per-session git worktree.

> **Status — prompt-driven core.** Tilth is deliberately small and currently being driven *down* to its essentials: a worker and an independent evaluator, the base file/search/bash tools, and full observability. There is **no codified test/lint gate** — the evaluator is the only gate — and **no interview step**: you author the work as markdown and run it. Capabilities get added back only as testing shows they're needed.

## How Tilth differs

Many minimal coding agents are *interactive* — a developer watches the output and course-corrects, kills a bad run, or re-prompts. Tilth runs *autonomously* for the length of a run, with no one watching mid-task. That single difference is why it carries machinery a pair-programming agent can skip: an **evaluator** — a second model that judges whether a change is a *proper* solution against the task's acceptance criteria, not just whether the code runs; **between-task caps** that stand in for the budget ceiling a human would otherwise impose; a per-task **evaluator ledger** so a retried task sees the reviewer's prior verdicts; **state kept out of the model's context**; and **offline-first observability** (detailed just below). None of this is a knock on interactive agents; it's a different shape for a different job.

### Hyper-observability

If no one is watching a run mid-flight, the recording *is* the supervision. Tilth's standing goal is **hyper-observability** — *every prompt the harness sends is accessible, and every run is fully inspectable after the fact.* Every assembled prompt, memory load, model call, and evaluator verdict lands in an append-only `events.jsonl`, and `tilth visualize` serves the whole thing as a local chat-style web app — tail an active run in near-realtime or replay a finished one end-to-end, with no state hidden out of reach.

![A finished Tilth run rendered by `tilth visualize`: the dashboard band — a header with an `all_done` status chip plus token-cost and event-count chips, a "Limit utilization" row of cost-budget, wall-clock, and per-task iteration meters, a stat band (tokens, cost, model and tool calls, verdicts), a session timeline, and a context-pressure chart](https://raw.githubusercontent.com/AlteredCraft/tilth/main/docs/assets/session-render.png)

*A finished run, rendered by `tilth visualize`.*

It's an early example of the goal, not a finished product. For the full product story — the Brain/Hands/Session split in detail, the memory channels, the two loops, and the worker↔evaluator dialogue — see the **[docs site](https://alteredcraft.github.io/tilth/)**. (The docs are mid-revision for the prompt-driven core; the README is the current source of truth for the run flow.)

## Quickstart

```bash
# Install the CLI from PyPI (puts `tilth` on your PATH, runnable from anywhere)
uv tool install tilth
# …or run it without installing, npx-style:   uvx tilth --help
# …or with pipx:                               pipx install tilth

tilth init                     # scaffolds ~/.tilth/.env
# edit ~/.tilth/.env — TILTH_BASE_URL, TILTH_API_KEY, TILTH_WORKER_MODEL are all
# required (Tilth refuses to start without them so a misconfigured run can't
# silently fall back to a provider/model your account doesn't have)
```

> **Working *on* Tilth?** Install from a clone instead — see [Working with the codebase](#working-with-the-codebase).

Tilth keeps all per-user state under `~/.tilth/` — the `.env` above and every run's `sessions/<id>/`. Relocate it with `$TILTH_HOME` (whole tree) or `$TILTH_SESSIONS_DIR` (just the runs).

You author the feature as markdown in the target repo, then run it — there's no interview step. The work lives in a feature directory you name under `<repo>/.tilth/<feature>/` (one repo can hold several features):

```
.tilth/todo-cli/
├── overview.md            # the feature's goal + scope boundaries (required)
├── T-001-<slug>.md        # one file per task, ordered by id
├── T-002-<slug>.md
└── ...
```

Each task file is small frontmatter plus two sections:

```markdown
---
id: T-001
title: Add the `add` subcommand
---

## Description
What to build, in the worker's voice. Real paths/symbols
(todo_cli/__main__.py:main()), not "the entrypoint".

## Acceptance criteria
- An externally checkable behaviour
- Another one
```

Then point Tilth at the feature directory:

```bash
git clone git@github.com:AlteredCraft/tilth-demo-todo-cli.git tilth-demo
# author tilth-demo/.tilth/todo-cli/  (run prints ready-to-fill templates if it's missing)
tilth run ./tilth-demo/.tilth/todo-cli
```

For each pending task, Tilth resets context from disk, lets the worker work with the file/search/bash tools until it calls `submit_case`, hands the case + diff to the evaluator in a fresh context, and on `accept` commits one task = one commit on the `session/<id>` branch (humans review and merge — Tilth never auto-merges). A run stops on all-tasks-done or a cap (iterations / wall-clock / dollar spend / evaluator calls). Interrupt with Ctrl-C; resume with `tilth resume`.

```bash
tilth resume                 # continue the latest session
tilth push                   # push the session branch to origin for review
tilth pr                     # push + open a PR against main (gh if present, else a compare URL)
tilth cleanse                # retire a merged/pushed session: worktree + branch gone, audit record kept
tilth reset                  # tear down a session's worktree + branch + dir (discards everything)
tilth visualize              # serve the live session viewer (127.0.0.1:8765)
tilth info                   # list sessions (status, progress, tokens); `tilth info <id>` for one session's detail
tilth config                 # show resolved provider config + run caps (API keys masked)
```

The `TILTH_*` env-var table (caps, evaluator routing, context-file selection) is documented in the generated `~/.tilth/.env` (copied from `.env.example`).

## Working with the codebase

Working *on* Tilth itself rather than using it? `uv sync` for the dev env, then run the CLI straight from the clone with `uv run tilth …` (no install needed — sessions still land in `~/.tilth/` unless you set `$TILTH_HOME`).

Prefer `tilth` on your PATH while still tracking your working copy? Install it editable from the clone instead:

```bash
uv tool install --editable .   # `tilth` on your PATH; resolves to this clone
```

Edits to the Python source then take effect immediately, with two caveats:

- **Code edits are live; structural changes aren't.** Changing *dependencies*, the *entry point*, or the *version* in `pyproject.toml` needs a `uv tool install --editable . --reinstall`; plain `.py` edits don't.
- **It shadows the published build.** While the editable install is active, `tilth` always runs this clone, not the PyPI release. To temp-test the *published* release without disturbing this install, run it ephemerally with `uvx` (e.g. `uvx tilth@0.1.0 --help`; add `--refresh` to bypass uv's cache and re-pull from PyPI) — or `uv tool uninstall tilth && uv tool install tilth` to point the PATH command back at PyPI.

```bash
# Lint
.venv/bin/python -m ruff check tilth/

# Tests
.venv/bin/python -m pytest

# Docs — live preview at http://127.0.0.1:8000
uv run --extra docs mkdocs serve

# Docs — strict build (the CI gate; catches broken nav refs, missing files, dead links)
uv run --extra docs mkdocs build --strict --site-dir /tmp/tilth-site
```

See [`CLAUDE.md`](./CLAUDE.md) for repo conventions and the architecture invariants worth preserving when editing the harness itself.
