Skip to main content

Monitoring & Logs

Smithers provides structured logging for debugging and observability.

Log Directory Layout

By default, logs are written to .smithers/logs/. When an execution ID is provided, logs are scoped:
.smithers/
├── logs/                          # Default log directory
│   └── <session-id>-001-*.txt     # Numbered log files
└── executions/
    └── <execution-id>/
        └── logs/                  # Execution-scoped logs
            ├── stream.ndjson      # NDJSON stream events
            └── stream.summary.json # Event counts

NDJSON Stream Format

Stream events are logged as newline-delimited JSON:
{"timestamp":1234567890,"type":"text-end","content":"..."}
{"timestamp":1234567891,"type":"tool-call","name":"Read","input":{...}}
{"timestamp":1234567892,"type":"tool-result","output":"..."}

Event Types

TypeDescription
text-endCompleted text block
reasoning-endCompleted reasoning block
tool-callTool invocation
tool-resultTool output
errorError event

Summary Files

After stream completion, a summary is written:
{
  "textBlocks": 5,
  "reasoningBlocks": 2,
  "toolCalls": 12,
  "toolResults": 12,
  "errors": 0
}

Summarization

For large outputs, Smithers can summarize content using Claude Haiku.

Configuration

Environment VariableDefaultDescription
ANTHROPIC_API_KEY-Required for AI summarization
SMITHERS_SUMMARY_THRESHOLD50Line count threshold for summarization
SMITHERS_SUMMARY_CHAR_THRESHOLD4000Character threshold for summarization
SMITHERS_SUMMARY_MAX_CHARS20000Max chars sent to summarizer
SMITHERS_SUMMARY_MODELclaude-3-haiku-20240307Model for summarization

Fallback Behavior

If ANTHROPIC_API_KEY is not set, outputs are truncated instead of summarized:
[first 500 chars]
[... truncated, see full output]

LogWriter API

import { LogWriter } from 'smithers-orchestrator/monitor'

const logger = new LogWriter('.smithers/logs', executionId)

// Write a log file
logger.writeLog('agent-output', content, { agent: 'claude' })

// Append to persistent stream
logger.appendLog('stream.log', 'new content')

// Write NDJSON stream part
logger.appendStreamPart('events.ndjson', {
  type: 'tool-call',
  name: 'Read',
  input: { file: 'src/main.ts' }
})

// Write summary
logger.writeStreamSummary('events', parts)

// Cleanup
await logger.flushAllStreams()

Inspecting Logs

# View NDJSON stream
cat .smithers/executions/<id>/logs/stream.ndjson | jq

# View summary
cat .smithers/executions/<id>/logs/stream.summary.json

# Tail logs during execution
tail -f .smithers/logs/*.txt