Terminal inbox
Run pilothouse for a live list of every session on the machine: who is working, who is waiting, who needs you. Approve or deny without hunting for the right tab.
Pilothouse is one inbox for Claude Code and Codex. It watches every session through the agents’ official hooks, checks your rules before every tool call, and brings what needs you to wherever you are: the terminal at your desk, or your phone when you’re not.
curl -fsSL https://pilothouse.dev/install.sh | shbrew install xasdta/tap/pilothousethen run pilothouse setup
Get updates: release notes when new agents and the relay land.
Animation: Claude Code is working in a terminal. You step away from your desk, so when the agent asks to run git push origin main, Pilothouse checks your rules, holds the request and sends it to your paired phone. You tap Allow, the phone signs the decision, and the agent continues in the terminal.
Pilothouse runs a small daemon per machine. Agents report to it through their hooks; you answer from wherever you are. There is nothing to sign up for.
Installs the Claude Code and Codex hooks (merged, never clobbered, backed up) and starts the user service.
$ pilothouse setup
✓ hooks installed: claude, codex
✓ service running (launchd)Expose the web app on your tailnet over HTTPS, then scan a QR code. The phone gets its own signing key.
$ pilothouse remote tailscale
✓ https://mac.tailnet.ts.net
$ pilothouse pair # shows a QRAt the desk, nothing changes. Step away and requests come to your phone. Your rules run either way.
$ claude # any terminal
$ pilothouse # the inbox
● 1 needs you · 3 workingMost tools only see a request once the agent decides to ask. Pilothouse checks every tool call atPreToolUse, so “never force-push” holds even when the agent’s own settings would have allowed it. Write rules in YAML, add a CEL condition when a glob isn’t enough.
version: 1
rules:
- name: no-force-push
match: { kind: shell, command: "git push*" }
when: 'command.matches("(--force|-f)\\b")'
action: deny
message: Force-push is blocked. Open a PR.
- name: ask-before-push-main
match: { kind: shell, command: "git push*main*" }
action: ask
- name: no-env-files
match: { path: "**/.env*" }
action: deny
message: Secrets stay out of the context.
- name: tests-are-fine
match: { kind: shell, command: "{npm,pnpm} test*" }
action: allowAny deny wins, then ask, then allow.
.pilothouse/policy.yaml can only add stricter rules until you trust it.pilothouse policy replay --since 7d shows what your new rules would have changed.A tool that grabs every prompt and sends it to your phone makes the terminal worse. Pilothouse looks at whether you’re actually at the machine. At your desk, it gets out of the way. Away, it holds the request and finds you.
How presence worksAt your desk: Pilothouse steps aside and the agent shows its own permission dialog, exactly as it would without Pilothouse. Nothing freezes. If you leave it unanswered for a while, you get a desktop notification.
Away (idle): the request is held and pushed to your paired devices. The first answer wins. Come back to the keyboard and it's handed back to the terminal; if nobody answers before the hold limit, the agent's own dialog takes over.
Everything below ships in the open-source binary. No tiers, no feature flags, no sign-in.
Run pilothouse for a live list of every session on the machine: who is working, who is waiting, who needs you. Approve or deny without hunting for the right tab.
pilothouse run claude keeps the agent in a small holder process. Close the terminal, restart the daemon, re-attach later. Detach with ctrl+\.
pilothouse task new "fix the flaky test" creates a branch, a worktree and an agent. Review the diff, then task done --pr.
Web Push to the paired web app, ntfy with signed Allow/Deny buttons, Slack and Discord webhooks, and desktop notifications.
Why does a session say “blocked”? explain shows the evidence and the rule that decided it. No guessing from screen scraping.
policy test checks a hypothetical call; policy replay re-runs your new rules against last week’s tool calls and shows what would change.
A single Go binary for macOS and Linux, amd64 and arm64. Runs as a launchd or systemd user service. Works on headless servers.
Sessions, prompts, commands and paths never leave your machine. The only call home is an anonymous update check you can switch off.
A remote “Allow” is powerful, so it is treated that way: signed by a device key, checked by your own daemon, and never routed through someone else’s server.
Pairing creates a P-256 key inside the phone’s browser that can’t be exported. Each remote decision is signed with it, time-stamped and single-use.
Local decisions only come through a Unix socket, and callers descended from an agent process are refused. A built-in rule asks you before an agent touches Pilothouse itself.
The web app listens on 127.0.0.1. Your phone reaches it through Tailscale Serve over HTTPS. There is no Pilothouse server in the middle.
Honest framing: Pilothouse runs as you. These protections are defense in depth that make accidental and casual self-approval hard; they are not a sandbox. Read the full security model →
There are good tools here. herdr is a great multiplexer; Happy has native apps; Claude Code ships its own remote control. Pilothouse is the vendor-neutral layer that adds policy and works alongside all of them.
| Feature | Pilothouse | herdr | Happy | Claude Remote Control |
|---|---|---|---|---|
| License | Yes: Apache-2.0 | Yes: Apache-2.0 | Yes: MIT | No: Proprietary |
| Agents | Claude Code, Codex | 22+ agent CLIs | Claude Code, Codex (Grok in the new runtime) | Claude Code only |
| Keep your terminal and how you launch agents | Yes: Yes — official hooks; any terminal, even inside tmux or herdr | Partly: Agents run inside herdr panes | Partly: Start agents through happy (or its own runtime) | Yes: Yes — /rc in a running session |
| Your rules before every tool call | Yes: YAML + CEL, user and repo files, any deny wins | No: No documented policy engine | No: No user-written rules | Partly: Claude’s own allow/ask/deny permission rules |
| Approve from your phone | Yes: Yes — each device signs its decisions | No: No first-party mobile client | Yes: Yes — native apps | Yes: Yes |
| Presence-aware (no phone buzz while you’re at the desk) | Yes: Yes — OS idle time; manual override | No: Not documented | No: Not documented | Yes: Skips push while you’re focused in the terminal |
| Works without an account | Yes: No account | Yes: No account | Partly: Key-based account (your phone holds the key) | No: Needs a Claude subscription |
No. Pilothouse installs hooks into Claude Code and Codex, so a claude or codex started from any terminal or IDE shows up in your inbox — Ghostty, iTerm2, VS Code, tmux, even inside herdr. Wrap mode (pilothouse run claude) is optional and only adds detach/re-attach.
Claude Code and Codex in v0.1. Claude Code gets the full set: rules before every tool call and remote approvals. Codex support follows what Codex’s own hooks expose (Codex asks you to trust new hooks once, with /hooks); the support table lists exactly what works. OpenCode, Copilot CLI and Gemini are on the roadmap.
No ports. Pilothouse serves its web app on 127.0.0.1 only. pilothouse remote tailscale uses Tailscale Serve to give it an HTTPS address that only devices on your tailnet can reach. You pair a phone by scanning a QR code.
You still get the terminal inbox and notifications through ntfy, Slack, Discord or your desktop, but answering from the phone needs a route to your machine. An end-to-end encrypted relay for people without Tailscale is on the roadmap.
No. Pilothouse checks whether you’re active at the machine. At the desk, it steps aside and the agent shows its own dialog right away. Only when you’re idle does it hold the request and send it to your devices. You can force either mode with pilothouse here, pilothouse away or pilothouse auto.
Agents carry on as if Pilothouse weren’t installed. The hook shim gives up within two seconds and returns “no opinion”. If you’d rather block tool calls when Pilothouse isn’t running, set approvals.fail_closed: true.
Pilothouse makes that hard on purpose. Local decisions are only accepted on a Unix socket and are refused if any ancestor of the calling process is an agent. Remote decisions must be signed by a paired device’s key. A built-in rule asks a person before an agent runs Pilothouse admin commands or edits Pilothouse’s files. It is defense in depth, not a sandbox: anything running as your user can ultimately change your files. The security page spells out the limits.
No. The only network call Pilothouse makes on its own is an anonymous update check (version, OS, architecture and a random ID that changes every month), and you can turn it off with update_check: false or PILOTHOUSE_NO_UPDATE_CHECK=1. Nothing about your sessions, prompts, commands or paths leaves your machine except through notification channels you set up.
Remote Control is great if you only use Claude Code and have a Claude subscription. Pilothouse covers Claude Code and Codex in one inbox, adds your own rules before every tool call, works with API-key setups, and runs entirely on your machine with no account. See the comparison.
Pilothouse is free and open source under Apache-2.0. It runs on macOS and Linux (amd64 and arm64); Windows is on the roadmap. A hosted relay and team policies may become a paid Pilothouse Cloud later — the open-source product stays complete for individuals.
Install in a minute. Pair your phone in two. No account, ever.
curl -fsSL https://pilothouse.dev/install.sh | shbrew install xasdta/tap/pilothousethen run pilothouse setup