The problem
I run a personal assistant on my own server: a phone app over my email, calendar, documents and photos, with a chat. Harder questions were going to outside chat models that couldn’t see the machine and left no record. I wanted an agent on the server that could look at everything and change code, without ever finding a change I hadn’t approved in an app I use every day. A rule in a prompt doesn’t settle that, because an agent working fast will reason its way past a sentence.
What it does
Wick is the agent behind the chat: when the first model call decides a message needs more than a reply, it hands the turn to Wick. Wick can read anything on the server. Apart from its own notes, scripts and documents it leaves for me, every change goes through one program, wick-write:
- A file in a git project goes onto a branch in a separate working copy. The files the live services run from don’t change.
- A file outside git is staged as a copy for review.
- Protected files (project journals, anything that looks like a secret, the guard’s own code) are refused, and Wick files a request in an escalation log instead.
Every accepted write is committed, so every change has an undo.
Wick can run the project’s tests on its branch and start a preview: a copy of the assistant running from the branch on copied data, reachable only from my devices, that shuts itself down after three hours. To ship, I type “ship it” in the chat. Wick records my words and the exact commit, and a scheduled job picks it up within five minutes.
How it’s built
Wick is Claude, run through the Claude command-line tool with an explicit tool allowlist. Reading and searching are open. The built-in Edit and Write tools are left out, so the sanctioned way to change a file is the guard, and the guard’s own folder is protected.
The merge job ships an approval only if the approval is under two hours old, my quoted words appear in one of my own chat messages from the 30 minutes before it, the branch is still exactly the commit I approved, the tests pass again, and the live repository has no uncommitted changes. Then it merges with a single merge commit, restarts the service and checks that the app answers. If it doesn’t answer within 30 seconds, the merge is reverted. I hear about the outcome either way.
Judgment calls (direction, money, other people, security) go to the escalation log for a longer session to review.
Decisions
- Wick’s limits are written in code. A rule in a prompt is advice, and the failure I cared about (a plausible bad write that compounds quietly) is the kind advice doesn’t stop.
- Approval is checked against what I actually typed. The merge job reads my messages directly, so an approval Wick misread or invented can’t ship.
- A failed deploy reverts itself. If a change stops the live app answering, the undo shouldn’t depend on me noticing.
- Email stays read-only, permanently. A mail tool that can send is the easiest way for an agent to do something irreversible in my name.
How it broke, and what changed
On the evening of 18 August, Wick couldn’t write anything. Four exchanges produced no log entry, no escalation and no undo. Every write came back as needing approval, and the guard’s audit log showed it had never been reached.
The cause was spelling. The command-line tool matches an allowlist entry against the literal text of a command. Wick’s instructions called the guard using the home-directory shortcut (a tilde), and the allowlist named it by its full path. The tilde isn’t expanded before matching, so the two never met, and in non-interactive mode a refused command fails quietly.
All the common spellings are allowed now. The broader change is how I read an allowlist: each entry permits one spelling of a command. Allowing git status doesn’t allow git -C <folder> status, so where a command has several common spellings, all of them are listed.
What’s still rough
- Wick runs as the same Unix user as everything else, and its allowlist includes general tools such as Python, so it could write around the guard. The guard catches mistakes and keeps an audit trail. It can’t stop an agent set on getting around it. A hard boundary needs Wick under its own user account, and that hasn’t been set up.
- Wick’s own small scripts skip the ship path on purpose, inside scheduling limits held in code.