The problem
When an agent loop does something unexpected, “why did it do that” is hard to answer after the fact if nothing recorded what it was thinking at each step. Console output scrolls away; without a persistent log, a confusing run is gone the moment the process exits.
Expected outcome
By the end of this guide you will have a simple append-only decision log any agent loop can write to, and read back afterward to understand exactly what it decided and why, at every step.
Requirements and costs
- Node.js (version 18 or newer).
- Cost: free. No dependencies.
Step-by-step implementation
- Download the starter from the link below.
- Log a decision at every meaningful step in your agent loop:
const { logDecision } = require("./decision-log"); logDecision({ step: "choose_tool", decision: "search", reason: "query looked like a lookup" }); - Read the log back any time, including after the process has exited:
const { readLog } = require("./decision-log"); const entries = readLog(); - Add whatever fields matter to you —
step,decisionandreasonare just a suggested shape;logDecisionaccepts any plain object.
A real example
logDecision({ step: "choose_tool", decision: "search", reason: "query looked like a lookup" });
logDecision({ step: "choose_tool", decision: "calculator", reason: "query contained numbers and an operator" });
readLog()
// [
// { "at": "2026-10-05T04:47:19.115Z", "step": "choose_tool", "decision": "search", "reason": "..." },
// { "at": "2026-10-05T04:47:19.115Z", "step": "choose_tool", "decision": "calculator", "reason": "..." }
// ]
Verification and troubleshooting
What we tested, on 5 October 2026 (record TNT-TEST-2026-10-05-015): logged two real decisions in sequence, then read the log back and confirmed both entries were present, in the order written, each with a timestamp and the exact fields passed in — proving the log genuinely persists across separate calls, not just within one.
Troubleshooting:
- The log file grows forever. This is deliberately append-only and doesn’t rotate itself; for a long-running agent, periodically archive or truncate
decisions.jsonlyourself, or pointlogDecisionat a new dated filename each day. readLog()throws on a line. That means something else wrote a non-JSON line into the file directly — only ever write to it throughlogDecision, never by hand.- You need to log from multiple processes at once.
appendFileSyncis safe for occasional concurrent writes from a few processes, but isn’t a substitute for a real logging service under heavy concurrent load.
Limitations and alternatives
This is a flat file, not a queryable database — fine for “read it back and scroll through,” not for searching thousands of entries by field. For that scale, pipe the same JSONL format into a real log aggregation tool instead of querying the file directly.
Free resources
The download contains the logger module.
Download the decision logger (ZIP, 1 KB)
Is there a paid version?
Not yet. This is the complete method. TNT Review has sold nothing to date and has no checkout, so any price we discuss in future should be read as a hypothesis, not an offer.