Features

What you get with agent-tail

Readable, greppable logs

Logs are plain text files written to tmp/logs/latest/ relative to your project root, with a consistent format. Timestamps, levels, source locations, and stack traces are all there — easy for you to scan and easy for an AI to parse.

[10:30:00.123] [LOG ] User clicked button
[10:30:00.456] [WARN ] Deprecated API call
[10:30:01.789] [ERROR ] Failed to fetch data (http://localhost:5173/src/api.ts:42:10)
Error: Network error
at fetchData (http://localhost:5173/src/api.ts:42:10)
at handleClick (http://localhost:5173/src/app.ts:15:5)

Levels are padded to 7 characters for alignment. Stack traces are indented. Source URLs are included for errors.

Log filtering

Not every log line is useful — HMR updates, noisy debug output, and framework internals add clutter that wastes AI context. The excludes option lets you filter them out before they hit disk.

The CLI supports it too, with repeatable --exclude flags:

agent-tail run --exclude "[HMR]" --exclude "/^DEBUG/" 'fe: npm run dev'

Plain strings are substring matches. Patterns starting with / are parsed as regex (e.g. /^HMR/i).

Muting services

Different from --exclude which filters log content, --mute silences entire services from your terminal and combined.log. Muted services still run and their output is still captured to individual log files — they just don’t clutter your terminal while you’re debugging something else.

agent-tail run --mute fe --mute worker 'fe: npm run dev' 'api: uv run server' 'worker: uv run worker'

In this example, only api output appears in your terminal. All three services still log to fe.log, api.log, and worker.log — so agents can still read everything.

--exclude filters noisy log lines by content (e.g. HMR messages). --mute hides entire services by name. Use --exclude to clean up what gets written to disk. Use --mute to focus your terminal on one service while debugging.

Multi-server log aggregation

Most projects run more than one process — a frontend, an API, maybe a worker. agent-tail can aggregate all of them into one session directory.

1. Use agent-tail run (recommended)

Run everything from one command. All output goes to the same session automatically.

2. Wrap services independently

Run each service in its own terminal. The wrap command detects the existing session:

# Terminal 1: Start the frontend (creates the session)
npm run dev
# Terminal 2: Wrap the API server (reuses the session)
npx agent-tail wrap api -- uv run fastapi-server
# Terminal 3: Tail everything
tail -f tmp/logs/latest/*.log

3. Direct file writes (no CLI needed)

Point your server's logging at the latest symlink. Works with any language:

# Python
log_dir = os.path.join(os.getcwd(), "tmp", "logs", "latest")
handler = logging.FileHandler(os.path.join(log_dir, "api.log"))
# Node.js
const log_stream = fs.createWriteStream(
path.join("tmp/logs/latest", "server.log"),
{ flags: "a" }
)

Searching and tailing logs

Because logs are plain files, every standard Unix tool works out of the box. Here are the most useful patterns:

# Follow all logs in real time
tail -f tmp/logs/latest/*.log
# Follow a specific service
tail -f tmp/logs/latest/browser.log
# Find all errors across every service
grep -r "ERROR" tmp/logs/latest/
# Case-insensitive search
grep -ri "failed\|timeout\|exception" tmp/logs/latest/
# Show context around each match
grep -r -C 5 "ERROR" tmp/logs/latest/
# Only ERROR and WARN lines
awk '/\[ERROR|\[WARN/' tmp/logs/latest/browser.log
# Count errors per service
grep -rc "ERROR" tmp/logs/latest/
# Use ripgrep for faster searches
rg "ERROR|WARN" tmp/logs/latest/

Captured browser events

The framework plugins capture more than just console.* calls:

  • Unhandled errors (window.onerror) — logged as UNCAUGHT_ERROR with full stack traces
  • Unhandled promise rejections — logged as UNHANDLED_REJECTION

These are the errors that silently break your app in the browser. Disable with captureErrors: false and captureRejections: false.

Session management

Each agent-tail run (or dev server start with a framework plugin) creates a new session — a timestamped directory under tmp/logs/ that holds all log files for that run. A latest symlink always points to the most recent session, so tmp/logs/latest/ is always the right path to give your agent.

  • Timestamped directories — e.g. 2024-01-15T10-30-00-123Z/
  • Latest symlink — updated on every new session, always points to the newest one
  • Auto-pruning — old sessions beyond the limit are removed (default: keep 10)
  • Gitignore detection — warns if your log directory isn't in .gitignore