A control plane for coding agents: it decides what they may do, at the moment they ask.
Coding agents are trusted or they are watched, and neither scales. Trusting one means finding out afterwards. Watching one means you are the bottleneck, and you are not watching the other three.
Sightline is the third option. It hosts Claude Code rather than sitting beside it, so every tool call an agent makes stops at a boundary Sightline owns — in Rust, before the call happens — where it is allowed, refused, amended, or handed to you. Most of them never reach you. That ratio is the point.
Nothing leaves the machine. No hooks, no server, no API key: it drives the
claude binary you already have, on the subscription you already pay for.
The boundary is only a mechanism. What makes it worth having is that Sightline knows things no single session can:
| ceiling | what the whole fleet has spent, and how many are running. A session cannot answer this in its own favour — the file lives outside every worktree. |
| scope | a worker writes inside the directory it owns. A stray absolute path into the main checkout is redirected there rather than refused, because it is nearly always a stale path and not an intention. |
| task | Sightline wrote down what this session was assigned, and the session has never seen that record. A write with no assignment is work nobody will check. |
| trust | a project's checks.toml is shell that arrived with someone else's code. It does not run until a person approved those exact commands — including when an agent reads the file and runs what it found. |
| collision | two live sessions about to change one file. Nothing else on the machine can answer this, because answering it means seeing the other session. Both would have reported success. |
| forbid | git push --force and its friends, whatever the permission mode says. |
Four answers are possible at that boundary — allow, deny, rewrite, escalate —
and rewrite is the one with no equivalent in a settings file or a hook. A gate
that can only say yes or no has to escalate every ambiguous call to a person.
curl -fsSL https://raw.githubusercontent.com/nyfeblade/sightline/master/install.sh | shOr grab a binary from releases, or build it — the install script is short, and worth reading before you pipe it into a shell:
cargo install --git https://github.com/nyfeblade/sightlineAs a desktop app on Linux, one file, nothing installed:
scripts/appimage.sh # builds dist/sightline-<version>-x86_64.AppImageClicking it opens the window; any argument goes to the commands, so
./sightline-0.4.1-x86_64.AppImage doctor works from the same file.
scripts/desktop-entry.sh puts it in your application menu instead. The app
needs webkit2gtk, which a normal desktop already has.
On Windows:
irm https://raw.githubusercontent.com/nyfeblade/sightline/master/install.ps1 | iexThen sightline-gui for the window, or sightline for the commands. Linux,
macOS and Windows; tmux is optional on the first two, and only for steering
sessions rather than watching them.
Watched — the ones you start yourself, in a terminal. Sightline reads their transcripts from outside: what they are running, what they touched, what they are blocked on. It is not in the loop, so none of the kernels above apply. This is what Sightline did before, and it still does it.
Owned — the ones Sightline starts. It holds both pipes, answers every permission request, and serves them tools of its own. Everything on this page about deciding applies here and only here.
Nothing about the first kind changed. If you want an agent governed, Sightline has to be the one holding it.
A chief is a session with no way to start a process. What it has instead is a tool that asks:
assign(path, task) start a worker on one assignment
fleet() every worker, whether it is busy, what it is doing
tell(who, text) say something to a worker you started
claim(summary) say your work is finished, and find out what the checks said
That is not a formality. A worker Sightline starts is confined to its directory, counted against the ceilings, policed on every call, and stopped when the fleet is stopped. One a chief started for itself would be none of those things — so there is no way to start one, and nothing to route around.
A worker cannot start workers. The tree stays one deep until somebody decides otherwise, deliberately.
A worker saying it has finished is worth nothing on its own.
Claimed the agent says so.
Checked the suite passed — which says the failures it can express did not
happen, and nothing more.
Verified something written to show the work wrong was run, did not fire, and
has been seen to fire at some point.
That last clause is the one people drop, and dropping it is how a suite of
refutations that could never fire verifies everything forever. sightline refute <task> <command> adds one; a refutation that has never caught anything is
reported as exactly that.
Alongside the checks are invariants — commands that must fail, each written to succeed only when a guarantee has stopped being true. A passing suite survives a change that quietly broke something load-bearing; a command looking for the breakage does not. This repository holds ten of its own, and every one was checked by breaking the thing on purpose and watching it catch it.
sightline trust . # read a project's checks, then approve those commands
sightline check <who> # what they say about a session's work
sightline invariants # try to break what must never stop being trueSomething that starts sessions on your behalf does not start without a number it cannot change.
sightline limits --sessions 4 --spend 20 --window 24hKept in Sightline's own directory, outside every worktree. A project may lower
them and never raise them, and sightline chief refuses to start without them.
The design rests on Claude Code's control protocol, which is undocumented. So it is not assumed — it is established by experiment, and the experiment is in the repository:
python3 docs/probes/control_protocol.py allSix properties, each of which can actually be wrong: that every tool call reaches
the host, that a refusal stops it, that the host can rewrite a call before it
runs, that initialize reports the models and effort levels available, that a
turn can be interrupted mid-tool, and that the model will call a tool the host
serves in-process. Last run against Claude Code 2.1.241 on a Claude Max
subscription: 6/6.
Two live end-to-end runs are examples rather than tests, because they spend quota:
cargo run -p sightline-core --example gate_live # the boundary holds
cargo run -p sightline-core --example chief_live # chief → worker → real taskThe monitoring half did not go anywhere, and it is what you will look at most.
- The session waiting on you, at the top, answerable without leaving the window — including the prompt Claude Code has drawn but not yet written down.
- The feed: every prompt, tool call, result, diff, subagent and error, live, while a turn is in flight.
- Files, git tree, plan, stats, errors per session, and a reading view for any file a session touched.
- Resuming anything, ever — every conversation on the machine, however old, reopened where it stopped.
- Cost, as the subscription view or the API-equivalent estimate.
- Notifications when something needs you, and a machine-readable stream at
sightline events --jsonfor anything else that wants to watch. - Isolated sessions on their own branch and checkout, merged back when you say so.
- Other agents: Aider has a real adapter; Codex and Gemini are read from the screen.
- Glue —
sightline glue <version>reconciles a fork onto a newer upstream release by teaching your own agent upstream's architecture, seams and invariants, then having it write the adapters in a worktree of its own.
Two files Claude Code already writes, plus one protocol it speaks.
~/.claude/projects/<project>/<session-id>.jsonl— the transcript, appended while a turn is in flight. Tailing it gives every prompt, tool call, result, token count and error as they happen.~/.claude/sessions/<pid>.json— the live-session registry. A pid is believed only when its start time matches the one recorded, so a recycled pid never reads as a live session.- The control protocol, for sessions Sightline owns: stream-json over two pipes, with an MCP server Sightline serves in-process. This is where permission decisions arrive and where the kernel's own tools live. No SDK, no Node, no API key.
CLAUDE_CONFIG_DIR is honoured; --root points at transcripts anywhere.
Steering a watched session needs the terminal it is in, and that is the one part with two implementations: tmux on Unix, a pseudo-console Sightline owns on Windows. Both answer the same two questions — what is on this screen, and take this key — so everything above them is written once.
Both file formats are Claude Code's own and undocumented, so they can change. Sightline parses defensively and says so when it meets a version it was not built against, rather than quietly showing figures that are wrong. Read that as the maintenance promise it is: a release can move a field or redraw a prompt, and when it does Sightline loses a detail rather than inventing one. Open an issue with your Claude Code version; the fix is usually a few lines.
crates/core holds everything that is not a way of looking at it; crates/tui
is the commands; crates/gui is the window. Neither front end may grow logic the
other needs — sending a message, answering a prompt, reaching a verdict on
whether work is done: one implementation, two callers. There are invariants that
fire if that stops being true.
docs/ARCHITECTURE.md is the current design and the evidence under it.
docs/PLATFORM.md and docs/BUILD.md are the layers and the working spec for
each. docs/STATE.md is the shorter, more perishable one: what works today,
what is built but not wired, and what would trip someone up if nobody said so.
Everything claimed to exist is checkable in this repository; everything else is marked as a claim.
- The single prompt — one place to say what you want and be asked about the rest — is designed and not built. Today that is the window and the commands.
- Windows has never been run on Windows, and the macOS app has never been run on macOS. Both compile and cross-check clean, which is not the same thing.
- Escalation currently means the kernels abstain and allow. Holding a call open while a person decides is the next piece.
- The chief has run well, and briefly. Evidence that it starts and orients; no evidence about a long run.
- Quota is the binding constraint, not the design. A live chief has already been stopped by a rate limit.
cargo build --release
cargo test
sightline invariants # what must never stop being true here
scripts/demo.sh # a synthetic ~/.claude, for screenshots and manual
# testing — nothing in it touches your real sessionsSightline was called Ironsight, and before that scope. Old .ironsight/ project
directories and IRONSIGHT_DATA_DIR are still read: a project's constitution and
checks are committed with its code, and there is no upgrade step anyone would
think to run.
MIT
