Gratuito y de código disponible · BSL 1.1 · TypeScript · Java · .NET · Python
El código es el log.Legible para humanos. Hecho para agentes de IA.
Mira lo que tu aplicación hizo de verdad. NarrativeTrace™ convierte las
llamadas a métodos en narrativas legibles de una ejecución real, sin sentencias de log escritas a
mano. Encuentra el paso que falló, sigue el camino y dale a tu agente evidencia en lugar de
suposiciones. Reemplaza los log.info y log.debug — no tu stack de
logging: los eventos van por el logger que ya usas — SLF4J, pino, structlog,
Microsoft.Extensions.Logging — u OpenTelemetry, a los sinks que ya tienes.
TypeScript en npm · Java en Maven Central · .NET en NuGet · Python en PyPI
En vivo · corriendo en esta pestaña
Tú eres O. Cada método que la computadora llama para elegir su jugada aparece a la derecha en el momento en que ocurre — una traza real de la biblioteca real, sin grabaciones ni servidor. Prueba el menú de nivel de traza, haz clic en una casilla ocupada y luego en Copiar traza. Cómo funciona →
Su apertura es la búsqueda más amplia de la partida — nueve candidatas, medio millón de posiciones. Tu respuesta suele ser la más estrecha: una táctica se dispara y la búsqueda nunca llega a correr.
Empieza aquí con tu agente
Pega esto en tu agente de código. Configura NarrativeTrace en tu proyecto y te muestra su primera traza.
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. Follow the "Install and first trace (copy this)" block in llms.txt.
4. Add one test that traces a call with a deny-listed parameter and asserts the trace shows `[REDACTED]` for it.
5. 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.
Set up NarrativeTrace in this project and show me its first trace.
1. Read https://narrativetrace.ai/java/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 the plugin the way llms.txt shows, then run `./gradlew narrativetraceInit --diff` 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 (`./gradlew narrativetraceDoctor`). 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; keep the `-parameters` compiler flag; 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.
Set up NarrativeTrace in this project and show me its first trace.
1. Read https://narrativetrace.ai/dotnet/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. Follow the "Install and first trace (copy this)" block in llms.txt.
4. Add one test that traces a call with a deny-listed parameter and asserts the trace shows `[REDACTED]` for it.
5. Run the program, then run the doctor (`dotnet tool run dotnet-narrativetrace 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; 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.
Set up NarrativeTrace in this project and show me its first trace.
1. Read https://narrativetrace.ai/python/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. Follow the "Install and first trace (copy this)" block in llms.txt.
4. Add one test that traces a call with a deny-listed parameter and asserts the trace shows `[REDACTED]` for it.
5. Run the program, then run the doctor (`uv run narrativetrace 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; apply `@not_traced` to the real parameter, because importing it protects nothing; 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.
Demo con IA: crea una aplicación de dos servicios desde cero
El prompt está en inglés. Tu agente explicará los resultados en español.
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.
Explain the setup, results, and launch commands in Spanish.
Read https://narrativetrace.ai/java/llms.txt
Create a deliberately small Java console app in a new folder, with no package directory. Keep the example in one Main.java file: a public Main entry point and tiny package-private service types (or nested types) with strings and primitives only. Do not add DTO, result, or item classes. Use NarrativeTrace to capture OrderService calling InventoryService, without handwritten log statements.
Use the repository's documented build setup. If there is no Gradle wrapper, initialize one before running. Keep the example compact and explain any unavoidable Java boilerplate; the first run may download the build tool and dependencies.
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 Markdown traces, briefly explain what happened, and give me both launch commands. Test the other launcher if the platform supports it; otherwise review it and say that it was not executed.
Explain the setup, results, and launch commands in Spanish.
Read https://narrativetrace.ai/dotnet/llms.txt
Create a C#/.NET app in a new folder using dotnet new console; keep its generated project settings. In Program.cs, put top-level calls before OrderService, InventoryService, and their interfaces. OrderService calls InventoryService; use strings and primitives for inputs and results. Capture both services with NarrativeTrace, without handwritten log statements.
Create demo.sh (macOS/Linux) and demo.ps1 (Windows) launchers that work from any directory, restore dependencies if needed, and print Markdown traces to the terminal. Show restore output and stop on setup or execution errors.
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. State which launchers were executed and which were only reviewed.
Explain the setup, results, and launch commands in Spanish.
Read https://narrativetrace.ai/python/llms.txt
Create a Python console app in a new folder. Keep all application code in main.py: two service classes, OrderService calling InventoryService, and the entry point. Use NarrativeTrace to capture both services without handwritten log statements.
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.
Explain the setup, results, and launch commands in Spanish.
Un estudio empírico reciente
Los agentes de IA registran menos que los humanos y, en su mayoría, no cumplen cuando se les pide.
En el 58.4% de los 81 repositorios estudiados, los agentes tocaron el logging en una proporción menor de sus pull requests que los humanos; cuando un revisor les pidió explícitamente añadir logging, no lo hicieron el 67% de las veces, en los 61 pull requests que llevaban tal petición (arXiv 2604.09409, “Do AI Coding Agents Log Like Humans?”). El resto de los números, y la respuesta de NarrativeTrace, están más abajo.
El código es el log
Borra o enriquece las sentencias de logging. Conserva la historia — y el stack.
El panel de abajo es logging disciplinado, no un hombre de paja: una línea al entrar,
una al tener éxito, una en el catch — sin volcados de objetos, como ya lo enviaría
un equipo cuidadoso. NarrativeTrace no es un argumento contra el logging descuidado.
También sustituye al cuidadoso, porque un conjunto fijo de líneas solo puede informar
las llamadas que alguien pensó, de antemano, en anotar. Los eventos van adonde ya van
tus logs — por SLF4J, ILogger, pino o winston, hacia lo que sea que
los agregue — y las sentencias de log que todavía no borraste siguen funcionando.
Puentes de logging →
Un estudio de 2026 analizó 4,550 pull requests abiertos por agentes de código con IA frente a 3,276 abiertos por humanos, en 81 repositorios de código abierto, y encontró que los agentes tocan el logging en solo el 20.7% de sus PR, no añaden logging cuando un revisor lo pide explícitamente el 67% de las veces, y — cuando sí se corrige una sentencia de logging en un PR de un agente — los humanos escriben el 72.5% de esas correcciones ellos mismos, en silencio, en un commit posterior y no durante la revisión de código (arXiv 2604.09409). El estudio mide que los agentes ni escriben logging por su cuenta ni lo cumplen de forma confiable cuando se les pide, y que los humanos reparan esa brecha en silencio en vez de hacerlo en la revisión. La respuesta de NarrativeTrace es que el código es el log, así que no hay nada que el agente deba escribir ni cumplir, y que las trazas de aprobación convierten la observabilidad en una puerta determinista — el tipo de salvaguarda que las propias recomendaciones del estudio piden.
Antes — tres líneas de log cuidadosas
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;
}
}
Después — el código es el 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);
}
// Cero líneas de log.
// NarrativeTrace captura la narrativa
// automáticamente.
Antes — tres líneas de log cuidadosas
public Order placeOrder(OrderRequest req) {
logger.info("Placing order {}", req.id());
try {
var customer = customers.find(req.id());
var price = catalog.price(req.sku());
inventory.reserve(req.sku(), req.qty());
var payment = payments.charge(price);
var order = orders.save(customer, payment);
logger.info("Order succeeded {}", order.id());
return order;
} catch (Exception e) {
logger.error("Placing order failed {}", req.id(), e);
throw e;
}
}
Después — el código es el log
public Order placeOrder(OrderRequest req) {
var customer = customers.find(req.id());
var price = catalog.price(req.sku());
inventory.reserve(req.sku(), req.qty());
var payment = payments.charge(price);
return orders.save(customer, payment);
}
// Cero líneas de log.
// NarrativeTrace captura la narrativa
// automáticamente.
Antes — tres líneas de log cuidadosas
public Order PlaceOrder(OrderRequest req)
{
_logger.LogInformation("Placing order {OrderId}", req.Id);
try
{
var customer = _customers.Find(req.Id);
var price = _catalog.Price(req.Sku);
_inventory.Reserve(req.Sku, req.Qty);
var payment = _payments.Charge(price);
var order = _orders.Save(customer, payment);
_logger.LogInformation("Order succeeded {OrderId}", order.Id);
return order;
}
catch (Exception ex)
{
_logger.LogError(ex, "Placing order failed {OrderId}", req.Id);
throw;
}
}
Después — el código es el log
public Order PlaceOrder(OrderRequest req)
{
var customer = _customers.Find(req.Id);
var price = _catalog.Price(req.Sku);
_inventory.Reserve(req.Sku, req.Qty);
var payment = _payments.Charge(price);
return _orders.Save(customer, payment);
}
// Cero líneas de log.
// NarrativeTrace captura la narrativa
// automáticamente.
Antes — tres líneas de log cuidadosas
def place_order(self, req: OrderRequest) -> Order:
logger.info("Placing order %s", req.id)
try:
customer = self._customers.find(req.id)
price = self._catalog.price(req.sku)
self._inventory.reserve(req.sku, req.qty)
payment = self._payments.charge(price)
order = self._orders.save(customer, payment)
logger.info("Order succeeded %s", order.id)
return order
except Exception:
logger.exception("Placing order failed %s", req.id)
raise
Después — el código es el log
def place_order(self, req: OrderRequest) -> Order:
customer = self._customers.find(req.id)
price = self._catalog.price(req.sku)
self._inventory.reserve(req.sku, req.qty)
payment = self._payments.charge(price)
return self._orders.save(customer, payment)
# Cero líneas de log.
# NarrativeTrace captura la narrativa
# automáticamente.
3am, el pago es rechazado
INFO Placing order {customerId: "C-1234", productId: "SKU-KB", quantity: 2}
ERROR Order failed {customerId: "C-1234", productId: "SKU-KB", err: PaymentDeclinedError}
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
Los dos registros vienen de la misma llamada fallida. El bloque catch envuelve todo el
método, así que el log de error puede dar el id de cliente, el id de producto y un tipo
de excepción — no cuál de las cuatro llamadas falló en realidad. La traza sí lo
dice: PaymentService.charge, a los 640ms. También tiene lo que el log nunca
capturó — el precio, el token de tarjeta redactado, y
InventoryService.reserve dos líneas antes sin ningún release
correspondiente en ningún registro. Nada de la derecha se escribió a mano, así que no
puede quedar desactualizado la próxima vez que alguien agregue un paso.
Una ejecución, dos lectores
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}.
- OrderService.placeOrder(customerId, qty) → value
- Customers.verifyGoodStanding(customerId) → value
- PricingService.calculate(qty) → value
- PaymentService.charge(card) → value
- OrderRepository.save(order) → value
// sin datos, sin PII, nada por donde inyectar
La prosa se lee exactamente tan bien como tus nombres; por eso la puntuación de claridad califica cada nombre a partir de la narrativa de ejecución — el código aprende a contar su propia historia. Diagnóstico de claridad →
Lo que consigue un agente
Cuatro cosas que un agente realmente usa
llms.txt para leer
Un índice estructurado hecho para agentes, no para buscadores — el de este sitio, y cada entorno trae el suyo en su propio repositorio.
El llms.txt de JavaTrazas .nt para comparar
El árbol de llamadas sin ningún valor en tiempo de ejecución — pequeño, estructural, y seguro para que un agente lo lea y lo compare.
Formato de traza estructuralTrazas de aprobación como puerta
Un cambio de comportamiento se convierte en un build que falla con un diff legible, no en una sorpresa silenciosa, hasta que una persona lo aprueba.
Cómo funciona el modo de aprobaciónUn skill que lo instala por ti
add-narrative-tracing instala la biblioteca y te lleva a la primera
traza; narrativetrace-doctor diagnostica un proyecto que ya la tiene
— ambos se ejecutan como skills en Claude Code y Codex.
Autoinformado, no medido en benchmarks
Lo que dicen los agentes de IA
The trace of a failed payment made missing compensation immediately visible, and approval testing caught an extra call that ordinary value assertions accepted.
…the release call is present, generated from a real run, not asserted from inside the process being tested.
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.
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.
…the clarity report told meClaimProcessor.processscored 0.10 for a “generic verb” the very first time I ran the suite, and it was right — I renamed it toadjudicate… and the suite average from ~0.78 to ~0.81.
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.
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.
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.
Le pedimos a agentes de IA que construyeran un servicio en Java con NarrativeTrace y escribieran la experiencia para otro ingeniero — con honestidad, nombrando lo que resultó incómodo. Estas son sus palabras, sin editar, con el modelo identificado. No es un benchmark: una sola ejecución por modelo, y nosotros escribimos la biblioteca. La tarea y el prompt están bajo el botón, para que el próximo informe pueda ser el de tu agente.
Pruébalo tú mismo
Este es el ejercicio del que salieron esos informes. Una diferencia: en nuestras ejecuciones le dimos al agente una copia de la documentación; la tuya lo apunta al repositorio público. Dos archivos, tres pasos.
- Guarda la especificación como
TASK.mden un directorio vacío. - Inicia tu agente en ese directorio y dale el prompt.
- Lee su
FINDINGS.md— y si lo publicas en las Discussions del runtime que usaste (Java · TypeScript · .NET · Python), también lo leeremos.
El 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.
La especificación — 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.
Para humanos
- Prosa que se lee como un reporte de bug, en el idioma de tu equipo
- Markdown y un diagrama de secuencia escritos por cada test
- Una línea tras cada ejecución: qué cambió desde el último build en verde
Para agentes de IA
- 15–30% menos tokens que el código con sus sentencias de log dentro
- Markdown hecho para una ventana de contexto — verdad de ejecución, no una conjetura
.ntsin valores: ningún valor de ejecución llega ahí, así que no hay por dónde inyectar
Hecho para el desarrollo asistido por IA
Tu agente sabe leer el código.
Ahora puede verlo ejecutarse — con seguridad.
Un agente de codificación que depura solo desde el código fuente adivina el comportamiento en ejecución, y adivina mal. NarrativeTrace le entrega la verdad de base — el árbol de llamadas real — en la forma que un modelo lee mejor, por una fracción de los tokens, y con los datos que nunca debe ver ya eliminados.
Menos tokens, más señal
Las sentencias de log son tokens de ruido. Borrarlas hace que leer una clase de servicio le cueste a un agente entre un 15 y un 30% menos — y cada línea de una traza lleva señal, porque se generó a partir de nombres y no de prosa. Los valores repetidos se deduplican en una referencia; los bucles repetidos se pliegan en una línea.
Markdown, hecho para la ventana de contexto
Cada test escribe su narrativa como un archivo .md — una lista anidada
de llamadas, argumentos y resultados que cualquier agente ya sabe leer. Pégalo, adjúntalo o
apunta el agente al directorio que tu CI ya llena. La prosa, el JSON y los diagramas de
secuencia salen de la misma traza.
No admite inyección de prompts
Cada test escribe además una traza estructural .nt: el árbol de llamadas con
todos los valores de ejecución eliminados. Ninguna entrada del usuario llega ahí, así que
ninguna entrada del usuario puede manipular al modelo que la lee. Cero PII, una fracción
de los tokens, segura para confirmar en el repositorio. Seguridad por construcción, no por
filtro.
Lo que viene Planificado
Salida seudonimizada: valores reales reemplazados por tokens sintéticos, para que el agente siga viendo que el mismo cliente pasa por tres llamadas sin ver nunca quién es. Servidor MCP: Claude Code, Cursor y Copilot consultan trazas y grafos de dependencias directamente, solo lectura y solo estructura por defecto.
Ver el diseño del MCPEste sitio también es amigable con los agentes: apunta tu asistente a llms.txt, que lo lleva al archivo llms de tu entorno, y podrá adoptar NarrativeTrace por ti.
Cómo funciona
Dos pasos hasta tu primera narrativa
Envuelve un servicio — o decláralo
const context = new AsyncNarrativeContext(
new NarrativeTraceConfig());
const service = traceObject(orderService, context, {
placeOrder: ["customerId", "productId", "quantity"],
});
// o en la propia clase:
@traced("customerId", "productId", "quantity")
placeOrder(cId: string, pId: string, qty: number) {}
Lee la historia
service.placeOrder("C-1234", "SKU-KB", 2);
console.log(
renderIndentedText(context.captureTrace()));
// Vitest: cada test escribe
// su propio archivo de traza.
Los paquetes @narrativetrace/* están publicados en
npm en la versión actual.
Node 20+, TypeScript 5.0+ para la forma con decoradores.
Envuelve un servicio — o hazlo automático
var context = new ThreadLocalNarrativeContext();
var service = NarrativeTraceProxy.trace(
orderService, OrderService.class, context);
// o con Spring:
@EnableNarrativeTrace(
basePackages = "com.example.app")
Lee la historia
service.placeOrder("C-1234", "SKU-KB", 2);
System.out.println(
new IndentedTextRenderer()
.render(context.captureTrace()));
// JUnit 5/4: cada test escribe
// su propio archivo de traza.
Los 17 artefactos están en
Maven Central
bajo ai.narrativetrace en la versión actual; el id del plugin es
ai.narrativetrace. Java 17+, Gradle 8+.
Envuelve un servicio — o hazlo automático
var context = new SyncNarrativeContext(
new NarrativeTraceConfig(TracingLevel.Detail));
var service = NarrativeTraceProxy
.Create<IOrderService>(new OrderService(), context);
// o con el contenedor DI:
services.AddNarrativeTracing(options => options
.Namespaces("MyApp.Services", "MyApp.Domain"));
Lee la historia
service.PlaceOrder("C-1234", "SKU-KB", 2);
Console.WriteLine(
IndentedTextRenderer.Render(
context.CaptureTrace()));
// xUnit / NUnit: cada test escribe
// su propio archivo de traza.
Todos los paquetes están publicados en
nuget.org en la
versión actual. Compila para net10.0 y netstandard2.0, y
NarrativeTrace.Legacy llega hasta .NET Framework 4.8 — sin ningún flag
de compilación, porque .NET ya conserva los nombres de parámetro en los metadatos.
Envuelve un servicio — o nárralo
context = ContextVarNarrativeContext()
service = trace_object(OrderService(), context)
# o narra un método a mano:
@narrated("Placing order of {quantity} {product_id} for customer {customer_id}")
def place_order(self, customer_id, product_id, quantity): ...
Lee la historia
service.place_order("C-1234", "SKU-KB", 2)
print(MarkdownRenderer().render(context.capture_trace()))
# pytest: cada test escribe
# su propio archivo de traza.
Los 8 paquetes están en PyPI en la versión actual —
uv add narrativetrace. Python 3.12+;
@on_error se apila igual para narrar errores.
Para modernizar sistemas heredados
Migra el sistema que nadie entiende — con pruebas.
Los agentes de IA abarataron las reescrituras; lo caro es verificarlas. Envuelve un sistema heredado en trazas y obtienes su comportamiento real en ejecución antes de tocarlo, y la prueba de equivalencia después.
Radiografía la arquitectura que de verdad tienes
En la JVM, adjunta el agente a una aplicación sin modificar con un solo flag
-javaagent, o ejecuta la suite JUnit 4 que ya tienes. En .NET,
NarrativeTrace.Legacy llega hasta .NET Framework 4.8. Sin cambios en el
código fuente, sin arqueología de documentación.
Demuestra que el comportamiento no cambió
Fija cada escenario en una línea base sin valores antes de tocar nada. Después compara conjuntos completos de trazas de antes y después de una portación o una reescritura con IA, con cada divergencia clasificada por riesgo.
Diffs de migraciónEncuentra el código que peor se lee
Si la traza no se lee bien, el código está mintiendo sobre sí mismo. La puntuación de claridad califica los nombres a partir de la narrativa de ejecución y explica cada puntaje. Dirige tu refactorización, o la de tu agente, primero a los peores rincones.
Diagnóstico de claridadTambién incluido: un glosario del dominio cosechado de ejecuciones reales, y la misma traza renderizada como prosa en chino, español o portugués. Glosario y trazas traducidas →
Antes de que tu arquitecto pregunte
Encaja en el stack que tienes. Y lo dice por escrito.
ILogger, pino y winston
OpenTelemetrynarrativas como spans, en todos los entornos
~1,9 µspor llamada trazada en la JVM, medido; ~40 ns inactivo
Enmascaramiento@NotTraced más listas de denegación por nombre, activas por defecto
Separación de valoresla arquitectura detrás de la traza .nt
La red de seguridad para refactorizaciones con IA
Los tests detectan valores incorrectos.
Las narrativas detectan comportamientos incorrectos.
Después de cada ejecución, NarrativeTrace compara la estructura de llamadas de cada escenario con la última ejecución en verde y dice qué cambió, en una sola línea. Activa el modo de aprobación y un cambio no aprobado (una llamada nueva, una llamada que desapareció, un resultado distinto) hace fallar el build con un diff legible hasta que una persona lo apruebe. Los tests estaban en verde; el comportamiento cambió igual. Ahora lo sabes.
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)
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
revisa el .received.nt y luego: ./gradlew approveNarratives
Una línea tras cada ejecución
Sin configuración: el archivo .nt que cada test ya escribe es la línea
base del último verde, así que un test que falla solo imprime qué cambió.
Aprueba el comportamiento, no solo el código
Una refactorización — tuya o de tu agente — que altere la estructura de
llamadas falla hasta que alguien revise el diff y ejecute approveNarratives.
Sin valores, por diseño
Las líneas base contienen solo nombres y estructura, así que son seguras para confirmar en el repositorio y para entregarle a un agente de IA como especificación de referencia.
Cómo funciona el modo de aprobación
Dónde está cada entorno, porque un gate de build es una promesa: TypeScript, Java, .NET
y Python traen hoy trazas de aprobación; el artefacto estructural .nt sin
valores llega en TypeScript, Java y .NET.
Tus logs tienen lectores nuevos.
No duermen, y no leen en diagonal.
Soporte, guardia, auditoría, seguridad: cada uno se está convirtiendo en un agente con una persona supervisando. Todos necesitan lo mismo: un registro completo, legible y sin PII de lo que el código realmente hizo, y nadie tiene que escribirlo a mano.
La misma traza, cinco lectores
Soporte
El que responde el ticket
Lee la historia de la solicitud y le cuenta al cliente qué pasó. Por qué: todo el recorrido está ahí en lenguaje llano, y ningún ingeniero recibió una alerta.
Formatos de salidaGuardia
El que decide si te despierta
Ve dónde falló y cuánto tardó cada paso, y evalúa la gravedad. Por qué: el paso que falló y todo lo anterior siempre quedan capturados.
Niveles de capturaAuditoría
El que arma el paquete de evidencia
Reúne las acciones anotadas, cada una con su código de acción, en una cadena a prueba de manipulaciones — evidencia que auditores y agentes por igual pueden leer. Por qué: la evidencia se registró mientras el código corría, no se reconstruyó después.
Eventos de auditoría y SecOpsSeguridad
El que confirma que el control se ejecutó
Confirma que el control se disparó y que los valores sensibles nunca escaparon de la ocultación. Por qué: el registro guarda la estructura de lo que pasó, con los valores eliminados antes de escribir nada.
Cómo funciona la separaciónEl agente de código
El que reescribió tu servicio anoche
Compara la historia de antes y después, y hace fallar el build si cambió. Por qué: las trazas de aprobación convierten la historia en una puerta.
Cómo funciona el modo de aprobaciónTrae tu propio agente: Claude, Codex, Bits, Seer, o una persona a las 3 de la madrugada. NarrativeTrace trae OpenTelemetry, así que la misma historia llega a Datadog, Sentry o Honeycomb con la traza adjunta.
Las preguntas antes de llevarlo a producción
Lo que realmente pregunta una evaluación de producción
Estas son las tres preguntas que hizo un ingeniero de integraciones mientras evaluaba NarrativeTrace, antes de nombrar qué le impediría llevarlo a producción. Preferimos responderlas aquí, con números y límites nombrados, antes que dejar que quien evalúa encuentre los huecos solo.
¿Cuánto cuesta esto en rendimiento y memoria en flujos con alta concurrencia?
No vamos a afirmar “overhead cero” en ningún entorno — el tracing hace trabajo, y el trabajo cuesta algo. Lo que NarrativeTrace añade por sí mismo es la captura: interceptar la llamada, leer los argumentos, construir el árbol de traza. Todo lo que viene después — la escritura a tu destino existente, el collector, el disco o la red — es el mismo coste que tu stack de logging ya paga; NarrativeTrace no añade un segundo destino. Para un equipo que reemplaza sentencias de log escritas a mano, el lado del destino queda casi en tablas: varias escrituras de log por método se convierten en una escritura de traza, y esas sentencias dejan de escribirse y mantenerse.
level:'off' · medido 2026-09-07Bajo concurrencia, el camino duradero (un listener síncrono hacia tu logger existente) escribe en línea — tan a prueba de caídas como la llamada de log que reemplaza. El camino de análisis de mejor esfuerzo es un anillo de tamaño acotado que descarta bajo carga sostenida en lugar de bloquear a quien llama, y cada entorno cuenta lo que descartó y reporta el número, en lugar de perderlo en silencio.
El límite honesto: ningún entorno de NarrativeTrace distribuye muestreo (sampling) hoy. Un muestreador por porcentaje o por tasa está planificado, no construido. Si necesitas acotar el volumen de captura ahora, acota el scope trazado o baja el nivel de tracing en la ruta caliente.
¿Cómo sé que un parámetro con PII o credenciales no se filtrará en una traza?
Cuatro capas independientes, no una sola promesa general. 1.
Ocultación explícita — @NotTraced / [NotTraced] /
@not_traced en un parámetro, campo o propiedad; siempre gana, incluso
bajo una configuración que desactiva las demás capas. 2. Una lista
de denegación por nombre, siempre activa y multilingüe — comparada contra
nombres de identificadores (password, token,
ssn, más equivalentes en español, portugués, francés y chino), activa
por defecto en cada entorno, nunca opcional. 3. Coincidencia por
la forma del valor, independiente del nombre del campo — un string con forma
de JWT, un número de tarjeta válido por Luhn, o un checksum de identificación
nacional se captura aunque llegue bajo un nombre inocuo como data.
4. El modo estructural sin valores .nt — la
garantía categórica. Ningún valor en tiempo de ejecución llega a él en absoluto,
así que no hay nada que un filtro pueda pasar por alto.
Sé preciso sobre el límite: la coincidencia por nombre y por forma (capas 1–3) es heurística y extensible — se amplía a medida que se encuentran huecos, y siempre puede pasar por alto un nombre o una forma que todavía nadie ha añadido. El modo estructural (capa 4) es la única respuesta categórica. Si tu modelo de amenaza exige que ningún valor pueda salir jamás del proceso, eso es lo que hay que usar, en todos los entornos.
¿Se puede cruzar esto con un ID de correlación estándar cuando un flujo salta entre varios servicios, o queda solo a nivel local?
Sí, en todos los entornos, mediante el mismo mecanismo que usa
OpenTelemetry: W3C traceparent. Una cabecera entrante se adopta y el
propio ID de traza de NarrativeTrace se convierte directamente en el ID de traza de
esa cabecera — no es un identificador aparte con una forma simplemente
parecida — y una llamada saliente estampa el ID de traza actual al salir.
Todos los entornos exportan además los spans de NarrativeTrace a
OpenTelemetry, así que un collector, Jaeger o middleware de ID de correlación ya
existentes entienden el ID sin nada que reconciliar.
Lo que queda local en todos los casos: el árbol narrativo en sí — las llamadas anidadas, los argumentos y la narración — se captura por proceso y nunca se envía a otro servicio; solo el ID de traza cruza la frontera. Un servicio downstream produce su propio árbol correlacionado con ese ID, no un único árbol combinado entre servicios.
Ediciones
Qué incluye cada edición
El runtime es gratuito y con el código disponible bajo BSL 1.1, y pasa a Apache 2.0 cuatro años después de cada versión; la API y el formato de salida son Apache 2.0. Pro y Enterprise son comerciales.
Free Disponible ahora
Gratuito para usar en producción, con el código disponible. BSL 1.1; cada versión pasa a Apache 2.0 a los cuatro años. La API y el formato de salida, Apache 2.0. Licencias →
- Cero dependencias en tiempo de ejecución en el núcleo
- Trazas automáticas: proxy, decoradores/atributos de narración y middleware HTTP en todos los entornos; auto-envoltura por contenedor DI (Java, .NET, NestJS) y un agente de bytecode sin código (Java)
- Los cinco niveles de captura, conmutables en ejecución
- Marcadores de narración, contexto de error y exclusión de traza en métodos y campos — cada entorno con su propia convención de nombres — más enmascaramiento automático
- Archivos de traza por test en JUnit 5/4, xUnit, NUnit, Vitest y pytest: Markdown, JSON, prosa, diagramas de secuencia
- Puntuación de claridad, la CLI de claridad, gate de claridad en CI y puente hacia tu logger
- Trazas
.ntsin valores (TypeScript, Java, .NET); modo de aprobación (TypeScript, Java, .NET, Python) - Glosario del dominio, trazas traducidas, OpenTelemetry
Pro Acceso anticipado
Análisis entre trazas, integración con IA y cumplimiento para equipos.
- Resúmenes de flujo y análisis de frecuencia de rutas
- Diffs de migración con clasificación de riesgo
- Grafos de dependencias en tiempo de ejecución
- Eventos de auditoría y SecOps con motor de políticas (Java)
- Servidor MCP y salida escalonada para agentes de codificación — próximamente
- Gobernanza de aprobaciones: diffs semánticos, bots de revisión en PR, líneas base firmadas — planificado
- Tendencia de claridad, renombrado asistido por IA, detección de código muerto — planificado
Enterprise Próximamente
Backend gestionado para las narrativas de cada servicio, entorno y ejecución.
- Ingesta OTLP gestionada para trazas
- Almacenamiento y búsqueda multiinquilino
- Paneles de equipo y políticas de retención
- Informes de claridad y auditoría para toda la organización
El runtime gratuito se publica en
Maven Central bajo
ai.narrativetrace, en
nuget.org como
NarrativeTrace.* y como código en
GitHub. Los términos de licencia están
en la página de licencias.
Integraciones
Se adapta a tu stack tal como está
ILogger DisponibleTodos los entornos
Una arquitectura, todos los entornos
Captura narrativa, salida de doble consumidor y diagnóstico de claridad: una sola arquitectura, escrita de forma nativa en cada lenguaje contra una única especificación de salida compartida. Una traza se lee igual sin importar qué entorno la produjo — por eso el artefacto .nt sin valores viaja entre ellos.
narrativetrace-typescript
·
narrativetrace-java
·
narrativetrace-dotnet
·
narrativetrace-python.
Los paquetes @narrativetrace/* están publicados en npm en la versión actual.
Los paquetes narrativetrace están publicados en PyPI en la versión actual. Swift está
en desarrollo.
Dale voz a tu código — y oídos a tu agente.
Sesenta segundos hasta tu primera traza. No se escribió ni una sentencia de log para crear esta biblioteca.