Skip to content

Quickstart

Install

$ uv add hansard

Zero runtime dependencies — Hansard adds nothing to your dependency tree. Requires Python 3.13+.

Integrate in about fifteen minutes

The smallest real integration: open a session, record a message, wrap the agent's work in a turn, record what it did.

import hansard

with hansard.session(path="./sessions", agent="support-bot") as sess:
    priya = sess.message(user_id="priya", text="restart the payments worker")

    with sess.turn(context=[priya]) as turn:
        turn.action(
            kind="tool",
            name="restart_worker",
            args={"service": "payments"},
            caused_by=[priya],
        )
        turn.output(
            text="Restarted the payments worker.",
            caused_by=[priya],
        )

A session is a directory, not a file: hansard.session() opens one append-only .jsonl segment per writer, so concurrent callers (one per person, one per agent process) never contend on the same file. context= and caused_by= are optional — omit them and Hansard falls back to inference — but passing them is what turns a guess into a recorded fact; see Attribution for the measured difference.

Replay it

$ uv run hansard replay ./sessions/s_01KZVVGRNR3D5V708Z4NPGG11H

Real, unedited output from that exact command against the session the snippet above produced:

session s_01KZVVGRNR3D5V708Z4NPGG11H | corrected view | 1 person | 1 writer | less than a second

20:44:44.090  priya    restart the payments worker

20:44:44.090  - turn begins
              agent saw: priya's message

20:44:44.090  * restart_worker(service="payments")
              `- caused by priya | recorded by the agent | 1.0

20:44:44.090  * output: Restarted the payments worker.
              `- caused by priya | recorded by the agent | 1.0

20:44:44.090  - turn ends (ok)

Every attribution here reads 1.0 because caused_by was passed — a fact the runtime recorded, not a guess. See The log format for what a session directory actually contains, and CLI reference for verify, inspect, and prune.

Try the multiplayer demo

The repository ships a demo agent that proves this against a real, concurrent, three-terminal session instead of a single-writer toy — see demo/README.md in the repository for the full walkthrough, including the messy overlapping-instructions scenario the Attribution page quotes from.