What an AI Agent Owes the Person Using It
If software acts for you, it owes you an account of what it did.
For product and engineering leaders building AI agents or AI features that read data, call tools or take actions for users.
Updated , by A Few Good Coders
13 min read11 sectionsEngineering note
Key takeaways
- Every agent turn should end with a one-line receipt: outcome, tokens in and out, rate, context fill, model calls, tool runs, any repairs or denials, and wall time, in a fixed order on every surface.
- One owner computes each number: Neel's engine measures the rate and every interface displays it, never averaging, merging or recomputing, so the terminal and the desktop app can never disagree.
- A missing number keeps its label, such as
— tok/sorcalls —, and provenance is a character (plain for measured,~for estimated,—for unreported), so an unknown is never shown as zero. - The inspector shows the instructions, tool definitions, context and raw response with repairs listed; it is an activity record, not a window into the model's private reasoning, and it says so.
- Approvals name the exact action and target (allow once, allow matching, deny), plan mode withholds every change, and failures always state what broke, where, and the next step.
Why an agent owes you a receipt
An AI agent acts on your behalf: it reads files, runs commands, spends memory, time and sometimes money, and then hands you a confident answer. A receipt is the smallest record that lets you check that answer. It says how the work ended, what it cost, which tools ran and where to see the full exchange.
A chat reply that sounds certain tells you nothing about how it was produced. Did the agent read the file it quotes, or guess? Did it run your tests, or describe what tests usually say? Did it make one model call or twelve? Was the context window nearly full, so the earliest instructions had been dropped? Without a receipt, the only way to find out is to repeat the work yourself, which defeats the point of an agent.
A card payment comes with a receipt because money changed hands and either side may need to check it later. An agent turn deserves the same, because authority changed hands. You let software act for you, and it owes you an account.
This note describes how we designed receipts for Neel, the local-first AI coding agent we are building, with Desktop and CLI front ends on one Rust engine. Neel is in development with no public release; the first installable build is planned for January 2027. The rules below come from its experience contract, the document every Neel surface follows. They apply to any AI product that takes actions.
The turn line, field by field
Under every reply, Neel prints one quiet line that summarises the turn. Its order and format are fixed, so you learn to read it once.
This is a real line from one of the engine's formatter test cases, a settled run with three model calls and two tool runs:
Three more markers appear between the tool count and the time, but only when they are not zero: repaired ×n when the engine silently fixed a malformed model response, history compacted when older conversation was summarised to fit the window, and n denied when you refused a tool request. A turn that needed repairs or lost history says so in the summary, not three clicks deep.
What sits behind the line
Open the turn and you get one row per model call. For the same run:
The rows tell the story of an agent loop. The first two calls ended by asking for tools. Each tool result was added to the conversation, so the input grew from 900 to 1,800 to 2,700 tokens. The third call wrote the answer. The last line says where the time went: 1.8 seconds inside the model, out of about 2.0 seconds overall, with half of the prompt tokens served from the prefix cache rather than read again.
Numbers follow one format everywhere. Tokens read 812, 1.8k, 128k or 1.2M, with k as 1,000, never 1,024. Durations read 38ms, 2.1s or 1m 04s. Every surface rounds with integer arithmetic, half to even, and picks the unit after rounding, so 59,960 ms is 1m 00s, never 60.0s.
One rate, measured once
Neel shows one generation rate per model call, and it comes from the engine. Interfaces display it; they never calculate, average or adjust it.
Tokens per second sounds like one number but is at least three:
- Prefill rate: how fast the model reads the prompt before it writes anything.
- Decode rate: how fast it writes output tokens once it has started.
- End-to-end rate: output tokens divided by the whole call's duration, including prefill and any waiting.
On a long prompt with a short answer, the end-to-end rate can be a fraction of the decode rate. If the terminal shows one and the desktop app another, a user sees two different speeds for the same turn and stops trusting both.
So the rule is strict. Each call shows the decode rate when the model runtime measured it directly. Otherwise it shows the end-to-end rate, carrying its own marker: plain when measured, ~ when it is Neel's estimate, — when nothing was reported. No surface averages rates across calls, merges them or recomputes them from tokens and time. While a call streams, the live rate follows the same rule and updates at most four times a second, so the figure is readable rather than flickering.
The inspector still lists every rate the engine reports (decode, end-to-end and prefill for each call, plus the turn-wide decode rate), each labelled with its source. Only the turn line and the call rows reduce them to one.
The principle generalises: one owner computes each fact, and every interface formats it. If two pieces of code can produce the same number, they eventually disagree.
A missing number keeps its label
When a figure is not available, Neel says which figure is missing. It never shows zero, and it never shows a bare dash.
Every value carries its provenance in a character, so the meaning survives plain text, screen readers and copy and paste:
A missing value keeps its label or unit: —→— tok, — tok/s, tools —, calls —, time —. Compare that with what many products do. A rate of 0 tok/s claims the model produced nothing, which is false. A lone — in the middle of a line leaves the reader guessing which fact is absent.
Some gaps are subtle. If the engine did not observe the start of a run, for example because the interface attached partway through, the call count would only cover the tail. Neel then shows calls — instead of a smaller number that looks precise and is wrong.
Memory follows the same discipline. The always-on status line names its source, as in 6.2G free (system) / 24G, because the operating system, the engine's admission check and the model runtime's own guard count free memory differently. When a model is refused for lack of memory, the message quotes the number from the check that refused it. An "unknown" is never quietly turned into a reassuring default.
The inspector shows the exchange, not private reasoning
The inspector is one step from any turn and shows what was sent to the model and what came back. It does not claim to show the model's private reasoning, because no product can honestly offer that.
In Neel the inspector holds:
- Prompt: the instructions, the tool definitions and the conversation context sent to the model, each part with its token count, so you can see what is taking up the window.
- Raw and parsed: the model's exact response next to Neel's reading of it, with any repairs listed in plain words, such as "code fence unwrapped" or "missing outer brace".
- Metrics: every rate and timing the engine reported, each with its source.
- Labels for what changed: each section says whether it is exact, truncated or redacted.
- Export: the full receipt, so it can be attached to a bug report or reviewed later.
It is one action away on every surface: neel inspect in the CLI, /inspect in the terminal interface, and an Inspect button on each turn in Desktop.
A related rule stops important detail from being buried. If the engine retried a call, repaired a parse, truncated a section or redacted content, the affected row carries a marker. The full detail lives in the inspector, but its existence is always visible where you are already looking.
Being precise about the boundary matters too. The inspector is an observable record: inputs, outputs, tool calls and timings. If a model returns reasoning text in its output, that text is part of the raw response like anything else. Neel does not present that, or anything else, as a window into the model's internal process. Promising more visibility than you can deliver is its own breach of trust.
Approvals and plan mode
An agent that can change your files or run commands should ask first, and the question should be specific enough to answer. Neel offers three answers to every tool request (allow once, allow matching, deny) and a plan mode that withholds every change.
A good approval request names the exact action and its target: run npm test in ~/projects/atlas, not "the agent wants to use the shell". Then:
- Allow once approves this call only.
- Allow matching trusts a command pattern for the rest of the session, so you are not asked the same question twenty times. The grant is visible and ends with the session.
- Deny refuses the call. That is a normal outcome, not an error: the tool row shows "denied" and the turn line counts it, so a refusal is never mistaken for a failure.
Plan mode removes the question entirely for anything that could change the project. The agent can read and reason, but every edit and every mutating command is withheld until you switch to build mode. In the CLI that switch is Shift+Tab. Plan mode is the right default for unfamiliar code, a large refactor or a first session with a new model.
Two design details make approvals work in practice. The approval state is drawn in the warning colour and in words, so it stands out without relying on colour alone. And approvals belong to the engine, not to each interface. Neel's direction includes approving a request from a paired phone; that only works safely because the computer and the phone are answering the same request held by the same engine.
Failures that say what broke, where, and what next
A failure message has three jobs: say what broke, say where, and say what to do next. Neel renders every failure in the same four rows on every surface.
The format, with illustrative wording (not output from a real run):
- The summary is one plain sentence about the outcome.
- The root names the component and an error code, so support conversations and bug reports start from the same fact.
- Next is the engine's own hint. Where an interface has a control that does exactly that, it offers the control: Desktop shows a "Choose model" button, and the terminal interface points to
/model. Where no such control exists, the hint is shown as text only, rather than a button that does something slightly different. - Details points to the inspector entry for this run, when the run is known.
Verbose mode adds the numbered cause chain, outermost first, plus identifiers and evidence. A stack trace never lands in the conversation: it goes to standard error in the CLI, stays collapsed in Desktop and lives in the inspector in the terminal interface.
The engine produces a structured diagnostic, and interfaces format its fields. No interface parses error text to decide what to show, because error text changes and parsers drift.
The same product in the terminal, the desktop and the editor
A person who moves from the terminal to the desktop app should feel one product and see the same facts, labelled with the same honesty. Neel achieves that by sharing meaning, not widgets.
The experience contract fixes what each colour means, which symbol means "measured", the words for each state and which numbers each surface must show. Each interface still renders with its own toolkit, because terminals, Flutter and editor panels differ too much to share components. What they share:
- Words. "Done", "Failed", "Interrupted" and "Waiting for approval" mean the same thing everywhere. Tool rows use the same outcomes: succeeded, failed, denied, cancelled, timed out, skipped.
- Numbers. The same rounding rules and units, from the same receipt.
- Symbols, with fallbacks. Every glyph has an ASCII alternative for terminals without UTF-8, and colour is never the only signal.
- Quiet by default. Transcript content has no boxes, metadata is dim, and colour appears only when state changes: amber when approval is needed or memory is tight, red on failure.
- Plain mode. Non-interactive CLI output prints the same turn line after the answer, so scripts and humans read the same summary.
Consistency is enforced rather than hoped for. One renderer serves the CLI and the terminal interface. Desktop's failure formatter is tested against the same fixture file. A tooling check fails if an interactive command has no row in the parity table that records how each surface matches it. Even this website's illustrations of Neel's turn lines are checked by a test against the formatter's exact layout. The editor extensions for VS Code and Android Studio are in development on the same engine and inherit the same layers.
How to apply this in any AI product
You do not need a coding agent to use these principles. Any AI feature that answers, drafts or acts can adopt them in a few weeks.
- Decide what each action owes the user. For a chat answer, perhaps the model, the sources and the time taken. For an agent that edits data, every change, its target and who approved it.
- Compute each fact once. The backend that calls the model records tokens, timings, rates and outcomes. Interfaces format; they never recalculate.
- Label provenance. Distinguish measured from estimated from missing, in characters rather than colour, and never show an unknown as zero.
- Keep a one-line summary and a one-step detail view. The summary sits under every answer. The detail view shows inputs, raw output, parsed output and metrics, and can be exported.
- Surface what was changed. Retries, repairs, truncation, redaction and compaction get a visible marker on the answer itself.
- Ask before acting, at the right scope. Once, for matching requests, or never in a read-only mode. Show standing grants and let them expire.
- Make failures structured. A summary, a component and code, a next step and a link to details, with the same wording in every client.
- Write it down and test it. A short contract file of words, formats and rules, plus a few drift tests, keeps web, mobile and desktop clients honest as the team grows.
- Promise only what you can show. An activity record is valuable. Do not present it as access to the model's mind.
The smallest useful version for a typical product is one line under each AI answer: which model answered, how long it took, which sources or tools it used, and a link to the full record. It costs little to build and changes how people judge the feature.
Our guide to shipping AI features people trust covers the wider product side: evaluation, rollout and support. You can follow Neel's progress on the Neel page, and if you want receipts, approvals and failure handling designed into your own AI product, talk to us.
Questions
What is an AI agent receipt?
It is a short record attached to each agent turn that says how the turn ended, how many tokens the model read and wrote, how fast it generated, how full the context window was, how many model calls and tool runs it took, and how long it lasted. A detail view behind it shows the full exchange. It lets a user check an answer without redoing the work.
What should an AI agent show the user?
At minimum: the outcome, which model answered, which tools ran and with what result, what it cost in tokens or time, and any retries, repairs, truncation or denials. Behind that summary, one action should open the exact prompt, tool definitions, context and raw response. Approvals should name the exact action and target before anything changes.
Why do tokens-per-second figures differ between tools?
Because there are several rates. Prefill measures how fast the model reads the prompt, decode how fast it writes, and end-to-end divides output tokens by the whole call's duration. Neel shows the engine-measured decode rate when available, otherwise the end-to-end rate with its own provenance marker, and never recomputes rates in the interface.
Can users see an AI model's reasoning?
Not its internal process. An agent can show what it sent to the model, what came back, which tools ran and how long each step took. If a model returns reasoning text, that is part of its output, not a verified account of how it reached the answer, and a product should not present it as one.
How should an AI agent ask for permission?
Name the exact action and target, such as running one command in one folder, and offer clear scopes: allow once, allow matching requests for this session, or deny. Treat a denial as a normal outcome and count it in the receipt. A read-only plan mode that withholds every change is a good default for unfamiliar work.
Can I use Neel today?
Not yet. Neel is in development with no public release, and the whole Neel ecosystem is planned to launch together in January 2027: Desktop, the CLI, the editor extensions and Mobile, on Windows, macOS, Linux, Android and iOS. You can join early access from the Neel page to hear when it is ready.