Claude Code
Each Claude Code session on a developer workstation becomes a citizen of the town, “Claude (name of the agent)”, typing at its desk while Claude works. Its permission requests reach the mail, so you can approve them from your phone. And a member of the town can give the agent a mission: a task Claude runs in a repository, on the plan of the developer.
This goes through the local agent, a small program of the Myrtille command line that runs on the workstation.
What Myrtille never does
Section titled “What Myrtille never does”- It never writes a file into a repository: the hooks go in the settings of the user, never in a project, and only after you saw the change and said yes.
- It never reads, stores or forwards a Claude credential, and never offers a “sign in with Claude”. Missions run the
claudeyou installed and signed in to yourself. - It never sends a prompt, a file content, an edit, a tool response, an answer of Claude or a transcript to the town hall. Transcripts never leave the workstation.
- It never skips the permissions of Claude Code, and never uses
--bare. Myrtille is never the only barrier: the permission rules and the sandbox of Claude Code stay in force. - It never opens a port to the network: the agent connects out to the town hall, and serves its hooks on
127.0.0.1only.
What you need
Section titled “What you need”- Claude Code 2.1.300 or later.
- Node 22.19 or later on the 22 line, or 24.6 or later.
- The command line of Myrtille, installed once:
npm install -g @myrtillehq/cli. It is published by the release pipeline of the project: thenextchannel before version 1.0 (@myrtillehq/cli@next),latestfrom 1.0.
Connect a workstation
Section titled “Connect a workstation”In the town, an owner creates an enrolment token (the step Agent of the setup, at /setup). It is single use and valid 15 minutes. Then, on the workstation:
myrtille connect https://town.example.commyrtille agentmyrtille init --hooksmyrtille connect <address>enrols the workstation: paste the enrolment token when it asks (typed without echo), or setMYRTILLE_ENROLMENT_TOKEN. A token given as an argument could be read by other users of the machine while the command runs. The token is traded for the long-term token of the agent, which the town hall renews over the connection. Options:--name <name>(the name the town plan refers to, by default the host name),--port <port>(the hook port, 7421 by default). The address must behttps, orhttpon this machine only, unless you add--allow-http.myrtille agentruns the agent until Ctrl+C. It keeps one outbound connection to the town hall and comes back on its own after a cut.myrtille init --hooksgives Claude Code its hooks (below).
The agent keeps its state readable by you only, in MYRTILLE_AGENT_DIR or else:
| System | Directory |
|---|---|
| Linux | $XDG_STATE_HOME/myrtille/agent (by default ~/.local/state/myrtille/agent) |
| macOS | ~/Library/Application Support/myrtille/agent |
| Windows | %APPDATA%\myrtille\agent |
The hooks, with your consent
Section titled “The hooks, with your consent”myrtille init --hooks writes the hooks of Claude Code in the settings of the user: $CLAUDE_CONFIG_DIR/settings.json, else ~/.claude/settings.json. Never in a project.
- It shows what changes and asks first (
--yesskips the question). - It adds its hooks after your own, and keeps the previous file as
settings.json.myrtille-backup, readable by you only. - It never touches a file that is not valid JSON, nor one that changed while you were asked.
- It refuses to make Claude Code run a copy of the command line that lies in a git working tree, a temporary folder or an npx cache, which a coding agent working there could change: install the command line instead.
- Run it again after an upgrade of Myrtille to refresh the hooks.
myrtille init --remove-hooksremoves them, and only them.
Each hook runs myrtille hook claude-code <event>, which passes the event to the agent over a private channel of the workstation. No key or port is written in the settings. Every hook but the permission request runs in the background, so a session is never slowed down.
What leaves the workstation
Section titled “What leaves the workstation”Per event: the session id, the working directory, the tool name and a summary of at most 200 characters (the description Claude Code writes, the file a tool acts on, the site of an address), the subagent type, the task subject, the notification message. Never a command line, a query, a search pattern or the input of an MCP tool. What looks like a secret in a summary is masked first. The masking is a safety net, not a guarantee.
The town places a session in the district of the repository the town plan declares for its working directory (repo.path), else in a district of kind local.
Permissions in the mail
Section titled “Permissions in the mail”When Claude Code asks for a permission, the request becomes an item of the mail, critical when the command looks destructive (deleting files, rewriting git history, dropping data). The hook waits for the decision of the town:
- Allow lets Claude Code go on; Deny refuses, with your message to Claude if you wrote one.
- The item expires 5 seconds before the hook does (the hook waits 600 seconds). Claude Code then applies its own behaviour, its prompt on the workstation, and the town says the request expired.
- When nobody can decide it (actions off in its district), the request is let go at once and Claude Code decides as if there were no hook.
Missions
Section titled “Missions”A mission is a task given to an agent from its panel in the town (Give a mission), by a member with at least the operator role, after a confirmation: a mission spends the plan of the developer. It runs only:
- in a repository the town plan names for that agent, with
missions.enabled: true; - in a repository you allowed on that workstation:
myrtille agent --allow-missions <path>(the root of a git repository; up to 50); - one at a time per repository, on a clean working tree, on a branch of its own that the agent creates first (
mission/...).
The agent runs the claude of the workstation, unmodified and signed in by its user, headless: claude -p --output-format stream-json --verbose --permission-mode default, the prompt on standard input. A mission uses your own Claude plan, under the terms of Anthropic and the usage limits of that plan. The town sees the mission start, its turns, the tool in use and its end; it never sees the prompt again, nor the transcript or the answers of Claude. A member can cancel a mission: Claude gets an interrupt, then a stop after 5 seconds.
Permissions inside a mission
Section titled “Permissions inside a mission”A headless session cannot show a prompt, so a mission gives its own session a hook, for that session only, passed with --settings (nothing is written into the repository or into your settings). When a tool call is not allowed by the settings of the repository, the session stops on that call and the agent opens a permission item in the mail. The item waits up to 30 minutes.
- On Allow or Deny, the agent resumes the session with
claude -p --resume <session id>, and the hook answers that very call. The mission goes on. - Without a decision in time, the call is denied with the reason, and the mission goes on without it.
- Calls an allow rule of the repository lets through, and calls a
denyoraskrule may match, follow the settings of the repository as before. - The end of a mission names the tools that were refused, never their input.
Allow missions only in a repository whose .claude/settings.json you trust, as you would before running claude there yourself.
When the town hall is out of reach
Section titled “When the town hall is out of reach”Myrtille is a comfort layer, never the only barrier.
- When the agent is not running,
myrtille hookexits at once and Claude Code goes on as if there were no hook. - When the town hall cannot be reached, or is lost while a permission waits, the hook answers at once with nothing, and Claude Code applies its own behaviour: its prompt on the workstation.
- Events wait in a queue on the workstation and are sent once the town hall is back. Meanwhile the citizens of the workstation turn grey in the town, with the time of their last news.
- A town hall that refuses the token of the agent (revoked or expired) stops it: run
myrtille connectagain.
Security of the agent
Section titled “Security of the agent”- The hook server listens on
127.0.0.1only and refuses a request without the key of the agent, from another host name, or from a web page. - The hooks of Claude Code reach the agent over a private channel only its user can open, and the key itself never travels on it.
- The agent sends its long-term token in the
Authorizationheader of one WebSocket to the town hall. Tokens and the key are never printed or logged. - Missions run
claudeandgitby their absolute path, never a copy committed in the repository, and pass them only the variables they need: never a token of Myrtille, of Coolify or of an API, and neverANTHROPIC_API_KEY.