His computer

A shell, an editor and a browser of his own, on your Mac, with rails.

One toolset, everywhere

Edward has the same fourteen tools in every turn: your chat, voice, pings, his wakes, the screens’ pulse and scheduled events. What a turn may do with them is its policy (did you ask? may it reach people? may it push?), checked when a tool is called; a refused call comes back as an honest Tool error: with the reason.

ToolWhat it does
bashA persistent shell in his home folder, sandboxed
str_replace_based_edit_toolView, create and edit files, under the same rails
web_search, web_fetchSearch the web and read pages
browserHis own invisible browser
chromeYour Chrome, through the Edward extension (off by default)
lookSee images, PDFs, a web page or the screen as pictures
messagesRead iMessage and mail
send_messageThe one guarded way to message someone
tell_ownerReach you: a note on Today, or a push
memorySearch, remember, close, explain or forget memories; read and write documents
scheduleReminders, follow-up wakes, your calendar and Reminders
screenHis screen, the household screen and the iPhone widget
planA visible checklist for longer work

Skill switches only take tools away: Shell/Bash gates the shell and editor, Web Search the web tools, iMessage the message tools, iOS Widget the widget, Push Notifications the urgent push.

His home and his shell

~/edward-home is his: bin/ (on his PATH), projects/, skills/, downloads/, jobs/ for background logs, and a Python 3.12 environment of his own. He may pip install, use uv and npm, and brew install ordinary formulae.

  • One persistent bash per conversation, so cd and variables carry over between commands.
  • 180 seconds a command; long work is a background job plus a scheduled wake to check on it.
  • A watchdog kills a session past 2 GB of memory or when the disk runs low; at most four sessions at once.
  • Every output is scanned and secrets are redacted before the model sees it.
  • Its environment is an allowlist: no API keys, no .env values, no database address.
  • If the sandbox can’t apply, bash fails closed. It never silently runs unsandboxed.

The rails

The shell runs under a macOS Seatbelt profile rendered from one table of rails, which the in-process editor checks too:

  • Not his own credentials: the session-signing key, the setup code and .env, however the path is spelled (compared by the file’s identity on disk, so case variants, symlinks and hard links count).
  • Not his own running code: no writes to the checkout Edward runs from, his releases or his own sandbox config, and none of the directories above them can be renamed or moved.
  • Not what production runs on: no writes to either Postgres cluster’s data or to Homebrew’s [email protected] and postgresql@16, and no upgrading them.
  • Not the services that act as you: no connection to Edward’s own API (:8000, :3000), the WhatsApp bridge, or his databases (:5432, :5433).
  • Not your other apps: no launching or scripting apps (messages go through send_message, never tell application "Messages"), never a second Google Chrome, and signals only to his own processes.

The sandbox is not a containment boundary. The shell runs as your macOS user. Reads are open (except his own credentials), and writes are open everywhere but the protected paths, including your shell startup files, ~/Library/LaunchAgents and Homebrew, from which programs later run as you, outside the sandbox. The rails stop accidents and turn misuse into deliberate work; they don’t make it impossible. For real isolation, run Edward under his own macOS user (prompt G in Adapting to your Mac). Short of that, keep friends’ pings on their default, which gives them no shell.

Two browsers

browser: his own

Playwright’s bundled headless shell, never Google Chrome, with his own cookies (never yours). It opens http and https only, and every request and redirect is checked: nothing on this Mac or your network, only public addresses. He can open, read, find, click, type, scroll and download.

chrome: yours, if you allow it

With EDWARD_CHROME_HANDS=on and the unpacked extension in chrome-extension/ loaded, Edward can use your own, signed-in Chrome. The extension connects only directly from this Mac, and only Edward’s own extension ID is accepted. Rails:

  • Typing outside a search box, pressing Enter there, or clicking anything labelled send, post, delete, accept, confirm, share and the like acts as you, so it runs only when you asked in that turn.
  • A payment step, or typing anything that looks like a card number, is refused in every turn.
  • Taking a picture of a tab never switches your active tab.

Chrome shows its “being debugged” bar while he works, unless you set EDWARD_CHROME_SILENT_DEBUGGER=on. With the hands on, /screen also opens as a tab in your Chrome (see Widget, screen & hub).

look

look hands the model the picture itself, not another model’s description of it: a photo from a chat, a file, a PDF, a web address, his own page, your Chrome tab, or this Mac’s screen (which needs Screen Recording for the backend’s python). Images are scaled to 1600 pixels at most, never up; a turn carries at most 40 images.

The web

On Claude, web_search and web_fetch are Anthropic’s server tools: the search and fetch run at Anthropic. With EDWARD_SERVER_WEB_TOOLS=off (or on the Codex fallback) they run locally: Brave Search with your key, and a local fetch that refuses this Mac and your network on every hop.

Your calendar and Reminders

  • Reading: straight from Calendar’s and Reminders’ own databases on this Mac (Full Disk Access), read-only, in every turn. If they can’t be read he says so; he never reports an empty day instead. apple-mcp, if set up, is the calendar’s fallback.
  • Changing: only when you ask, through a small signed EventKit helper (macOS 14+). Grant it once, at the Mac, with bash backend/scripts/eventkit_request_access.sh. Edward never asks macOS himself, because a dialog nobody answers would hang a turn.

The long form, including the full list of what the sandbox does not prevent, is computer.md.