Documentation

The field guide.

Everything from installing Kestrel to wiring it into your agent. Read on the left; the example for each section follows you on the right.

v1.0.0macOS · Linux · WindowsMIT
JK jump 01Install 02Quickstart 03Commands 04Flags 05kestrel.yaml 06Diagnosis rules 07Verify 08AI agents 09Security 10Go deeper
01Install

Get the binary.

Kestrel is a single static binary. Prebuilt archives cover macOS (Apple Silicon and Intel), Linux (x86_64 and ARM64) and Windows (x64). Every install path verifies a SHA-256 checksum.

PlatformCommand
Homebrewbrew install aareevs/tap/kestrel
macOS / Linuxcurl -fsSL …/scripts/install.sh | sh installs to ~/.local/bin
Windowsirm …/scripts/install.ps1 | iex installs to %LOCALAPPDATA%\Programs\kestrel and adds it to PATH
Go 1.26+go install github.com/Aareevs/Kestrel-CLI/cmd/kestrel@latest

Or grab an archive and checksums.txt from the releases page. Then check your setup with kestrel doctor.

# Homebrew (macOS & Linux)
$ brew install aareevs/tap/kestrel

# curl, detects OS + arch, verifies SHA-256
$ curl -fsSL https://raw.githubusercontent.com/\
    Aareevs/Kestrel-CLI/main/scripts/install.sh | sh

# Windows PowerShell
> irm https://raw.githubusercontent.com/Aareevs/\
    Kestrel-CLI/main/scripts/install.ps1 | iex

$ kestrel doctor
✓ platform     darwin/arm64
✓ data dir     ~/.kestrel (0700)
✓ storage      sqlite ok
✓ config       none, discovery mode
02Quickstart

Thirty seconds, four commands.

No config file needed. Run these from your project root.

kestrel inspectDiscover services, ports, health routes and dependencies. Reads files only.

kestrel watchSupervise the stack in dependency order with live, classified logs.

kestrel diagnoseSee what broke first, with ranked hypotheses and next steps.

kestrel verifyProve the fix holds across a 30s stability window.

Just want to wrap one command? kestrel run -- npm run dev captures, classifies and records it with zero config. Want a config? kestrel init proposes one from discovery.
$ kestrel inspect
◆ services   web (vite) · api (express) · db (postgres)
◆ ports      5173 · 4000 · 5432
◆ health     GET /health  src/server.ts:41
◆ depends    web → api → db

$ kestrel watch
✓ db    ready  1.2s
✓ api   ready  2.8s
✓ web   ready  0.9s
✗ db    exited 137
✗ api   ECONNREFUSED 127.0.0.1:5432

$ kestrel diagnose
1. K002 dependency-down   0.94
   db exited first → api lost :5432 → web 502

$ kestrel verify
PASS fix holds · 16 samples · 0 orphans
03Commands

Every command, and its shortcut.

CommandShortWhat it does
inspectins infoDetect technologies, service candidates, ports and health routes. Reads files only.
watchw startSupervise configured services in dependency order with live status.
runrRun any command under Kestrel with no config: capture, classify, probe, record.
statuss statLiveness vs. readiness per service.
diagnosediagRanked, evidence-backed hypotheses for each incident.
timelinetl timeLast healthy state, first anomaly, symptoms, recovery.
verifyv checkProbes across a stability window, with a before/after comparison.
sessionssessList, show, export or delete recorded sessions.
doctordocCheck platform, data directory, config and tools.
mcpRead-only MCP server over stdio, for AI agents.
initPropose a kestrel.yaml. Asks first, never overwrites.
configShow, validate or locate the config. Secrets are always masked.
cleanupApply the retention policy now.
$ kestrel --help

Usage: kestrel [command]

  inspect    detect stack (reads files only)
  watch      supervise with live status
  run        wrap any command, zero config
  status     liveness and readiness
  diagnose   ranked root-cause hypotheses
  timeline   incident timelines
  verify     did the fix work?
  sessions   list / show / export / delete
  doctor     check this machine
  mcp        read-only server for agents
  init       propose kestrel.yaml
  config     show / validate / locate
  cleanup    apply retention now
04Flags

Global flags.

These work on every command.

FlagEffect
-j --jsonJSON output, same as --format json.
--project <dir>Project directory. Default: nearest ancestor with a kestrel.yaml, else the current directory.
--session <id>Session to act on: full ID, unique prefix, or last (default).
-v --verboseDiagnostic logging to stderr.
-q --quietOnly essential output.
--no-colorDisable ANSI styling. NO_COLOR is honored too.
--allow-execLet verify run configured command checks without a prompt.
$ kestrel diag -j
{
  "session": "01JA9…",
  "incidents": [{
    "id": 3,
    "hypotheses": [{
      "rule": "K002-dependency-down",
      "confidence": 0.94,
      "claim": "hypothesis",
      "supporting": ["evt_8f21", "evt_8f24"],
      "next_step": "check db memory limit"
    }]
  }]
}
05kestrel.yaml

Optional, and strict.

Kestrel works from discovery alone; a config just makes its picture sharper. It lives at the project root as kestrel.yaml or .kestrel.yaml (not both). Unknown keys are errors, every problem is reported at once with a line number, and kestrel config validate exits 2 when the file is invalid. A JSON schema ships in docs/kestrel.schema.json for editor support.

services[]

KeyNotes
nameRequired, unique. Letters, digits, - _ ., up to 63 characters.
dirWorking directory relative to the project root.
commandWhat Kestrel runs, only under run, watch and verify.
env${VAR} is resolved from your shell at start. Resolved values are never stored or printed.
depends_onOther services. Unknown names and cycles are errors.
healthhttp, tcp or process, with interval 2s, timeout 1s, retries 3, startup_grace 10s.

A service with only a probe, like a database you run yourself, is observed and never started.

Top level

KeyDefaultNotes
storage.retention_days7Older ended sessions are removed.
storage.max_total_mb500Oldest closed sessions go first. The active one never does.
correlation.window10sUsed only as a weak correlation signal.
redaction.extra_patterns[]Extra regexes to redact.
verify.checks[]probe or command checks.
version: 1
project:
  name: example-app
storage:
  retention_days: 7
  max_total_mb: 500
redaction:
  extra_patterns: ["acme_[a-z0-9]{32}"]
services:
  - name: database
    health: { type: tcp, address: localhost:5432 }
  - name: api
    dir: ./backend
    command: go run .
    env: { DATABASE_URL: "${DATABASE_URL}" }
    depends_on: [database]
    health: { type: http, url: http://localhost:8080/health }
  - name: frontend
    dir: ./frontend
    command: npm run dev
    depends_on: [api]
verify:
  checks:
    - { type: probe, service: api }
    - { type: command, run: go test ./... }
06Diagnosis rules

Six rules, all evidence.

Kestrel groups anomalies into incidents, finds the initiating failure using the dependency graph and port evidence (timing is only a weak signal), then runs these rules. Every hypothesis cites the event IDs that support or contradict it.

K001Port conflictTwo things want the same port. Both are named.
K002Dependency downA dependency died and its dependents failed after it.
K003Crash after startReached ready, then exited.
K004Startup failureNever became ready. Here is the first fatal line.
K005Dependency not runningStarted before what it needs was up.
K006Missing moduleAn import or package that isn't installed.

Claim levels

Each finding carries one: observed, correlated, hypothesis, verified or unresolved. A hypothesis is never presented as fact, and an incident nothing explains stays unresolved.

$ kestrel diagnose
Incident #3  3 services · first signal 14:02:11.384

1. K002 dependency-down       0.94  hypothesis
   db exited 137 → api lost :5432 → web 502
   supporting   evt_8f21 evt_8f24 evt_8f2a
   contradicting —

2. K003 crash-after-start      0.21

next → raise db memory limit, then kestrel verify
07Verify

"It went away" isn't "it's fixed".

kestrel verify samples the affected services across a stability window (default --window 30s, --interval 2s, so 16 samples). The window always runs to the end. It never starts, restarts or signals your services.

  • passed every sample passed.
  • flaky some passed, some failed. A fix that landed mid-window, or a relapse.
  • failed no sample passed.

Checks are chosen from evidence: each affected service's health probe, a TCP check for every address the incident failed to reach, liveness when watch is still running, and your configured commands, but only with --allow-exec or a yes at the prompt.

Run verify while kestrel watch is still going. It then also checks whether the incident's errors are still occurring during the window, which gives the strongest answer.
$ kestrel verify
Before   K002 dependency-down · db exited 137
Window   30s · every 2s · 16 samples

probe  db    :5432        ●●●●●●●●●●●●●●●●  passed
probe  api   /health      ●●●●●●●●●●●●●●●●  passed
tcp    127.0.0.1:5432     ●●●●●●●●●●●●●●●●  passed
live   web                ●●●●●●●●●●●●●●●●  passed

During the window: no recurrence

PASS  fix holds
08AI agents

Give your agent the evidence.

kestrel mcp is a Model Context Protocol server over stdio. Agents ask for the diagnosis instead of grepping logs. It serves one project, and reads what run and watch recorded.

Claude Code

claude mcp add kestrel -- kestrel mcp --project /path/to/project

Tools

ToolReturns
get_diagnosisRanked hypotheses with supporting and contradicting event IDs and a next step.
get_failure_timelineIncident timelines, the dependency graph, past verifications.
get_recent_errorsLatest error and fatal events (default 50, max 500).
get_session_summaryFinal service state, counts by type, notable events.
get_verification_resultsPast verify runs and the latest report in full.
get_service_statusLiveness and readiness per service.
list_servicesServices from the config, commands masked.
inspect_projectDiscovery findings with file:line and confidence.
  • Strictly read-only. No tool starts, stops, signals or executes anything.
  • Logs are data. The agent is told that log text is untrusted and never instructions.
  • Redacted twice. At record time and again on the way out, with today's patterns.
# Claude Code
$ claude mcp add kestrel -- \
    kestrel mcp --project /path/to/project

# Cursor, VS Code, Claude Desktop…
{
  "mcpServers": {
    "kestrel": {
      "command": "kestrel",
      "args": ["mcp", "--project",
               "/path/to/your/project"]
    }
  }
}
09Security

Runs next to your secrets. Acts like it.

  • Discovery only reads. It never runs scripts, package managers or build tools, never follows directory symlinks, and never opens .env.
  • Redaction before storage. Private keys, JWTs, URL credentials, provider keys, auth headers and secret-named pairs are masked before anything is printed or written.
  • Only its own processes. Signals go only to process groups (Windows Job Objects) Kestrel created. Ctrl-C leaves zero survivors.
  • Hostile logs stay inert. Log text is never executed, and terminal escape sequences are stripped.
  • Bounded under floods. A 50 MB/min log flood plateaus around 47 MiB of memory, with every drop accounted for.
  • Exec needs consent. verify commands run only with --allow-exec or an explicit yes.
# what your process printed
DATABASE_URL=postgres://admin:hunter2@db:5432/app
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIi…
STRIPE_KEY=sk_live_51Hx…

# what Kestrel shows, stores and sends to agents
DATABASE_URL=postgres://admin:[REDACTED:url-credential]@db:5432/app
Authorization: Bearer [REDACTED:jwt]
STRIPE_KEY=[REDACTED:provider-key]
10Go deeper

The full references.

$ ls docs/
architecture.md      packages + pipelines
configuration.md     kestrel.yaml reference
diagnosis-rules.md   K001 – K006
events.md            event model
mcp.md               agent setup + tools
security.md          threat model
verification.md      stability window
kestrel.schema.json  editor schema