trail
Trail wraps any command (trail run -- <cmd>) or Docker container and captures its stdout/stderr into per-session JSONL files on local disk.
Open source Repository Open in the app JSON README (API)
About
Trail wraps any command (trail run -- <cmd>) or Docker container and captures its stdout/stderr into per-session JSONL files on local disk. The bundled MCP server exposes list_sessions and get_logs so Claude Code can filter by level, regex, time window, or line range — server-side, without burning context window. Includes a debug-with-trail skill that walks Claude through a 4-phase debug flow: read existing logs first, add marked instrumentation only when needed, and a mandatory cleanup step verified by grep. Local-first, no cloud, no daemon, single static binary.
Details
- Kind
- Plugins
- Topic
- Cloud & DevOps
- Publisher
- pratham-mishra04
- Origin
- marketplace
- Category
- ferramentas
- Stars
- 8
- Forks
- 1
- Open pull requests
- 2
- Last push
- 2026-06-09T19:24:43Z
- Repository state
- ativo
- Language
- Go
- License
- MIT
- Added
- 2026-08-30 01:48:58
- Updated
- 2026-08-30 01:48:58
- Origin id
pratham-mishra04/trail/trail
README
# trail
Local stdout/stderr capture for AI coding agents.
Run any process under `trail`, then ask Codex, Claude Code, Cursor, Windsurf, or another MCP-capable agent to query the captured logs without pasting terminal output into chat.
Single static binary. Plain JSONL files on disk. No daemon, no database, no cloud.
## Guided Debugging At A Glance
Trail is most useful when the agent needs to move beyond "read the last error" and run a disciplined debugging loop: inspect captured logs, keep a ledger, add temporary probes only when needed, wait for the dev server to restart, reproduce the issue, verify the fix, and remove every probe.

The important constraint is cleanup. Every temporary log line carries a unique `TRAIL-DEBUG-<id>` marker, and the workflow is not done until the agent verifies that marker is gone from the repo.
## Fast Setup
All integrations need the `trail` binary on your `PATH` first:
```bash
curl -fsSL https://raw.githubusercontent.com/Pratham-Mishra04/trail/main/install.sh | sh
trail version
```
Then add the integration for your agent.
### Codex
```bash
codex plugin marketplace add Pratham-Mishra04/trail --ref main
codex plugin add trail@pratham
```
Start a new Codex thread, then ask:
```text
Use Trail to list my captured sessions.
```
### Claude Code
```text
/plugin marketplace add Pratham-Mishra04/trail
/plugin install trail@pratham
/reload-plugins
```
Verify by asking:
```text
What skills are available?
```
You should see `pratham:trail:debug-with-trail`.
### Other MCP Agents
Use the manual MCP config in [Editor Setup](#editor-setup). You will get the `list_sessions` and `get_logs` tools, but not the bundled Codex/Claude guided debugging skill.

## First Capture
Wrap the process you want to debug:
```bash
trail run -- npm run dev
```
Trail prints a session id and file path, then forwards your app's stdout/stderr normally while also capturing every line:
```text
trail: capturing "npm run dev" -> 39f6875e-3417-4146-867b-c430971b7489 (file: /Users/you/.config/trail/sessions/39f6875e-3417-4146-867b-c430971b7489.jsonl)
```
Now ask your agent:
```text
List my Trail sessions, then show me the errors from the most recent one.
```
Or query from the terminal:
```bash
trail sessions
trail logs --session 39f6875e-3417-4146-867b-c430971b7489 --level error
trail logs --session 39f6875e-3417-4146-867b-c430971b7489 --query "ECONNREFUSED"
```
The agent calls `list_sessions` and `get_logs` over MCP. Trail filters the logs in the Go process and returns structured results instead of a wall of text.
## What Trail Gives You
- **Process capture:** `trail run -- <cmd>` wraps any command, captures stdout/stderr, forwards signals, and mirrors the child's exit code.
- **Docker capture:** `trail docker <container>` captures `docker logs -f` for an already-running container.
- **Agent tools:** `trail mcp` exposes `list_sessions` and `get_logs` over stdio MCP.
- **Human tools:** `trail sessions` and `trail logs --session <id>` expose the same query surface in the terminal.
- **Local files:** captured logs are plain JSONL under `~/.config/trail/sessions/`.
## Guided Debugging Workflow
The Codex and Claude Code plugins ship a `debug-with-trail` skill for runtime debugging. It turns Trail into a repeatable agent workflow for server crashes, failing tests, silent failures, and "what happened in the logs?" investigations.
Ask in plain English:
```text
My Express server returns 500 on POST /orders. Use Trail to debug it.
```
The skill walks the agent through:
1. **Prerequisites:** verify `trail` is installed and the relevant process is being captured.
2. **Read existing logs first:** query errors, recent output, and relevant terms before touching code.
3. **Instrument only when needed:** add temporary targeted log lines with a unique `TRAIL-DEBUG-<id>` marker.
4. **Verify the fix:** query the marker output after the change, not just static code.
5. **Clean up:** remove every temporary log line and verify `rg TRAIL-DEBUG-<id>` returns nothing.
The cleanup rule is the important part: every added probe carries a unique marker, and the agent is instructed to remove the whole log statement after the fix is verified.
Read the exact skill instructions:
- [Codex skill](integrations/codex/skills/debug-with-trail/SKILL.md)
- [Claude Code skill](integrations/claude-code/skills/debug-with-trail/SKILL.md)
## Use Cases
- **Debugging a running app:** wrap `npm run dev`, `python manage.py runserver`, `go run .`, or any other server and let the agent query only the relevant logs.
- **Investigating long test runs:** `trail run -- go test -v ./...`, `trail run -- pytest -v`, or `trail run -- npm test`, then ask what failed and why.
- **Build, lint, and typecheck output:** capture long compiler or linter output once, then filter by level, file name, symbol, or regex.
- **Comparing flaky runs:** capture a passing run and a failing run, then ask the agent what changed.
- **Long-running scripts and migrations:** keep a permanent, queryable local record instead of relying on terminal scrollback.
- **Noisy Docker containers:** use `trail docker <name>` to make container logs queryable without flooding the agent context.
In every case, the pattern is the same: attach terminal output to your agent by handing it a session id, instead of piping logs through prompts.
## Editor Setup
The Codex and Claude Code plugins are the recommended setup because they include both MCP wiring and the guided debugging skill.
For manual MCP setup, make sure `trail` is on the `$PATH` of the shell that launches your editor. macOS GUI apps do not always inherit your shell path; if the MCP server fails to start, check `which trail` from the editor's terminal.
### Claude Code Without The Plugin
```bash
claude mcp add trail -s user -- trail mcp
```
This path wires up the raw MCP tools (`list_sessions`, `get_logs`) only — it does not include the bundled `debug-with-trail` skill.
### Cursor
`.cursor/mcp.json`:
```json
{
"mcpServers": {
"trail": {
"command": "trail",
"args": ["mcp"]
}
}
}
```
### Windsurf
Settings -> MCP:
```json
{
"mcpServers": {
"trail": {
"command": "trail",
"args": ["mcp"]
}
}
}
```
### Claude Desktop
`claude_desktop_config.json`:
```json
{
"mcpServers": {
"trail": {
"command": "trail",
"args": ["mcp"]
}
}
}
```
## Install Options
### One-liner
```bash
curl -fsSL https://raw.githubusercontent.com/Pratham-Mishra04/trail/main/install.sh | sh
```
The installer detects your OS/arch, downloads the matching prebuilt binary from the latest GitHub Release, verifies its SHA-256 checksum, and installs `trail` to `~/.local/bin/trail`.
If `~/.local/bin` is not on your `$PATH`, the installer prints the exact `export` line to add. Override the destination with `BIN_DIR=/usr/local/bin` or pin a version with `VERSION=v0.1.0`.
`wget` works too:
```bash
wget -qO- https://raw.githubusercontent.com/Pratham-Mishra04/trail/main/install.sh | sh
```
### Manual Download
```bash
ARCHIVE=trail_darwin_arm64.tar.gz
BASE=https://github.com/Pratham-Mishra04/trail/releases/latest/download
wget "$BASE/$ARCHIVE"
wget "$BASE/checksums.txt"
grep " $ARCHIVE\$" checksums.txt | shasum -a 256 -c -
tar xzf "$ARCHIVE"
sudo mv trail /usr/local/bin/
```
Available archives:
- `trail_darwin_arm64.tar.gz`
- `trail_darwin_amd64.tar.gz`
- `trail_linux_arm64.tar.gz`
- `trail_linux_amd64.tar.gz`
### Go Install
```bash
go install github.com/Pratham-Mishra04/trail@latest
```
Go's `go install` does not inject release metadata, so `trail version` may print `trail dev (commit none, built unknown)`. The binary still works normally.
### Build From Source
```bash
git clone https://github.com/Pratham-Mishra04/trail
cd trail
make install
```
This runs `go install` with version metadata baked in. The binary lands at `$(go env GOPATH)/bin/trail`.
### Supported Platforms
macOS and Linux on amd64/arm64. Windows is not supported.
## Why Server-side Queries
When an agent reads raw log files into its context to filter them, every query pays for re-loading the file's tokens through the LLM. Trail filters in the Go process and returns only matching entries.
This means:
- The agent does not burn context on log lines that will not matter.
- Regex and level filters are deterministic.
- Latency is bounded by the filter work, not token generation speed.
## What It Captures
| Source | Command | Notes |
|---|---|---|
| Wrapped command | `trail run -- <cmd>` | Wraps any binary; separate stdout/stderr pipes preserve stream attribution. |
| Docker container | `trail docker <name>` | Wraps `docker logs -f`; passes `--since` through. |
Both commands accept `--name <label>` to override the auto-derived session name and `--ephemeral` to delete the session file when the capturer exits cleanly. The file survives a `SIGKILL`; only graceful shutdown triggers cleanup.
Trail does not capture:
- A bare PID you did not start under Trail. That would require `ptrace` or `eBPF`.
- Arbitrary log files written to disk by another tool. Use `tail`, `lnav`, or normal file tools for those.
## Querying Captured Logs
### From An Agent
The MCP server exposes two tools:
- **`list_sessions(active_only?, limit?)`:** returns session metadata including the absolute file path of each session JSONL file, ordered active-first.
- **`get_logs(session_id, filters?)`:** returns matching entries.
`get_logs` filters include:
- `limit`, `page`, and `order`
- `query` as a case-insensitive regex
- `level`: `error`, `warn`, `info`, `debug`, `unknown`, or `all`
- `start_time` / `end_time` as RFC3339 timestamps
- `duration` as a Go-style duration, such as `"10m"` or `"2h"`
- `start_line` / `end_line`
Time-window, duration, and line-range filters are mutually exclusive. Combining them returns an error.
If a result looks incomplete, the response includes the absolute `file_path` and the agent can read the JSONL file directly with its file tools.
### From The Terminal
```bash
trail sessions # table
trail sessions --json # JSON for scripting
trail sessions rm <id> # delete one
trail sessions rm --all # delete all
trail logs --session <id> # last 100, pretty
trail logs --session <id> -n 50 # last 50
trail logs --session <id> --level error # errors only
trail logs --session <id> --query "ECONNREFUSED" # case-insensitive regex
trail logs --session <id> --format json # raw JSON entries
```
`trail logs --session` is required. There is no implicit "most recent" default; the MCP tool follows the same rule.
## How It Works
- **Two-process model:** capture processes (`trail run` / `trail docker`) own session files. The MCP server is read-only and spawned by the editor on demand; it never starts, modifies, or stops captures.
- **One JSONL file per session:** files live at `~/.config/trail/sessions/<uuid>.jsonl`. The first line is a meta header; every subsequent line is one captured entry.
- **Append-only writes + tolerant reader:** entries are appended to a regular file (`os.OpenFile(O_APPEND)`); `maxRawLen` caps the `Raw`/`Message` fields but not the whole marshaled JSON line, so concurrent reads rely on the reader being tolerant of malformed or partial trailing lines (see `internal/store/reverse.go` and `TestRead_TolerantOfPartialLastLine`) rather than on kernel-level atomicity.
- **Server-side filtering:** cheap filters run before full JSON decode; eligible newest-first queries (`Order=newest`, `Limit>0`, `Page≤1`, no time/line bounds) use a reverse scan from the end of the file.
- **Conservative log-level detection:** Trail only assigns a level when there is clear evidence, such as a JSON `level` field, logfmt `level=`, or an anchored prefix like `ERROR:`.
## License
MIT