{"id":48919146,"url":"https://github.com/gillkyle/agent-tail","last_synced_at":"2026-04-17T04:07:38.950Z","repository":{"id":336972286,"uuid":"1151873406","full_name":"gillkyle/agent-tail","owner":"gillkyle","description":"Pipe logs from all your dev servers into a single place accessible to your agents.","archived":false,"fork":false,"pushed_at":"2026-03-11T20:19:04.000Z","size":5905,"stargazers_count":82,"open_issues_count":7,"forks_count":5,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-11T15:16:15.827Z","etag":null,"topics":["agents","ai","cli","console","development","dx","logs","tools"],"latest_commit_sha":null,"homepage":"https://agent-tail.vercel.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gillkyle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-07T02:35:57.000Z","updated_at":"2026-03-17T19:18:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gillkyle/agent-tail","commit_stats":null,"previous_names":["gillkyle/agent-tail"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/gillkyle/agent-tail","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gillkyle%2Fagent-tail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gillkyle%2Fagent-tail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gillkyle%2Fagent-tail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gillkyle%2Fagent-tail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gillkyle","download_url":"https://codeload.github.com/gillkyle/agent-tail/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gillkyle%2Fagent-tail/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31914488,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T18:22:33.417Z","status":"online","status_checked_at":"2026-04-17T02:00:06.879Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents","ai","cli","console","development","dx","logs","tools"],"created_at":"2026-04-17T04:07:37.687Z","updated_at":"2026-04-17T04:07:38.931Z","avatar_url":"https://github.com/gillkyle.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u0026\u003e\u003e agent-tail\n\nPipe dev server and browser console logs to log files on your machine that AI coding agents like Claude Code, Amp, and Cursor can read and grep.\n\n[Documentation](https://agent-tail.vercel.app/)\n\n![agent-tail demo](https://github.com/gillkyle/agent-tail/raw/refs/heads/main/assets/agent-tail-demo.gif)\n\n**Try it!**\n\n```bash\nnpx agent-tail run 'server: echo \"Hello world!\"' \u0026\u0026 cat tmp/logs/latest/server.log\n```\n\nThat's the full cycle: run a command, output is captured to a log file, read the file.\n\n## Quickstart\n\n### 1. Install globally or into a project\n\nGlobal install:\n\n```bash\nnpm install -g agent-tail\n```\n\nProject install:\n\n```bash\nnpm install -D agent-tail\n```\n\nGlobal install only changes how you invoke the CLI. Logs still go to `tmp/logs/` relative to the current project by default.\n\n### 2. Wrap your dev command\n\n```bash\nagent-tail run 'fe: npm run dev' 'api: uv run server'\n```\n\nOr, with a project-local install:\n\n```bash\nnpx agent-tail run 'fe: npm run dev' 'api: uv run server'\n```\n\n### 3. Tail the logs\n\n```bash\ntail -f tmp/logs/latest/*.log\ntail -f tmp/logs/latest/browser.log\n\nagent-tail tail -f\nagent-tail tail browser -n 50\n```\n\nUse plain `tail` if you want direct file paths. Use `agent-tail tail` if you want the CLI to resolve the latest session for you. It forwards flags like `-f` and `-n 50` directly to system `tail`.\n\nIf you prefer a hidden folder, use `--log-dir .agent-tail` for the CLI and `logDir: \".agent-tail\"` for the Vite/Next.js plugin config.\n\n## Table of Contents\n\n- [Quickstart](#quickstart)\n- [Server-side and client-side logs](#server-side-and-client-side-logs)\n- [Installation](#installation) — [CLI](#cli-server-side-logs) | [Vite](#vite-plugin-browser-logs) | [Next.js](#nextjs-plugin-browser-logs)\n- [Packages](#packages)\n- [Features](#features) — [Log filtering](#log-filtering) | [Muting services](#muting-services) | [Multi-server](#multi-server-log-aggregation) | [Monorepos](#monorepos--package-runners) | [Searching and tailing](#searching-and-tailing-logs) | [Captured events](#captured-browser-events) | [Session management](#session-management)\n- [How agents use it](#how-agents-use-it)\n- [Agent Setup](#agent-setup)\n- [Configuration](#configuration) — [Vite](#vite-1) | [Next.js](#nextjs-1) | [CLI Options](#cli-options)\n- [CLI Commands](#cli-commands)\n- [Why Files, Not MCP](#why-files-not-mcp)\n- [FAQ](#faq)\n\n## Server-side and client-side logs\n\nagent-tail captures two kinds of logs: **server-side** output (stdout/stderr from your dev commands) and **client-side** output (browser `console.*` calls). The CLI handles server logs and works with any stack. Framework plugins for Vite and Next.js handle browser logs. Use them together to get everything in one place.\n\n```bash\nagent-tail run 'fe: npm run dev' 'api: uv run server'\n# tmp/logs/latest/fe.log        — Vite server output\n# tmp/logs/latest/browser.log   — browser console (via plugin)\n# tmp/logs/latest/api.log       — API server output\n# tmp/logs/latest/combined.log  — everything interleaved\n```\n\n## Installation\n\n### CLI (server-side logs)\n\nThe CLI wraps any command and captures its stdout/stderr to log files. No plugins, no config — works with any language or framework.\n\nGlobal install:\n\n```bash\nnpm install -g agent-tail\n```\n\nProject install:\n\n```bash\nnpm install -D agent-tail\n```\n\nGlobal install still writes logs to `tmp/logs/` in the current project by default. To switch to a hidden folder, pass `--log-dir .agent-tail` or configure `logDir: \".agent-tail\"` in the framework plugin.\n\nWrap one or more commands with unified logging in your `package.json`:\n\n```json\n{\n    \"scripts\": {\n        \"dev\": \"agent-tail run 'fe: npm run dev' 'api: uv run server' 'worker: uv run worker'\"\n    }\n}\n```\n\nCreates a session directory, spawns all services, prefixes output with `[name]`, and writes individual + combined log files.\n\nIt works with any command, not just Node — Python, Go, Ruby, whatever you run in a terminal:\n\n```bash\nnpx agent-tail run 'api: uv run fastapi dev'\n```\n\n### Vite plugin (browser logs)\n\nThe Vite plugin captures browser `console.*` calls by injecting a small script into your page during development. Logs are written to `browser.log` in the same session directory the CLI uses.\n\n```bash\nnpm install -D agent-tail\n```\n\n```ts\n// vite.config.ts\nimport { defineConfig } from \"vite\"\nimport { agentTail } from \"agent-tail/vite\"\n\nexport default defineConfig({\n    plugins: [agentTail()],\n})\n```\n\nThen in another terminal:\n\n```bash\ntail -f tmp/logs/latest/browser.log\n# or\nagent-tail tail browser -f\n```\n\n### Next.js plugin (browser logs)\n\nThe Next.js plugin does the same thing — captures browser `console.*` output — but requires a bit more wiring because of how Next.js handles config, layouts, and API routes.\n\n```bash\nnpm install -D agent-tail\n```\n\n**1. Wrap your Next.js config**\n\n```ts\n// next.config.ts\nimport { withAgentTail } from \"agent-tail/next\"\n\nexport default withAgentTail({\n    // your Next.js config\n})\n```\n\n**2. Add the script to your layout**\n\n```tsx\n// app/layout.tsx\nimport { AgentTailScript } from \"agent-tail/next/script\"\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n    return (\n        \u003chtml\u003e\n            \u003chead\u003e\n                {process.env.NODE_ENV === \"development\" \u0026\u0026 \u003cAgentTailScript /\u003e}\n            \u003c/head\u003e\n            \u003cbody\u003e{children}\u003c/body\u003e\n        \u003c/html\u003e\n    )\n}\n```\n\n**3. Create the API route**\n\n```ts\n// app/api/__browser-logs/route.ts\nexport { POST } from \"agent-tail/next/handler\"\n```\n\n### .gitignore\n\nAdd your log directory to `.gitignore`:\n\n```\n# .gitignore\ntmp/\n```\n\nagent-tail warns on startup if the log directory isn't gitignored. Disable with `warnOnMissingGitignore: false`.\n\n## Packages\n\nInstall the umbrella package to get everything:\n\n```bash\nnpm install -D agent-tail\n```\n\n| Package | Description |\n|---------|-------------|\n| [`agent-tail`](./packages/agent-tail) | Umbrella package — includes CLI, Vite plugin, and Next.js plugin |\n| [`agent-tail-core`](./packages/core) | CLI and shared core (types, formatting, log management) |\n| [`vite-plugin-agent-tail`](./packages/vite-plugin) | Vite plugin — browser console capture |\n| [`next-plugin-agent-tail`](./packages/next-plugin) | Next.js plugin — browser console capture |\n\n## Features\n\n### Readable, greppable logs\n\nLogs are plain text files 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.\n\n```\n[10:30:00.123] [LOG    ] User clicked button\n[10:30:00.456] [WARN   ] Deprecated API call\n[10:30:01.789] [ERROR  ] Failed to fetch data (http://localhost:5173/src/api.ts:42:10)\n    Error: Network error\n        at fetchData (http://localhost:5173/src/api.ts:42:10)\n        at handleClick (http://localhost:5173/src/app.ts:15:5)\n```\n\nLevels are padded to 7 characters for alignment. Stack traces are indented. Source URLs are included for errors.\n\n### Log filtering\n\nNot 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.\n\n```ts\n// vite.config.ts\nagentTail({\n    excludes: [\n        \"[HMR]\",           // substring match\n        \"Download the React DevTools\",\n        \"/^\\\\[vite\\\\]/\",     // regex match\n    ],\n})\n```\n\nThe CLI supports it too, with repeatable `--exclude` flags:\n\n```bash\nagent-tail run --exclude \"[HMR]\" --exclude \"/^DEBUG/\" 'fe: npm run dev'\n```\n\nPlain strings are substring matches. Patterns starting with `/` are parsed as regex (e.g. `/^HMR/i`).\n\n### Muting services\n\nDifferent 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.\n\n```bash\nagent-tail run --mute fe --mute worker 'fe: npm run dev' 'api: uv run server' 'worker: uv run worker'\n```\n\nOnly `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.\n\n\u003e **--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.\n\n### Multi-server log aggregation\n\nMost projects run more than one process — a frontend, an API, maybe a worker. agent-tail can aggregate all of them into one session directory.\n\n**1. Use `agent-tail run` (recommended)**\n\nRun everything from one command. All output goes to the same session automatically.\n\n**2. Wrap services independently**\n\nRun each service in its own terminal. The `wrap` command detects the existing session:\n\n```bash\n# Terminal 1: Start the frontend (creates the session)\nnpm run dev\n\n# Terminal 2: Wrap the API server (reuses the session)\nnpx agent-tail wrap api -- uv run fastapi-server\n\n# Terminal 3: Tail everything\ntail -f tmp/logs/latest/*.log\n# or\nagent-tail tail -f\n```\n\n**3. Direct file writes (no CLI needed)**\n\nPoint your server's logging at the `latest` symlink. Works with any language:\n\n\u003cdetails\u003e\n\u003csummary\u003ePython, Node.js, Ruby, Go examples\u003c/summary\u003e\n\n#### Python (FastAPI, Django, Flask)\n\n```python\nimport os\nimport logging\n\nlog_dir = os.path.join(os.getcwd(), \"tmp\", \"logs\", \"latest\")\nos.makedirs(log_dir, exist_ok=True)\n\nhandler = logging.FileHandler(os.path.join(log_dir, \"api.log\"))\nhandler.setFormatter(logging.Formatter(\n    \"[%(asctime)s] [%(levelname)-7s] %(message)s\",\n    datefmt=\"%H:%M:%S\"\n))\n\nlogger = logging.getLogger(\"api\")\nlogger.addHandler(handler)\nlogger.setLevel(logging.DEBUG)\n```\n\n#### Node.js (Express, Fastify, etc.)\n\n```ts\nimport fs from \"node:fs\"\nimport path from \"node:path\"\n\nconst log_dir = path.resolve(\"tmp/logs/latest\")\nfs.mkdirSync(log_dir, { recursive: true })\n\nconst log_stream = fs.createWriteStream(\n    path.join(log_dir, \"server.log\"),\n    { flags: \"a\" }\n)\n\nfunction log(level: string, ...args: unknown[]) {\n    const time = new Date().toTimeString().slice(0, 12)\n    const msg = args.map(a =\u003e typeof a === \"string\" ? a : JSON.stringify(a)).join(\" \")\n    log_stream.write(`[${time}] [${level.toUpperCase().padEnd(7)}] ${msg}\\n`)\n}\n```\n\n#### Ruby (Rails, Sinatra)\n\n```ruby\nlog_dir = File.join(Dir.pwd, \"tmp\", \"logs\", \"latest\")\nFileUtils.mkdir_p(log_dir)\n\nlogger = Logger.new(File.join(log_dir, \"rails.log\"))\nlogger.formatter = proc { |severity, time, _, msg|\n    \"[#{time.strftime('%H:%M:%S.%L')}] [#{severity.ljust(7)}] #{msg}\\n\"\n}\n```\n\n#### Go\n\n```go\nlogDir := filepath.Join(\".\", \"tmp\", \"logs\", \"latest\")\nos.MkdirAll(logDir, 0755)\n\nf, _ := os.OpenFile(filepath.Join(logDir, \"server.log\"),\n    os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)\nlog.SetOutput(f)\n```\n\n\u003c/details\u003e\n\n### Monorepos \u0026 package runners\n\nIf you use Turborepo, Nx, Lerna, or any other monorepo runner, you can use `agent-tail init` to create a shared session at the monorepo root, then let the runner start each package with `agent-tail wrap`:\n\n```json\n// Root package.json\n{\n    \"scripts\": {\n        \"dev\": \"agent-tail init \u0026\u0026 turbo dev\"\n    }\n}\n```\n\nEach package's `dev` script uses `agent-tail wrap` with `--log-dir` pointing back to the root log directory:\n\n```json\n// apps/web/package.json\n{\n    \"scripts\": {\n        \"dev\": \"agent-tail wrap web --log-dir ../../tmp/logs -- vite\"\n    }\n}\n```\n\n`agent-tail init` creates the session and `latest` symlink once, then each `agent-tail wrap` discovers the existing session via the symlink. All services write to the same session directory — `web.log`, `api.log`, `worker.log`, `combined.log`, and `browser.log` (if using a framework plugin) all end up in `tmp/logs/latest/`.\n\nThe `--log-dir` path is relative to each package, so adjust based on your monorepo depth. This pattern works with any runner that starts multiple packages in parallel.\n\n### Searching and tailing logs\n\nBoth work: direct Unix tools on the log files themselves, or `agent-tail tail` when you want the CLI to resolve the latest session for you.\n\n```bash\n# Follow all logs in real time\ntail -f tmp/logs/latest/*.log\nagent-tail tail -f\n\n# Follow a specific service\ntail -f tmp/logs/latest/browser.log\nagent-tail tail browser -f\n\n# The wrapper forwards directly to system tail\nagent-tail tail combined -n 100\n\n# Find all errors across every service\ngrep -r \"ERROR\" tmp/logs/latest/\n\n# Case-insensitive search\ngrep -ri \"failed\\|timeout\\|exception\" tmp/logs/latest/\n\n# Show context around each match\ngrep -r -C 5 \"ERROR\" tmp/logs/latest/\n\n# Only ERROR and WARN lines\nawk '/\\[ERROR|\\[WARN/' tmp/logs/latest/browser.log\n\n# Count errors per service\ngrep -rc \"ERROR\" tmp/logs/latest/\n\n# Use ripgrep for faster searches\nrg \"ERROR|WARN\" tmp/logs/latest/\n```\n\n### Captured browser events\n\nThe framework plugins capture more than just `console.*` calls:\n\n- **Unhandled errors** (`window.onerror`) — logged as `UNCAUGHT_ERROR` with full stack traces\n- **Unhandled promise rejections** — logged as `UNHANDLED_REJECTION`\n\nThese are the errors that silently break your app in the browser. Disable with `captureErrors: false` and `captureRejections: false`.\n\n### Session management\n\nEach `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.\n\n- **Timestamped directories** — e.g. `2024-01-15T10-30-00-123Z/`\n- **Latest symlink** — updated on every new session, always points to the newest one\n- **Auto-pruning** — old sessions beyond the limit are removed (default: keep 10)\n- **Gitignore detection** — warns if your log directory isn't in `.gitignore`\n\n## How agents use it\n\nagent-tail works best with AI tools that have access to your codebase — Claude Code, Cursor, Amp, and others. When your agent reads the log files, it gets:\n\n- Timestamped errors with source locations\n- Stack traces to trace the call path\n- Server and browser output side by side\n- The exact error message — no paraphrasing, no guessing\n\n**Without agent-tail**, you copy-paste from browser devtools, describe the error in prose (\"there's a 500 on the users page\"), and hope the agent guesses right. Or you install an MCP browser tool that requires a running connection, can't be piped through `grep`, and gives you structured results you can't compose with other tools.\n\n**With agent-tail**, every time you start your dev server, agent-tail creates a new session directory and symlinks `tmp/logs/latest/` to it. The agent runs `grep ERROR tmp/logs/latest/` and gets the exact stack trace, source file, and line number. Plain files — no connection state, no tool registration, no token overhead. Agents already know how to read files.\n\n## Agent Setup\n\nInstall the agent-tail skill to give your AI coding agent built-in knowledge of how to set up and use agent-tail:\n\n```bash\nnpx skills add gillkyle/agent-tail\n```\n\nThe skill activates automatically when you ask about capturing logs, debugging runtime errors, or checking console output. Works with Claude Code, Cursor, Codex, and [other supported agents](https://skills.sh).\n\nOr add a snippet to your project's agent instructions file manually (`CLAUDE.md`, `.cursorrules`, `.github/copilot-instructions.md`, or equivalent):\n\n```markdown\n## Dev Logs\n\nAll dev server output is captured to `tmp/logs/`. The latest session\nis symlinked at `tmp/logs/latest/`.\n\nWhen debugging, check logs before guessing about runtime behavior:\n\n    grep -ri \"error\\|warn\" tmp/logs/latest/\n    tail -50 tmp/logs/latest/browser.log\n    agent-tail tail browser -n 50\n```\n\n## Configuration\n\nAll options are optional with sensible defaults.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eVite\u003c/strong\u003e\u003c/summary\u003e\n\nAll options go in a single call — the plugin handles both server and client:\n\n```ts\nagentTail({\n    logDir: \"tmp/logs\",             // Directory for log storage (relative to project root)\n    logFileName: \"browser.log\",     // Log file name within each session\n    maxLogSessions: 10,             // Max session directories to keep\n    endpoint: \"/__browser-logs\",    // Server endpoint for log ingestion\n    flushInterval: 500,             // Client-side flush interval (ms)\n    maxBatchSize: 50,               // Max batch size before immediate flush\n    maxSerializeLength: 2000,       // Max serialized object length\n    warnOnMissingGitignore: true,   // Warn if logDir isn't gitignored\n    levels: [\"log\", \"warn\", \"error\", \"info\", \"debug\"],\n    captureErrors: true,            // Capture unhandled window errors\n    captureRejections: true,        // Capture unhandled promise rejections\n    excludes: [],                   // Patterns to exclude (substring or /regex/)\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eNext.js\u003c/strong\u003e\u003c/summary\u003e\n\nNext.js doesn't have a unified plugin model, so options are split across two call sites depending on whether they affect the server or the client.\n\n**Server-side options** go in the config wrapper (second argument):\n\n```ts\n// next.config.ts\nimport { withAgentTail } from \"agent-tail/next\"\n\nexport default withAgentTail(\n    { /* your Next.js config */ },\n    {\n        logDir: \"tmp/logs\",             // Directory for log storage (relative to project root)\n        logFileName: \"browser.log\",     // Log file name within each session\n        maxLogSessions: 10,             // Max session directories to keep\n        endpoint: \"/__browser-logs\",    // Server endpoint for log ingestion\n        warnOnMissingGitignore: true,   // Warn if logDir isn't gitignored\n        excludes: [],                   // Patterns to exclude (substring or /regex/)\n    }\n)\n```\n\n**Client-side options** go on the script component:\n\n```tsx\n// app/layout.tsx\nimport { AgentTailScript } from \"agent-tail/next/script\"\n\n{process.env.NODE_ENV === \"development\" \u0026\u0026 (\n    \u003cAgentTailScript\n        options={{\n            flushInterval: 500,             // Client-side flush interval (ms)\n            maxBatchSize: 50,               // Max batch size before immediate flush\n            maxSerializeLength: 2000,       // Max serialized object length\n            levels: [\"log\", \"warn\", \"error\", \"info\", \"debug\"],\n            captureErrors: true,            // Capture unhandled window errors\n            captureRejections: true,        // Capture unhandled promise rejections\n        }}\n    /\u003e\n)}\n```\n\nThe API route handler requires no configuration — it reads the log path from environment variables set by the config wrapper:\n\n```ts\n// app/api/__browser-logs/route.ts\nexport { POST } from \"agent-tail/next/handler\"\n```\n\n\u003c/details\u003e\n\n### CLI Options\n\nShared options for `agent-tail run`, `agent-tail wrap`, and `agent-tail init`:\n\n```\n--log-dir \u003cdir\u003e       Log directory relative to cwd (default: tmp/logs)\n--max-sessions \u003cn\u003e    Max sessions to keep (default: 10)\n--no-combined         Don't write to combined.log\n--exclude \u003cpattern\u003e   Exclude lines matching pattern (repeatable, /regex/ or substring)\n--mute \u003cname\u003e         Mute a service from terminal and combined.log (repeatable, still logs to \u003cname\u003e.log)\n```\n\n## CLI Commands\n\n### `agent-tail run`\n\nSpawn one or more commands with unified logging. Each argument is a `name: command` pair:\n\n```bash\nagent-tail run 'fe: npm run dev' 'api: uv run server' 'worker: uv run worker'\n```\n\nCreates a session directory, spawns all services, prefixes output with `[name]`, and writes individual + combined log files.\n\nUse `--mute` to silence specific services from the terminal while still capturing their logs:\n\n```bash\nagent-tail run --mute fe --mute worker 'fe: npm run dev' 'api: uv run server' 'worker: uv run worker'\n```\n\n### `agent-tail wrap`\n\nWrap a single command and write its output to a named log file in the current session:\n\n```bash\nagent-tail wrap server -- npm run dev\n```\n\nUseful when you want to add a service to an existing session created by `agent-tail init` or a framework plugin.\n\n### `agent-tail init`\n\nCreate a new log session directory without running any commands:\n\n```bash\nagent-tail init\n```\n\nSets up the session directory and `latest` symlink. Useful when other tools (like framework plugins) will write to the session.\n\n### `agent-tail tail`\n\nTail the latest session's logs via the system `tail` command:\n\n```bash\nagent-tail tail -f\nagent-tail tail browser -n 50\nagent-tail tail combined -f\n```\n\nWith no query, `agent-tail tail` tails every `.log` file in the latest session. With a query, it looks for an exact `\u003cquery\u003e.log` match first, then falls back to substring matches. Any remaining flags are passed straight to `tail`.\n\n## Why Files, Not MCP\n\nPlain log files beat a protocol server for this use case. ([longer discussion](https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/))\n\n- **Universal** — works with any agent, any editor, `tail`, `grep`, `jq`, `awk`. MCP only works with agents that explicitly support it.\n- **No moving parts** — `appendFile()` vs. a server process + protocol + tool registration + connection lifecycle. Any of those can fail silently.\n- **Zero connection state** — the file is a persistent timeline, not a live stream you can miss. No \"was I connected when the error happened?\"\n- **Composable** — pipe output through `grep`, chain with `awk`, redirect to another file, or process with code. MCP tool results have to pass through the agent's context window to be combined or persisted.\n- **Token efficient** — reading a file costs nothing in tool descriptions. MCP servers register tool schemas that consume context on every turn (popular browser-tools MCP servers use 13–18k tokens just in tool definitions).\n- **Deterministic for agents** — \"read the last 200 lines of `tmp/logs/latest/browser.log`\" beats hoping the model calls a tool correctly. Agents already know how to read files and use `grep`.\n- **Human + AI see the same bytes** — no reformatting, no schema negotiation. \"Check line 428\" just works.\n- **History for free** — full session history on disk. MCP sessions disappear after a crash. Agents reason better with context they can scroll back through.\n- **Easy to extend** — changing the log format or adding a new log file is a one-line change. Extending an MCP server means understanding its codebase, protocol layer, and tool registration.\n- **No permission friction** — reading a local file is passive context. MCP tools may need approval, rate limiting, or sandbox exceptions.\n- **Works across every stack** — every language can append to a file. Not every stack has a clean MCP SDK.\n\nThat said, MCP has real strengths in other contexts. It provides structured, queryable interfaces that are useful for complex data sources (databases, APIs, search indexes) where flat files would be unwieldy. It also works in environments where the agent has no filesystem access, like cloud-hosted IDEs or remote sandboxes. For log capture specifically, files are the better fit — logs are inherently append-only text, and the entire Unix toolchain already exists to search, filter, and tail them.\n\n## FAQ\n\nSee the [full FAQ](https://agent-tail.vercel.app/faq) on the docs site.\n\n**Which package should I install?** Install `agent-tail` — it's the umbrella package that includes the CLI, Vite plugin, and Next.js plugin. One install, all features.\n\n**Can I install the smaller packages separately?** Yes. `agent-tail-core` for CLI only, `vite-plugin-agent-tail` for Vite only, `next-plugin-agent-tail` for Next.js only. The umbrella re-exports everything.\n\n## License\n\n© 2026 Kyle Gill\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgillkyle%2Fagent-tail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgillkyle%2Fagent-tail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgillkyle%2Fagent-tail/lists"}