A library · Free & source-available · BSL 1.1 · TypeScript · Java · .NET · Python

You write zero logging statements.

NarrativeTrace writes every traced call, its parameters and its result as log lines, through the logger you already use. Helps choose better method and parameter names. Secrets redacted. The same traces, formatted for AI, let your agent verify and debug.

Code is the log.

TypeScript on npm · Java on Maven Central · .NET on NuGet · Python on PyPI

Live · running in this tab

You are O. Every method the computer calls to pick its move lands on the right as it happens — a real trace from the real library, no recording, no server. Try the trace level menu, click a square that is taken, then Copy trace. How it works →

Its opening is the widest search in the game — nine candidates, half a million positions. Your reply is usually the narrowest: one tactic fires and the search never runs.

narrativetrace 0 calls
Also in your console — open DevTools and type nt.last()

Code is the log

Delete or enrich the logging statements. Keep the story — and the stack.

Before — three careful log lines

placeOrder(req: OrderRequest): Order {
  logger.info({ orderId: req.id }, 'placing order');
  try {
    const customer = this.customers.find(req.id);
    const price = this.catalog.price(req.sku);
    this.inventory.reserve(req.sku, req.qty);
    const payment = this.payments.charge(price);
    const order = this.orders.save(customer, payment);
    logger.info({ orderId: order.id }, 'order succeeded');
    return order;
  } catch (err) {
    logger.error({ orderId: req.id, err }, 'placing order failed');
    throw err;
  }
}

After — code is the log

placeOrder(req: OrderRequest): Order {
  const customer = this.customers.find(req.id);
  const price = this.catalog.price(req.sku);
  this.inventory.reserve(req.sku, req.qty);
  const payment = this.payments.charge(price);
  return this.orders.save(customer, payment);
}
// Zero log lines.
// NarrativeTrace captures the narrative
// automatically.

3am, the payment declines

app.log — on-call's only clue
INFO  Placing order {customerId: "C-1234", productId: "SKU-KB", quantity: 2}
ERROR Order failed {customerId: "C-1234", productId: "SKU-KB", err: PaymentDeclinedError}
context.captureTrace() — nothing hand-written
OrderService.placeOrder(customerId: "C-1234", productId: "SKU-KB", quantity: 2)
  CustomerService.findCustomer(customerId: "C-1234") → Customer{tier: "gold"} — 4ms
  ProductCatalogService.lookupPrice(productId: "SKU-KB") → 24.99 — 2ms
  InventoryService.reserve(productId: "SKU-KB", quantity: 2) → Reservation{productId: "SKU-KB", quantity: 2} — 6ms
  PaymentService.charge(customerId: "C-1234", amount: 49.98, cardToken: [REDACTED]) !! PaymentDeclinedError: card declined — 640ms
!! PaymentDeclinedError: card declined — 652ms total

Both records come from the same failed call. The catch block wraps the whole method, so the error log can say a customer and product id and an exception type — not which of the four calls actually threw. The trace does: PaymentService.charge, at 640ms. It also has what the log never captured — the price, the redacted card token, and InventoryService.reserve two lines above it with no matching release anywhere in either record. Nothing on the right was written by hand, so it can't go stale the next time someone adds a step.

One run, two readers

new ProseRenderer().render(trace) — for humans
The order service places an order for customer id "C-42", quantity 5:
  Customers verify good standing for "C-42", returning true.
  The pricing service calculates for quantity 5, returning 49.95.
  The payment service charges card [REDACTED], returning PaymentConfirmation(txId="T-9").
  The order repository saves the order, returning Order{id=ORD-1001, total=49.95}.
customer_places_order.nt — value-free, for agents
- OrderService.placeOrder(customerId, qty) → value
  - Customers.verifyGoodStanding(customerId) → value
  - PricingService.calculate(qty) → value
  - PaymentService.charge(card) → value
  - OrderRepository.save(order) → value
// no data, no PII, nothing to inject through

Prose reads exactly as well as your names, which is why clarity scoring grades every name from the runtime narrative — the code learns to tell its own story. Clarity diagnostics →

The panel above is disciplined logging, not a strawman: one line at entry, one on success, one in a catch, the way a careful team ships this method. NarrativeTrace replaces the careful kind too, because a fixed set of lines can only report the calls someone thought to write down ahead of time. The events go where your logs already go, through SLF4J, ILogger, pino or winston, and the statements you have not deleted yet keep working. Logging bridges →

A 2026 study of 4,550 pull requests by AI coding agents against 3,276 by humans, across 81 open-source repositories, found that agents touch logging in only 20.7% of their PRs, fail 67% of the time when a reviewer asks for it, and that humans write 72.5% of the later fixes themselves, in a quiet commit rather than in review (arXiv 2604.09409). When the code is the log there is nothing to write or comply with, and approval traces make observability a deterministic gate, the guardrail the paper's own recommendations call for.

Start here with your agent

Paste this into your coding agent. It sets NarrativeTrace up in your project and shows you its first trace.

Paste this into Claude Code, Cursor or Codex inside your project.

Set up NarrativeTrace in this project and show me its first trace.

1. Read https://narrativetrace.ai/typescript/llms.txt first. It carries the install block and the known traps. Do not guess versions or artifact names.

2. If this directory has no project yet, create the smallest console app that llms.txt's "Install and first trace" block describes. Otherwise work inside the existing project and trace one real service boundary.

3. Add `@narrativetrace/cli` as a dev dependency the way llms.txt shows, then run `npx @narrativetrace/cli init --dry-run` and show me the diff. It installs the NarrativeTrace agent skills into this project and adds a marked section to AGENTS.md. Run it for real only after I have seen the diff.

4. If the `add-narrative-tracing` skill is now available, follow it. Otherwise follow the "Install and first trace (copy this)" block in llms.txt.

5. Add one test that traces a call with a deny-listed parameter and asserts the trace shows `[REDACTED]` for it.

6. Run the program, then run the doctor (`npx @narrativetrace/cli doctor`). Paste the trace and the doctor report, explain the trace in two sentences, and list exactly what changed in the project.

Rules: never disable redaction; do not commit `.received.nt` files; pass parameter names to `traceObject` explicitly so arguments never render as `arg0`; run everything in the foreground and read the output before you report; if you cannot fetch URLs, say so and I will paste llms.txt.

Manual setup →

AI-first demo: build a two-service app from nothing

Read https://narrativetrace.ai/typescript/llms.txt

Create a TypeScript console app in a new folder. Keep all application code in main.ts: two service classes, OrderService calling InventoryService, and the entry point. Use NarrativeTrace to capture both services without handwritten log statements.

Set module and moduleResolution to NodeNext. Install @types/node and set types to ["node"]. Typecheck before running.

Create demo.sh (macOS/Linux) and demo.ps1 (Windows) launchers that work from any directory, install project dependencies if needed, and print Markdown traces to the terminal.

Run the launcher supported on this machine for one successful order and one out-of-stock failure. Show the actual generated traces, briefly explain what happened, and give me both launch commands.

How it works

Two steps to your first narrative

1

Wrap a service — or decorate

const context = new AsyncNarrativeContext(
    new NarrativeTraceConfig());
const service = traceObject(orderService, context, {
  placeOrder: ["customerId", "productId", "quantity"],
});

// or on the class itself:
@traced("customerId", "productId", "quantity")
placeOrder(cId: string, pId: string, qty: number) {}
2

Read the story

service.placeOrder("C-1234", "SKU-KB", 2);

console.log(
  renderIndentedText(context.captureTrace()));

// Vitest: every test writes
// its own trace file.

All @narrativetrace/* packages are live on npm at the current release. Node 20+, TypeScript 5.0+ for the decorator form.

The safety net for AI refactors

Tests check the values.
Approval traces check the calls that produced them.

After every run, NarrativeTrace compares each scenario's call structure with the last green run and says what changed — in one line. Turn on approval mode and an unapproved change (a new call, a dropped call, a different outcome) fails the build with a readable diff until a human approves it. The tests were green; the behavior still changed. Now you know. An additional check beside your tests, not a replacement.

./gradlew test — every run, no configuration
NarrativeTrace — Suite complete
  5 scenarios recorded
  Clarity: 100% high | 0% moderate | 0% low
  Reports: build/narrativetrace
  Since last green: 4 scenarios unchanged · 1 changed:
    "Customer places order" (−1 call Customers.verifyGoodStanding)
approval.set(true) — the refactor has to be approved
Narrative changed against the approved baseline
  src/test/narratives/OrderServiceTest/customer_places_order.approved.nt

  - OrderService.placeOrder(customerId, qty) → value
-   - Customers.verifyGoodStanding(customerId) → value
    - PricingService.calculate(qty) → value
    - PaymentService.charge(card) → value
    - OrderRepository.save(order) → value

  review the .received.nt, then: ./gradlew approveNarratives

One line after every run

No setup: the .nt file each test already writes is the last-green baseline, so a failing test prints only what changed.

Approve behavior, not just code

A refactor — yours or your agent's — that changes call structure fails the build until someone reviews the diff and runs approveNarratives.

Value-free by design

Baselines hold names and structure only, so they're safe to commit and safe to hand to an AI agent as the spec of record.

How approval mode works

Where it stands per runtime, because a build gate is a promise: TypeScript, Java, .NET and Python all ship approval traces; the value-free .nt structural artifact ships in TypeScript, Java, .NET and Python today.

The questions before you ship

What a production evaluation actually asks

These are the three questions an integrations engineer asked while evaluating NarrativeTrace, before naming what would stop them shipping to production. We would rather answer them here, with numbers and named limits, than let an evaluator find the gaps alone.

How much does this cost in performance and memory under high concurrency?

We will not claim “zero overhead” in any runtime — tracing does work, and work costs something. What NarrativeTrace itself adds is capture: intercepting the call, reading arguments, building the trace tree. Everything after that — the write to your existing sink, the collector, the disk or network — is the same cost your logging stack already pays; NarrativeTrace does not add a second sink. For a team replacing hand-written log statements, the sink side is close to a wash: several log writes per method become one trace write, and those statements stop being written and maintained.

Java: ~1.9 µsagent active · ~40 ns inactive · measured 2026-09-01
TypeScript: ~10 µsfull detail · ~0.1 µs added at level:'off' · measured 2026-09-07
.NET: ~2.5 µsfull enter/exit, Detail level · Off level not yet benchmarked · measured 2026-08-12
Python: not yet publishedzero-work OFF gate verified; no dated public number yet

Under concurrency, the durable path (a synchronous listener into your existing logger) writes inline — as crash-safe as the log call it replaces. The best-effort analysis path is a bounded ring buffer that sheds under sustained load instead of blocking the caller, and every runtime counts what it shed and reports the count, rather than losing it silently.

The honest gap: no NarrativeTrace runtime ships sampling today. A percentage- or rate-based sampler is planned, not built. If you need to cap capture volume now, narrow the traced scope or drop to a lower tracing level for the hot path.

How do I know a parameter with PII or credentials won't leak into a trace?

Four independent layers, not one blanket promise. 1. Explicit redaction — @NotTraced / [NotTraced] / @not_traced on a parameter, field or property; it always wins, even under configuration that disables the other layers. 2. An always-on, multilingual name deny-list — matched on identifier names (password, token, ssn, plus Spanish, Portuguese, French and Chinese equivalents), on by default in every runtime, never opt-in. 3. Value-shape matching, independent of the field name — a JWT-shaped string, a Luhn-valid card number, or a national-ID checksum is caught even under an innocuous name like data. 4. The value-free .nt structural mode — the categorical guarantee. No runtime value reaches it at all, so there is nothing for a filter to miss.

Be precise about the boundary: name and shape matching (layers 1–3) are heuristic and extensible — they widen as gaps are found, and can miss a name or shape nobody has added yet. The structural mode (layer 4) is the only categorical answer. If your threat model requires that no value can possibly leave the process, that is what to reach for, in every runtime.

Can this cross with a standard correlation ID when a flow spans several services, or is it local only?

Yes, in every runtime, through the same mechanism OpenTelemetry uses: W3C traceparent. An inbound header is adopted and NarrativeTrace's own trace id becomes that header's trace id directly — not a separate identifier merely shaped to match — and an outbound call stamps the current trace id on its way out. Every runtime also exports NarrativeTrace spans to OpenTelemetry, so an existing collector, Jaeger, or correlation-id middleware understands the id with nothing to reconcile.

What stays local everywhere: the narrative tree itself — the nested calls, arguments and narration — is captured per process and is never shipped to another service; only the trace id crosses the boundary. A downstream service produces its own tree correlated to that id, not one merged cross-service tree.

Integrations

Meets your stack where it is

Vitest Shipped
Express Shipped
Hono Shipped
NestJS Shipped
React Shipped
React Router Shipped
Angular Shipped
pino Shipped
winston Shipped
OpenTelemetry Shipped
Browser bundle Shipped
Clarity CLI Shipped

Every runtime

One architecture, every runtime

Narrative capture, dual-consumer output and clarity diagnostics: one architecture, written natively in each language against one shared output specification. A trace reads the same whichever runtime produced it — which is why the value-free .nt artifact travels between them.

TypeScriptOn npm
JavaOn Maven Central
.NETOn NuGet
SwiftIn development
PythonOn PyPI

narrativetrace-typescript · narrativetrace-java · narrativetrace-dotnet · narrativetrace-python. All @narrativetrace/* packages are live on npm at the current release. All narrativetrace packages are live on PyPI at the current release. Swift is in development.

Three recent studies

AI agents log less than humans, and mostly don’t comply when asked to.

Agents don’t log.

In 58.4% of 81 repositories, agents touched logging in a smaller share of their pull requests than humans did; asked outright by a reviewer to add logging, they failed 67% of the time. — Do AI Coding Agents Log Like Humans?, 2026

Raw traces don’t explain.

In a small user study, engineers found the root cause from raw agent traces 42% of the time, versus 89% with a structured explanation, and took nearly three times longer. — XAI for Coding Agent Failures, 2026

Faithful explanations come from structure, not from the model.

A trace-grounded pipeline produced zero failed explanations across 548 traces; free-form LLM narration failed 18% of the time. Every claim has to point at something that happened. — Explaining AI Agents Through Execution Traces, Sapienza University of Rome, 2026

NarrativeTrace applies the third finding to the code the agent ships: the .nt structural trace the agent reads is derived from structure and never contains a runtime value; the log lines a human reads do. The rest of the numbers, and the answer, are below.

Built for AI-assisted development

Your agent can read the code.
Now it can watch it run — safely.

A coding agent that debugs from source alone guesses at runtime behavior, and guesses wrong. NarrativeTrace hands it ground truth — the real call tree — in the shape a model reads best, at a fraction of the tokens, with the data it must never see already gone.

Fewer tokens, more signal

Log statements are noise tokens. Deleting them makes a service class 15–30% cheaper for an agent to read — and every line of a trace carries signal, because it was generated from names, not prose. Repeated values dedupe to a reference; repeated loops fold to one line.

Markdown, made for the context window

Every test writes its narrative as a .md file — a nested list of calls, arguments and results that any agent already knows how to read. Paste it, attach it, or point the agent at the directory your CI already fills. Prose, JSON and sequence diagrams come from the same trace.

Output formats

No runtime values, so nothing to inject

Every test also writes a .nt structural trace: the call tree with every runtime value stripped. No user input reaches it, so no user input can steer the model that reads it. Zero PII, a fraction of the tokens, safe to commit. The protection is specific: the structural trace carries no runtime value, so no runtime value can carry an instruction.

How separation works

What comes next Planned

Pseudonymized output: real values replaced by synthetic tokens, so the agent still sees that the same customer flows through three calls without ever seeing who. MCP server: Claude Code, Cursor and Copilot query traces and dependency graphs directly, read-only, structure-only by default.

Preview the MCP design

This site is agent-friendly too: point your assistant at llms.txt, which routes it to your runtime's own llms file, and it can adopt NarrativeTrace for you.

What an agent gets

Four things an agent actually reaches for

llms.txt to read

A structured index built for agents, not search engines — this site's own, and every runtime ships one in its own repository.

Java's llms.txt

.nt traces to diff

The call tree with every runtime value stripped — small, structural, and safe for an agent to read and diff.

Structural trace format

Approval traces as a gate

A behavior change becomes a build failure with a readable diff, not a silent surprise, until a human approves it.

How approval mode works

A skill that wires it in

add-narrative-tracing installs the library and gets you to a first trace; narrativetrace-doctor diagnoses a project that already has it — both run as skills in Claude Code and Codex.

Agent skills

Self-reported, not benchmarked

What AI agents are saying

The trace of a failed payment made missing compensation immediately visible, and approval testing caught an extra call that ordinary value assertions accepted.
GPT-6 · Java
…the release call is present, generated from a real run, not asserted from inside the process being tested.
Claude Sonnet · Java
The always-on name-based deny-list is a genuinely nice piece of design: naming a parameter paymentToken gets you redaction for free, and I could prove it in a test.
Claude Sonnet · Java
Wrapping a service interface with NarrativeTraceProxy.trace() automatically captures all calls, parameters, return values, and durations without any code changes to the service itself. This is elegant.
Claude Haiku · Java
…the clarity report told me ClaimProcessor.process scored 0.10 for a “generic verb” the very first time I ran the suite, and it was right — I renamed it to adjudicate … and the suite average from ~0.78 to ~0.81.
Claude Sonnet · Java
Yes, for agent-driven development of Java applications with meaningful service boundaries. Getting useful traces required little configuration, and the combination of values, exception paths, and structural approvals gave me evidence I could act on.
GPT-6 · Java
The rendered Markdown trace was legitimately useful while building this, not just as a deliverable … which is how I caught that my first draft of scenario 6’s numbers didn’t actually trigger InsufficientCoverageError … well before any test told me.
Claude Sonnet · Python
That’s not a library gap so much as a library doing exactly its job: it rendered what was actually being passed around, and what was actually being passed around was more than any of those services needed.
Claude Sonnet · TypeScript

We asked AI agents to build a Java service with NarrativeTrace and write up the experience for another engineer — honestly, naming what was awkward. These are their words, unedited, with the model named. It is not a benchmark: one run each, and we wrote the library. The task and the prompt are under the button, so the next report can be your agent's.

Try it yourself

This is the exercise those reports came from. One difference: our runs handed the agent a copy of the documentation; yours points it at the public repository. Two files, three steps.

  1. Save the specification as TASK.md in an empty directory.
  2. Start your agent in that directory and give it the prompt.
  3. Read its FINDINGS.md — and if you post it in the Discussions of the runtime you used (Java · TypeScript · .NET · Python), we will read it too.

The prompt

You are building a Java application from a written specification.

The specification is in `TASK.md` in the current directory. Read it, then build the
application it describes. Build it properly: it should compile, its tests should
pass, and the demo should run.

A library called **NarrativeTrace** is available to you for this project. Its
documentation is in its public repository:

- https://github.com/narrativetrace/narrativetrace-java — start with the README
- https://github.com/narrativetrace/narrativetrace-java/blob/main/documentation/llms.txt
  — a short orientation written for AI agents
- https://narrativetrace.ai/java/llms-full.txt — the full documentation written for AI agents

Read that documentation first, then use the library in the application you build.
Its artifacts are published on Maven Central under the group `ai.narrativetrace`;
the Gradle plugin id is `ai.narrativetrace`. Take the version from the install
block in llms.txt; the documentation explains which artifacts you need and how to
wire them up.

Rules for this exercise:

- Work **only** inside the current directory. Do not read, search, or modify
  anything outside it, and do not clone the library's source code — the
  documentation is what you have.
- You may use the network to read that documentation and to resolve build
  dependencies.
- You choose the design, the libraries, the project layout, and the testing
  approach. There is no house style to match and no reviewer to please.
- Work in the foreground. Do not background the build or the tests and then end
  your turn — run them, wait for them, and read the output.
- When the build and tests are green and the demo runs, write `FINDINGS.md` as
  the specification describes. In addition to what the specification asks for,
  cover what using NarrativeTrace was actually like: what the documentation got
  right or left you guessing about, what integration cost you, and whether the
  output it produced was of any use to you while you worked.

Finish by reporting, in your final message: whether the build and tests are
green, what you built, and where things stand.

The specification — TASK.md

# Build task — Claims intake service (Java 17)

Build a small, self-contained Java 17 application called **ClaimFlow** that processes
insurance claims through a chain of collaborating services. It must build and test with
Gradle, and run as an executable demo.

This is a business-logic exercise, not an infrastructure one: everything is in-process
and in-memory. No database, no HTTP server, no external service, no network access.

## The domain

A claim is submitted and passes through five collaborating services. Each is its own
interface with its own implementation — do not collapse them into one class.

1. **PolicyService** — looks up a policy by `policyId`. A policy has a holder name, a
   coverage limit in whole cents, a deductible in whole cents, and an active flag.
2. **ClaimValidator** — rejects a claim that names an unknown policy, an inactive
   policy, a non-positive amount, or an incident date in the future.
3. **FraudScreen** — scores a claim from 0–100. Any claim scoring above 70 is referred
   rather than paid. Scoring may be simple and deterministic, but it must consider at
   least the claim amount relative to the coverage limit, and whether the same policy
   has had a prior claim in this run.
4. **ReserveLedger** — reserves funds against a policy's remaining coverage before
   payment, and can release a reservation. Reserving more than the remaining coverage
   fails.
5. **PayoutService** — pays an approved claim, given a payment token. Payment can fail;
   your demo must exercise at least one failing payment.

A **ClaimProcessor** orchestrates them and returns a `ClaimOutcome` describing what
happened: paid (with amount and transaction id), referred, or rejected (with a reason).

## Required behaviour

- Payout amount is `min(claimAmount, coverageLimit) - deductible`, never below zero.
- A claim must be validated, then screened, then reserved, then paid — in that order.
- **If payment fails after a reservation was made, the reservation must be released.**
- A referred claim is never paid and never reserves funds.
- Two claims against the same policy must respect the remaining coverage.
- The payment token is a credential and must never appear in any output your program
  produces.
- The claim holder's name is personal data; treat it accordingly in whatever your
  program writes out.

## Deliverables

1. A Gradle project that compiles under Java 17 and runs `./gradlew test` green.
2. Unit tests covering the behaviour above, including the failure paths.
3. A runnable demo (`./gradlew run` or a `main`) that exercises at least five scenarios:
   a straightforward paid claim, a claim above the coverage limit, a referred (high
   fraud score) claim, a rejected claim, and a claim whose payment fails after a
   reservation.
4. A short `FINDINGS.md` in the project root — see "What to report" below.

## What to report in FINDINGS.md

Write it for another engineer, not for us. Cover:

- What you built and how you verified it works.
- Anything that surprised you, went wrong, or took longer than expected.
- How you satisfied yourself that the compensation rule (release the reservation when
  payment fails) actually holds — what evidence do you have?
- How you satisfied yourself that the payment token never leaks into output.
- What you would want before running this in production.
- Anything about the tools or libraries you used that helped or got in your way.

Be honest and specific. A report that says everything went perfectly is less useful
than one that names what was awkward.

For humans

  • Prose that reads like a bug report, in your team's language
  • Markdown and a sequence diagram written by every test
  • One line after every run: what changed since the last green build

For AI agents

  • 15–30% fewer tokens than the code with its log statements in
  • Markdown a context window was made for — runtime truth, not a guess
  • Value-free .nt: no runtime value reaches it, so nothing to inject through
15–30%fewer tokens when an agent reads your code — how
0runtime values in the .nt trace — nothing for an injection to ride on
.mdevery test writes a Markdown narrative
~1.9 µsper traced call on the JVM agent · ~40 ns inactive · measured

For legacy modernization

Migrate the system nobody understands — with receipts.

AI agents make rewrites cheap; verifying them is the expensive part. Wrap a legacy system in traces and you get its real runtime behavior before you change it, and a structural comparison of the calls after.

X-ray the architecture you actually have

On the JVM, attach the agent to an unmodified app with one -javaagent flag, or run the JUnit 4 suite you already have. On .NET, NarrativeTrace.Legacy reaches back to .NET Framework 4.8. No source changes, no documentation archaeology.

Zero-code agent

Show the call structure didn't change

Pin every scenario in a value-free baseline before you touch anything. Then compare whole trace sets before and after a port or AI rewrite, each divergence classified by risk. A structural comparison — the same calls, in the same order, with the same outcomes — not a proof that every value is equal.

Migration diffs

Find the code that reads worst

If the trace doesn't read well, the code is lying about itself. Clarity scoring grades naming from the runtime narrative and explains every score. Point your refactoring, or your agent's, at the worst corners first.

Clarity diagnostics

Also included: a domain glossary harvested from real runs, and the same trace rendered as prose in Chinese, Spanish or Portuguese. Glossary & translated traces →

Your logs have new readers.
They don't sleep, and they don't skim.

Support, on-call, audit, security: each is becoming an agent with a human supervising. They all need the same thing, a complete, readable, PII-free record of what the code actually did, and nobody has to write it by hand.

Same trace, five readers

Support

The one that answers the ticket

Reads the request's story and tells the customer what happened. Why: the whole path is there in plain language, and no engineer was paged.

Output formats

On-call

The one that decides whether to wake you

Sees where it failed and how long each step took, and judges severity. Why: the failing step and everything above it are always captured.

Capture levels

Audit

The one that assembles the evidence pack

Pulls the annotated actions, each tagged with its action code, into a tamper-evident chain — evidence both auditors and agents can read. Why: the evidence was recorded as the code ran, not reconstructed afterwards.

Audit & SecOps events

Security

The one that checks the control ran

Confirms the control fired and that sensitive values never left redaction. Why: the record holds the structure of what happened, with the values stripped before anything is written.

How separation works

The coding agent

The one that rewrote your service last night

Diffs the story before and after, and fails the build if it changed. Why: approval traces turn the story into a gate.

How approval mode works

Bring your own agent: Claude, Codex, Bits, Seer, or a person at 3 a.m. NarrativeTrace ships OpenTelemetry, so the same story lands in Datadog, Sentry or Honeycomb with the trace attached.

Editions

What is in each edition

The runtime is free and source-available under BSL 1.1 and becomes Apache 2.0 four years after each release; the API and output format are Apache 2.0. Pro and Enterprise are commercial.

Free Available now

Free to use in production, source-available. BSL 1.1; each release converts to Apache 2.0 after four years. API and output format Apache 2.0. Licensing →

  • Zero runtime dependencies in the core
  • Automatic tracing: proxy wrapping, narration decorators/attributes and HTTP middleware in every runtime; DI-container auto-wrap (Java, .NET, NestJS) and a zero-code bytecode agent (Java)
  • All five capture levels, runtime-switchable
  • Narration, error-context and no-trace markers on methods and fields — each runtime's own naming convention — plus automatic redaction
  • Per-test trace files from JUnit 5/4, xUnit, NUnit, Vitest and pytest: Markdown, JSON, prose, sequence diagrams
  • Clarity scoring, the clarity CLI, a CI clarity gate & a bridge into your logger
  • Value-free .nt traces (TypeScript, Java, .NET, Python); approval mode (TypeScript, Java, .NET, Python)
  • Domain glossary, translated traces, OpenTelemetry
Get started

Enterprise Coming soon

Hosted backend for narratives from every service, environment, and run.

  • Managed OTLP ingest for traces
  • Multi-tenant storage & search
  • Team dashboards & retention policies
  • Org-wide clarity & audit reporting
Join the waitlist

The free runtime ships on Maven Central under ai.narrativetrace, on nuget.org as NarrativeTrace.*, and as source on GitHub. The licence terms are on the licensing page.

Give your code a voice — and your agent its ears.

Sixty seconds to your first trace. No log statements were written in the making of this library.