@bizrk/agent-ledger
v0.1.2
Published
Core runtime logic and buffer for Agent Ledger
Readme
Agent Ledger
Agent Ledger is a runtime logging system designed for strict, AI-friendly, and filterable application logs. It's not just a console wrapper—it behaves as an in-memory runtime ledger that records application behavior across both core host applications and decoupled plugins/products without losing structured state.
It optimizes for:
- Predictable Structuring: All entries adhere strictly to a
LedgerEntryformat (level,product,category,source,message,metadata). - Scoped Defaults: Deep nesting features allow you to construct loggers scoped to a flow or file, removing the need to repeatedly pass boilerplate strings.
- Opt-In Safety: Configurable enablement functions allow client-side logs to remain totally silent without crashing unless explicitly activated (e.g. through specific query parameters and cookies).
Packages
The functionality is split across two main packages in the monorepo:
agent-ledger— The core runtime, types, buffer, and logic.agent-ledger-web— Optional browser helpers specifically for reading URLs, syncing debug cookies, and formatting toconsole.log.
1. Global Setup & Enablement (Host App)
Agent Ledger must be configured once globally by the host application early in the lifecycle.
If you are running in a browser, use the agent-ledger-web helpers for URL-driven enablement. For example, ensuring logs never output on localhost unless a developer explicitly triggers ?agentledger=true first:
import { configureAgentLedger, getAgentLedger } from 'agent-ledger';
import {
getBrowserContext,
parseBrowserOverrides,
hasDebugCookie,
setupConsoleOutput,
emitStartupBanner,
syncDebugCookie
} from 'agent-ledger-web';
// Optional: Mount the styled terminal output formatter
setupConsoleOutput();
// Sync opt-in query param (e.g. `?agentledger=true`) to a persistent cookie.
// If a user hits `?agentledger=false`, the cookie is deleted.
const SECRET_COOKIE_NAME = 'bizrk_ledger_auth';
syncDebugCookie(SECRET_COOKIE_NAME, 'agentledger');
// Read current URL shapes and the newly persisted cookie
const browserContext = getBrowserContext();
const overrides = parseBrowserOverrides(); // Pulls ?debug=... params
// Configure the engine
configureAgentLedger({
defaultProduct: 'site-core',
level: 'debug', // Default minimum level
categories: ['app', 'flow', 'nav', 'ui', 'error'],
outputs: ['console', 'buffer'], // Where logs get routed
allowLogging: () => {
// Only output if they have previously enabled the secret cookie!
return hasDebugCookie(SECRET_COOKIE_NAME, browserContext);
}
}, overrides);
// Output configuration to console cleanly
emitStartupBanner();2. Using the Loggers
Agent ledger loggers automatically swallow calls when logging is disabled, meaning you never have to write if (logsEnabled) { ... } wrappers in your product components. Note: Error objects passed as metadata are automatically and safely preserved!
The Default Logger
If you ask for a default logger, it automatically assumes your defaultProduct boundary.
import { getAgentLedger } from 'agent-ledger';
const logger = getAgentLedger();
// Unscoped Call Signature:
// logger.<level>(category, source, message, metadata?)
logger.info('nav', 'router', 'Navigated to simulated page', { path: '/home' });
logger.debug('ui', 'button', 'User clicked UI element', { x: 100, y: 200 });
logger.error('error', 'app', 'Simulated failure occurred', new Error('Something broke!'));Plugin / Product Registration
If you are writing a sub-module or plugin within the app, you can register it independently and fetch its own bound logger.
import { registerAgentLedgerProduct, getAgentLedger } from 'agent-ledger';
// Register the product (idempotent, doesn't crash if repeated)
registerAgentLedgerProduct({ product: 'leancss' });
// Get a logger permanently bound to the product
const pluginLogger = getAgentLedger('leancss');Scoping Contexts
To avoid constantly repeating categories and sources across a file, you can scope a logger down infinitely.
// Scope to a specific source boundary and category!
const compileLogger = getAgentLedger('leancss').scope({
source: 'Compiler.run',
category: 'flow'
});
// Because 'source' and 'category' are both bound, the shape shrinks to just (message, metadata)
compileLogger.info('start', { fileCount: 12 });
compileLogger.info('complete', { outputFiles: 8 });3. Metadata Redaction
Agent Ledger automatically intercepts the payload before it enters the buffer or console and masks sensitive data. If any keys inside your metadata dictionary match standard vulnerable strings (like password, token, authorization, cookie), their values are scrubbed and replaced with [REDACTED].
If an Error object is passed into metadata, it successfully extracts the stack, message, and name properties to ensure they serialize properly and don't collapse when stringified.
4. The In-Memory Ledger Buffer
When the buffer output is enabled in configuration, logs populate an internal rolling ring-buffer (capable of retaining recent events in-memory up to a maximum size).
This allows you to easily pull a JSON payload or formatted text directly from the developer console (or AI Agent prompts) at runtime!
import { globalBuffer } from 'agent-ledger';
// Output an AI-friendly plaintext summary of current application flow
console.log(globalBuffer.exportText());
// Output strict JSON telemetry
console.log(globalBuffer.exportJSON());5. URL Debug Testing API
When utilizing the agent-ledger-web browser package, the router supports the following native query structures to dynamically filter system logging without touching code:
?agentledger=true— Sets a cookie activating the whole system (as implemented in setup)?debugLevel=trace— Overrides the global configuration to output everything down to trace.?debugCategories=flow,error— Mutes all telemetry except flow and error levels.?debug=leancss— Mutes the core system and focuses telemetry only on the LeanCSS product logs.?debug=true— Un-mutes product filtering entirely, defaulting back to all available products.
