Valet
Lets an AI agent run commands on someone else's machine, while the machine's owner decides what it's allowed to do.
- Role
- Designed and built it
- Status
- Live on macOS, since Nov 2026
- Stack
- Rust, Tauri, TanStack Start
- Runs on
- macOS first
The problem
An agent is only as good as what it can see. The bugs that hurt most live on someone else's machine: an install that fails on one customer's laptop, a crash the reports don't explain.
The ways in weren't built for this. Remote desktop assumes a person watching a screen. SSH hands over an account's full rights at login. Agent tools like Claude Code ask the person who started them, on their own machine. None of them cover two parties: one who wants to look, and one who owns the machine.
Valet is a valet key. The agent gets to drive; it doesn't get to open the trunk.
How it works
- The agent starts a session. It reads a skill file, creates a session with
curl, and hands its person a six-character code. No accounts on either side. - The client reviews. They enter the code in the Valet app on their Mac, see who's asking and why, and choose what to allow up front: nothing, everything, or the sender's suggested set.
- Everything else asks. Anything outside those permissions lands on the client's screen with the exact command that will run. Medium risk takes a click; high risk takes Touch ID. Sessions end after an hour unless the client extends them.
Acme Support suggests these permissions
Anything you switch off asks you first instead.
Files
Programs
Processes
Starts with 5 permissions. Everything else asks.
Commands only: no screen sharing and no mouse or keyboard control, ever. Try a prompt below, and watch what the agent gets back.
Three things an agent might ask for
Network access always asks, even when the program is already allowed.
POST /sessions/k7q2/actions {"tool": "run_command", "args": {"command": ["/usr/bin/curl", "-s", "https://api.acme.com/v1/drivers/latest"]}, "reason": "Checking the latest driver Acme recommends."} ← "pending" // waiting for the person
Acme Support wants to run a command
curl -s https://api.acme.com/v1/drivers/latest/usr/bin/curl in ~connect api.acme.com:443
Agent's reason
Checking the latest driver Acme recommends.
The decisions that mattered
Every call came back to one question: whose machine is it? Valet's answer is that the client decides, every time, on their own hardware.
The client's machine decides
Grants and the allow-or-ask call live in the client app's Rust core. The relay in the middle carries actions back and forth and keeps a read-only copy of the grants. It never decides anything.
Enforce in the sandbox, not by reading commands
Guessing what a shell command does from its text is a losing game. Every command runs under the macOS sandbox, with a profile built from the session's grants that starts from deny all. Credential folders like
~/.sshand~/.awsare denied again after every broad allow.What the command says
/Applications/AcmeApp.app/Contents/MacOS/AcmeApp --diagnoseA program the client allowed, with a harmless flag.
The screen can't approve anything
The app's interface shows text an agent wrote, so it's treated as untrusted. It can only hand a choice back to Rust, which takes one answer per prompt, only after a 600 ms pause, and runs Touch ID itself.
Read before you write
Every read returns a hash of the file, and every write must carry the hash it was based on. If the file changed in between, the write is turned back before anyone is asked.
- 1 read_file config.json → hash 7d1e…a40c
- 2 nothing touches the file
- 3 write_file config.json base_hash 7d1e…a40c
- "gpu": "auto"
+ "gpu": "integrated"
Nothing outlives the session
Tokens live in memory only, never on disk. Ending a session kills its processes and drops its grants, and everything on the relay expires on its own.
How I built it
Spec first, again. The product spec, the design system and the architecture were written before any code, and a clickable mockup of the whole session came before the real app. The permission engine was written in TypeScript for that mockup, then ported to Rust with shared test cases so the two can't drift apart.
The relay reuses Wave's plumbing: token handling, long-polling and rate limits, on the same Redis under its own prefix. Claude Code wrote the code, and every commit so far carries its co-author line. When a fresh agent tried the skill file cold, the places it stumbled went straight back into the skill.
What's next
Valet is days old, and it's live. The Mac app ships signed and notarised, and updates itself from each new release. Here's what's still open.
A signed log of every session
Each action, decision and result chained by hash and signed on the client, so both sides can check what happened. Designed, not built yet.
End-to-end encryption
Today the relay sees commands and output in plain text while a session is alive. It says so plainly until that changes.
Network grants per host
Network access is all or nothing for now, and every network action asks.
Life after sandbox-exec
macOS still ships it, but it's deprecated. Endpoint Security or a VM-based runner are the fallbacks.
Windows, then Linux
The Mac comes first. Windows Hello takes the place of Touch ID.