claude-computer
GitHub

claude-computer · reference

What's inside

A plain list of what you get when you create an instance from claude-computer: every package it installs, every service it talks to, where files go, what each script does, and what runs without being asked.

Each line is in the repo — Brewfile, setup-tools.sh, vscode-extensions.txt, bin/, claude-global/, docs/. If the two ever disagree, tools/check_inventory.py in the site repo fails and the page is wrong.

  • 68packages
  • 17services
  • 5machines
  • 37scripts
  • 12commands
  • 4hooks
  • 9jobs
On this page 8 sections
  1. What it installs
  2. Services it uses
  3. My fleet
  4. Folder structure
  5. The second brain
  6. Every script
  7. The process
  8. Getting it

What it installs#

Packages come in three Homebrew layers. Brewfile goes on every machine; Brewfile.dev adds the build-machine tools; Brewfile.server is for headless Macs. Anything installed beyond these layers belongs in that machine's file, or map-check reports drift.

Needed by the setup itself#

  • domt4/autoupdateHomebrew tapdaily brew autoupdate keeps packages current
  • ghGitHub CLIrepos, keys and PRs without a browser
  • agefile encryptionone key per machine opens the secrets store
  • sopsencrypted config filessecrets/secrets.yaml: names in clear, values not
  • gitleakssecret scannerpre-commit backstop in every repo
  • rcloneobject-storage syncarchive, camera cold copy, encrypted resources
  • masMac App Store CLIinstalls Xcode on build machines
  • jqJSON processorevery hook parses its input with it
  • coreutilsGNU utilitiesgtimeout, used by the session-start and stop hooks

Claude uses these from its shell#

  • ripgreptext searchthe default way Claude searches; one config caps lines
  • fdfiles by namereads .gitignore and .ignore, like rg
  • ast-grepstructural code searchmatches syntax, not text — skips comments and strings
  • yqYAML processorjq for frontmatter and config files
  • shellcheckshell linterlint for every bash script, including Claude's
  • justcommand runnerone name per project task: just --list
  • treedirectory treea directory's layout in one call

Languages and runtimes#

  • miseversion managerone manager for Python and Node versions
  • uvPython packages, scriptsuv run --script runs the Python in bin/
  • pnpmJS packagesno npm, no yarn

For you at the terminal — Claude doesn't use these#

  • starshipprompta powerlevel10k-style line, from a file
  • herdragent workspacesevery Ghostty window shares one session
  • zsh-autosuggestionszsh suggestionsfewer keystrokes
  • zsh-syntax-highlightingzsh highlightingcatch a typo before you run it
  • fzffuzzy finderinteractive picking in the shell
  • zoxidesmarter cdz <dir>; never aliased over cd
  • direnvper-folder envloads a project's .envrc when you cd in
  • lazygitgit TUIlg, for reviewing a messy tree by hand
  • batcat with highlightingreadable file output; never aliased over cat
  • ezamodern lsll; never aliased over ls
  • git-deltagit diff pagergit's pager for you; plain when piped
  • tlrctldr clientshort examples instead of man pages

None of these is aliased over a standard command. Claude Code copies shell aliases into its own shell, where a model's ls -lt or cat -A would run a tool that reads those flags differently.

Ghostty opens every window, and the ⌥Space quick terminal, into one herdr session. Its sidebar shows each Claude Code session as working, blocked, done or idle; macOS tells you when one finishes or needs you, and ⌘J jumps to it. Ghostty's ⌘ shortcuts drive herdr's tabs and panes.

Ops and networking#

  • btopprocess monitorwhat is eating the machine
  • tmuxterminal multiplexerlong jobs that outlive a window
  • watchrepeat a commandwatching a job change something
  • naabuport scanneranswering "why is this port open"
  • mtrtraceroute + pingdiagnosing a flaky link to a box
  • wgetfile downloaderfetching a file in a script

Media and documents#

  • ffmpegaudio and videotranscode, trim, extract audio
  • imagemagickimage conversionresize and convert in scripts
  • pandocdocument conversionmarkdown to anything
  • popplerPDF toolstext and pages out of PDFs
  • exiftoolmetadata readerthe camera brain finds photos by metadata
  • ocrmypdfOCR for PDFsscanned family documents become searchable

Apps#

14 apps and fonts
  • claude-codeClaude Codethe operator; installed first, listed for rebuilds
  • ghosttyterminalits config is a text file the brain can own
  • tailscale-appprivate networkhow a manager machine reaches a headless box
  • google-chromebrowserthe human's browser, never the headless one
  • visual-studio-codeeditorfor the times you read code yourself
  • obsidiannotesthe second brain is plain markdown in a repo
  • claudeClaude desktop appthe chat window beside the terminal
  • telegrammessagingwhere tg-send lands
  • iinamedia playerplaying what the camera brain ingests
  • libreofficeoffice suitesoffice --headless converts generated documents
  • macparakeeton-device dictationtranscripts without anything leaving the Mac
  • font-meslo-lg-nerd-fontmonospace fontthe terminal font, with the prompt's glyphs
  • qlmarkdownQuick Look: markdownspacebar on a note shows the note
  • syntax-highlightQuick Look: sourcespacebar on code shows code

macparakeet is Apple-silicon only (macOS 14+); the Brewfile skips it on Intel, and the dictation and transcript pipeline goes with it.

The dev-machine layer#

  • orbstackcontainers on macOSDocker for Python services and self-hosting
  • calibreebook librarybooks and comics in library/
  • cloudflare-wranglerCloudflare CLI, run as wranglerWorkers, D1, R2 and DNS from the terminal
  • biomeJS/TS lint and formatone tool instead of ESLint plus Prettier
  • ruffPython lint and formatthe Python half of the same rule
  • pyrightPython typestype hints checked; Claude's Python LSP
  • typescript-language-serverTypeScript language serverClaude's TypeScript LSP
  • mermaid-clidiagram renderermmdc for quick diagrams
  • ccusageClaude Code usageseeing what all-day sessions cost
  • XcodeApple toolchain (via mas)iOS builds; needs an Apple ID in the App Store

darktable, for the camera brain, is an optional manual install: Homebrew disabled its cask because the macOS build fails Gatekeeper, so /setup asks, and on a yes you download it from darktable.org and choose Open Anyway.

claude-global/settings.json turns on the official pyright-lsp and typescript-lsp plugins, so Claude navigates Python and TypeScript by symbol — definitions, references — instead of by text, and sees type errors after each edit. The two servers above are what they talk to.

The server layer#

  • cloudflaredCloudflare Tunnelexposing a service without opening a port

orbstack is in this layer too, for Bugsink and other self-hosted containers.

VS Code extensions#

Installed from vscode-extensions.txt by setup-tools.sh. Extras on one machine go in that machine's file.

17 extensions
  • anthropic.claude-codeClaude Code in VS Codethe same operator, in the editor
  • ms-vscode-remote.remote-sshremote editingediting on a headless box
  • eamodio.gitlensgit blame and historywho changed this line, and when
  • ms-python.pythonPython supportone of the two languages
  • ms-python.vscode-pylancePython language servercompletions and types
  • charliermarsh.ruffRuff in the editorsame linter as the command line
  • biomejs.biomeBiome in the editorsame formatter as the command line
  • redhat.vscode-yamlYAML supportconfig and CI files
  • tamasfe.even-better-tomlTOML supportpyproject.toml, starship.toml
  • timonwong.shellcheckShellCheck in-editorbin/ is bash
  • yzhang.markdown-all-in-onemarkdown editingbrains and notes are markdown
  • davidanson.vscode-markdownlintmarkdown lintingkeeps the docs consistent
  • mechatroner.rainbow-csvCSV viewerreading exports without a spreadsheet
  • usernamehw.errorlensinline errorsproblems where they happen
  • editorconfig.editorconfigEditorConfigone indent rule across editors
  • streetsidesoftware.code-spell-checkerspell checkthe docs are the product here
  • gruntfuggly.todo-treeTODO indexfinding what you left behind

What Homebrew can't install#

setup-tools.sh handles the rest, in idempotent steps you can run one at a time with --only.

  • oh-my-zshthe zsh framework, keeping the linked ~/.zshrc
  • runtimesmise use --global [email protected] node@lts
  • playwrightthe pinned Playwright CLI and its bundled Chromium, profiles 700
  • agent-reachAgent Reach from a pinned commit, with yt-dlp and mcporter, and its Claude skill
  • macparakeetlinks macparakeet-cli from the app bundle onto PATH
  • vscodethe extensions above
  • autoupdatethe daily brew autoupdate agent (upgrade and cleanup)

Agent Reach covers the platforms the bin/ wrappers don't: YouTube transcripts, GitHub, RSS, and social channels if you opt in. It installs upstream tools and one skill that tells Claude which to call; agent-reach doctor says which channels work. Only the channels that need no login are installed. One that needs a cookie or a key keeps it in ~/.agent-reach/config.yaml, outside the secrets store, so adding it is yours to do: agent-reach configure, run yourself.

Also linked or applied by /setup, not installed: dotfiles/ (zshrc, zshenv, ripgreprc, starship.toml, ghostty.config, herdr.toml, gitconfig, gitignore_global, editorconfig) and macos-defaults.sh (keyboard repeat, Finder, Dock, hot corner, screenshots to ~/Pictures/Screenshots, ask for password on wake). ripgreprc caps each line rg prints at 200 bytes and changes nothing about what matches; zshenv points every shell at it, including the non-interactive ones agents run, which never read zshrc. zshrc titles each terminal tab after the client, project or product the shell is in, and a wt worktree as <name> ⎇ <branch>.

Services it uses#

Accounts come first, before you touch the machine, because every later step that needs a login stalls without one. Costs are only listed where the repo states them, and they were true at time of writing. A dash means the repo names nothing there.

Required6

  • Claude Max

    required

    Claude Code itself — the operator

    Cost paid subscription

    Could be replaced by nothing; this is Claude Code

  • GitHub

    required

    every repo, the SSH key, PRs, Actions

  • Homebrew

    required

    packages on every Mac

    Cost free

  • Tailscale

    requiredfor more than one machine

    the tailnet a manager uses to reach a box

    Could be replaced by a swap invited by CONTRIBUTING

  • Cloudflare R2

    requiredto use those folders

    archive, camera cold copy, encrypted resources

    Cost cheap, no egress fees

    Could be replaced by S3

  • Telegram bot

    requiredfor notifications

    tg-send when a job ends; capture from your phone

    Cost free

Optional11

  • Cloudflare (Workers, D1, Pages, DNS)

    optional

    shipping projects (Next.js via OpenNext), DNS

    Cost not stated; set a spend alert

    Could be replaced by Vercel; Fly.io or Railway for Python

  • Tavily

    optional

    tavily web search

    Could be replaced by exa, jina, firecrawl

  • Exa

    optional

    exa semantic search

    Could be replaced by tavily, jina

  • Firecrawl

    optional

    firecrawl page to markdown; feed full text

    Could be replaced by jina, or browse

  • Jina Reader

    optional

    jina page or search as markdown

    Cost works keyless at a low rate limit

    Could be replaced by firecrawl, browse

  • Google Cloud OAuth

    optionaladded later

    gcal, gmail, gdrive, gtasks, analytics

  • PostHog

    optional

    analytics, replay, flags, errors in projects

    Cost free tier: 1M events, 5K recordings, 100K exceptions a month

    Could be replaced by self-hosted Bugsink

  • Turso

    optional

    SQLite off Cloudflare, embedded replicas

    Cost free plan: 100 databases, 5 GB

    Could be replaced by Cloudflare D1, a plain file, Supabase

  • Resend

    optional

    transactional email from a project

  • Expo EAS

    optional

    mobile builds and submissions

  • Mac App Store (Apple ID)

    optionalbuild machines

    Xcode through mas

    Cost free

    Could be replaced by downloading Xcode yourself

MacParakeet transcribes on the machine; nothing leaves the Mac. There is no Dropbox, no Syncthing and no iCloud Drive on working folders: every job they would do is already covered, and a second sync engine brings its own idea of what "deleted" means. A folder of git repos is worse — two machines writing the same .git through a two-way sync can corrupt it, and a deletion on one machine is a deletion on all of them.

There is no secrets service. Every key above lives in secrets/secrets.yaml in your private instance as <name>.<field> — names in clear, values encrypted with sops to an age key on each manager machine and to a paper backup key. The bin/ wrappers decrypt one value at a time; Claude never decrypts anything, and you type every value yourself with secrets set. docs/SECRETS.md lists each one and how to get it. Losing r2-crypt.password means losing ~/resources in R2; it cannot be recovered from the bucket. Website logins stay in your own password manager — Apple Passwords is enough.

My fleet#

Five machines and a camera, in two kinds. A manager machine runs Claude Code and keeps a clone of the brain at ~/claude-computer; it writes its own docs/machines/<host>.md and nobody else's. A headless box has no brain: a manager reaches it over Tailscale and SSH, and afterwards writes that box's file onto it at /etc/claude-computer/machine.md, so the box can still say what it is if the repo goes stale.

Every one of my manager machines clones the same private repo — I called mine sys-admin. What makes a machine itself isn't the repo name, it's the hostname: Claude reads scutil --get LocalHostName and keeps docs/machines/<host>.md for it, and tags every commit [<host>]. So name your machines what you want to see in that path — sudo scutil --set LocalHostName mini — and keep the clone at ~/claude-computer on every one of them, because the hooks and permission rules assume that path. See docs/INSTALL.md § One repo for the whole fleet.

  • Laptop

    the daily driver

    manager machine, clone of the brain

  • Mac Studio

    runs a local Qwen model

    manager machine, clone of the brain

  • Mac Mini

    where the first from-scratch /setup is being run

    manager machine, clone of the brain

  • Hetzner VPS

    headless Linux, managed entirely by Claude

    headless box over Tailscale and SSH

  • Raspberry Pi

    the media centre

    headless box over Tailscale and SSH

That's my fleet; yours will differ. A machine that is not in docs/FLEET.md is out of scope until you add it — nothing is managed implicitly.

One more thing on the fleet that has no operating system:

Folder structure#

  • ~/
    • claude-computer/the fleet brain — repo
    • clients/<name>/one private repo per client — brief/ is tracked
    • projects/active work — one repo per project (+ _scratch/, disposable)
    • products/projects that graduated to production — one repo each
    • personal/finance, personal projects — one repo each
    • vault/Obsidian second brain — repo
    • archive/cold storage staging — pushed to object storage, then removed
    • library/camera (RAW workflow), books and comics (Calibre)
    • resources/<person>/family key documents — encrypted two-way sync

Top-level folders are containers, not repos (except claude-computer and vault). Repos live one level down; a folder there with no CLAUDE.md may group the repos of one thing — a product with a site and an API.

A client folder is a repo of its own, so the client's documents in brief/ are versioned and backed up like code, and never live on one machine only. Code built for that client is a separate repo inside the client's folder, which the client repo ignores. new-client <name> makes one; new-app <type> <name> --dir ~/clients/<client> adds the code.

Any folder that needs automation gets a CLAUDE.md — a brain — and a TASKS.md. Folders that just hold files have no brain. The vault is laid out for cheap capture and for Claude's retrieval, not for browsing — the second brain has its own section below.

The repo itself#

  • CLAUDE.mdthe fleet brain's operating instructions
  • install.shthe one-liner that puts the operator on a new Mac
  • bin/every script; each answers --help and returns exit codes
  • lib/common.shthe cc_* helpers and EX_* exit codes every bash script sources
  • lib/cc.py, lib/google_auth.pythe same for the uv run --script scripts; Google OAuth
  • lib/dashboard/, lib/docs/the page shells for dashboard and docs-build
  • claude-global/linked into ~/.claude — global CLAUDE.md, hooks, commands
  • claude-global/settings.jsonthe template's permissions and hooks; you never edit it
  • claude-global/settings.overlay.jsonyours: rules added, rules removed with a reason, preferences
  • secrets/the sops-encrypted store, its example, and the backup key's .pub
  • Brewfile, Brewfile.dev, Brewfile.serverpackages, layered by role
  • setup-tools.shwhat Homebrew cannot install
  • vscode-extensions.txtthe editor extension list
  • dotfiles/shell, prompt, terminal, git — linked by /setup
  • macos-defaults.shdefaults write for a new Mac
  • templates/scaffolds for apps, their docs/, and the other brains
  • .githooks/pre-committhe gitleaks scan; enabled with git config core.hooksPath .githooks
  • tests/what CI runs beyond ShellCheck, including an install.sh dry run
  • docs/INSTALL.mdthe one-line install, and how to read it before you run it
  • docs/FIRST-PROMPT.mdthe prompt a new user pastes
  • docs/DEV-GUIDELINES.mdhow every project is built
  • docs/SECRETS.mdevery secret the scripts expect, how to get each value, and the age keys
  • docs/FLEET.mdindex of machines
  • docs/DECISIONS.mdappend-only decision log, [host] [date] tagged
  • docs/TEMPLATE-DECISIONS.mdwhy the template is built this way
  • docs/machines/one file per machine, written only by that machine
  • docs/diagrams/render.pythe hand-laid SVGs in the README
  • UPSTREAMthe template's URL, for the fetch-only remote
  • .template-versionthe template release this instance is on; template-pull updates it
  • CHANGELOG.mdwhat changed in each release, and the steps to move an instance across

The second brain#

Obsidian, over a git repo, with Claude doing the filing. Capture is free; filing, linking and retrieval are Claude's job. The vault has two layers: notes/ and daily/ are yours, in your own words; memory/ is Claude's graph of people, orgs, meetings, decisions, commitments, topics and projects, built only from evidence in sources/, every fact a dated log line that cites its source.

  • vault/
    • inbox/everything lands here — dictation, clips, phone and email, transcripts
    • daily/one note per day, drafted from tasks — yours
    • notes/flat. your own ideas, one per note — yours
    • sources/evidence: transcripts, clips, emails, repo snapshots, confirmations
    • memory/Claude's graph, every fact cited from sources/
      • people/one note per person, with dated ties
      • orgs/companies, clients, communities
      • meetings/one note per meeting, by year
      • decisions/what was decided, and what superseded it
      • commitments/who owes whom what, open until closed
      • topics/themes three or more notes share
      • projects/one hub per repo, kept after the checkout is gone
    • maps/all tasks, weekly reviews
    • Home.mdopen commitments, recent meetings, people — live Dataview views
    • _templates/one Templater template per type

Structure lives in properties, not folders. Every note has type and created, and each type its own required properties. The schema is the vault's own CLAUDE.md, and vault-lint checks every note in memory/ against it before anything lands. A missing property is an error; a property the type doesn't define is a warning with a guess — a commitment's dropped_on gets "did you mean done_on?" — and never fails the lint. Keys you add on purpose go in the vault's .vault-lint.yaml.

  • notenotes/nothing; links to topics, people, projects, sources
  • dailydaily/nothing
  • personmemory/people/name; relationship now, ties over time; on your own note, github and git_authors
  • orgmemory/orgs/name
  • meetingmemory/meetings/YYYY/date, attendees, transcript
  • decisionmemory/decisions/date, status (made, superseded, reversed), sources
  • commitmentmemory/commitments/from, to, status (open, done, dropped), made_in
  • topicmemory/topics/name
  • projectmemory/projects/status, repo
  • sourcesources/kind: transcript, clip, email, repo, confirmation …

How things get in#

Capture is one move; the route and what runs on it are Claude's problem.

CaptureRouteScript or command

  • A thought, a to-dodictate into inbox/quick.mdnone — the cheapest capture wins
  • A meetingrecord it in MacParakeettranscripts-sync
  • A file, a URL, a podcastmacparakeet-cli transcribe … --no-historynone — it stays out of the database
  • A message, photo or voice notesend it to your Telegram botcapture, every 5 minutes
  • An emaillabel it vault in Gmailcapture, every 5 minutes
  • A web pageObsidian Web Clipper, saving to inbox/none
  • RSS and newsletterssources/feeds/feeds.txtfeeds-sync, daily 06:00
  • A GitHub repoproject-import <owner/repo>, or --catalogue for all of thema snapshot in sources/repos/, no clone

What Claude does with it#

  • /transcripts — each recording becomes a meeting note, matched to its calendar event with gcal at: five summary lines, what was discussed, decided and left open; the people and orgs linked or created; decisions and commitments as notes of their own; action items routed to the brain that owns them; the raw transcript filed in sources/.
  • /inbox — transcripts first, then every capture: your own thinking into notes/, material from elsewhere into sources/, people and decisions pulled out of both.
  • commitments — lists what is owed, yours first; commitments brief picks what is overdue or due this week and who you met yesterday; and it closes or reopens one with your word as the evidence, filed as a dated confirmation.
  • /today — the daily note, drafted from every brain's tasks and from commitments brief rather than the calendar: Now, Commitments, Met yesterday, Due this week. The night shift's ## Overnight stays at the top.
  • /review — the weekly pass: it empties ## Unassigned, hands each new Google Task to a brain, proposes done, dropped or a new date for every commitment past due, and a status for the hubs of projects whose checkout is gone.

The night shift#

vault-nightly runs at 04:30 on the vault's home machine and does the filing with nobody watching: it runs /inbox with claude -p over the day's transcripts and captures, and writes a few project hubs from fresh repo snapshots. It is fenced. Claude works in a git worktree of the vault, never the vault itself, with --permission-mode dontAsk and a short list of allowed tools, so anything else is refused rather than asked. Tasks for other brains go to a file the script validates before it writes them. The result merges only past a gate — vault-lint clean, nothing deleted outside inbox/, nothing uncommitted — and a failed run leaves the vault and its inbox exactly as they were, and says so on Telegram. What it did is under ## Overnight in the next daily note, every item linked and every commit revertible.

Rules that keep it sane#

  • Every fact in memory/ cites evidence. No source, no fact. A changed fact gets a new dated log line; nothing true at the time is overwritten.
  • Your words are never rewritten. In notes/ and daily/, Claude adds properties and links; the text stays yours. If you edit a memory/ note, your edit wins over Claude's next pass.
  • Tasks live with their brain; the vault gets copies. tasks-sync writes read-only copies into maps/tasks.md and a block in each hub in memory/projects/. Ticking a box in Obsidian changes nothing — you change a task by telling the brain that owns it.
  • Generated and authored content never mix. Scripts write only between their markers or in notes marked generated. Everything else is yours, and no script overwrites it.
  • A hub is keyed by its repo, not a checkout. When a checkout goes, its hub's task block is frozen and /review decides whether the project is done, archived or abandoned.
  • ## Unassigned has an exit. Action items no brain owns sit at the top of the task map; every weekly review gives each one an owner or drops it to ## Later; once there are more than ten, tasks-sync sends one Telegram alert a day.
  • Nothing leaves the Mac to become text. MacParakeet transcribes on the machine, voice notes from your phone included.

Why not PARA#

PARA was designed for a human doing the filing. It asked me to decide where a note belonged at the moment I had the least context to decide. With Claude filing, the right structure is an inbox, a flat notes folder, a graph Claude keeps and properties — and the discipline moves from "file correctly" to "capture everything."

What it needs#

The obsidian cask, and macparakeet (Apple silicon, macOS 14+ — the Brewfile skips it on Intel, and without it there is no dictation or transcript pipeline). vault-setup creates the vault and installs Obsidian Git, Dataview and Templater (third-party code; versions recorded), and on a second machine restores the plugin code a fresh clone is missing. The Web Clipper is a browser extension: install it by hand and point it at inbox/. capture needs a Telegram bot and, for email, the Google sign-in; run it on one machine only.

Every script#

Everything in bin/ is on the PATH, answers --help, and returns an exit code rather than prose: 0 ok, 1 failed, 2 usage, 3 a tool is missing, 4 no age key or this machine can't open the secrets store, 5 missing config or secret.

You run it8

  • analytics#set up GA4 and Tag Manager from a project's analytics.yaml; funnels, reportsyou or Claude; publish only when you say
  • archive-pull#search the R2 archive index and restore a file or folderyou, or /retrieve
  • archive-push#move a folder from ~/archive to R2, verify, rebuild INDEX.mdyou, or /archive
  • camera-ingest#copy a memory card into the camera library, verified, then push to R2you, when a card goes in
  • schedule#install, remove and list the fleet's launchd jobsyou, during /setup
  • secrets#the sops + age store: status, set, admit a machine, run a project with keysyou; Claude only for status and checks
  • template-pull#apply a template release file by file, three-way; --dry-run firstyou, when a release is out
  • wt#create a git worktree for a branch and open a session in ityou

Claude, mid-session12

  • browse#load a page in Playwright's Chromium: markdown, screenshot or PDFClaude, feeds-sync
  • commitments#open commitments, yours first; brief for the day; close or reopen one on your wordClaude, vault-nightly, you
  • dashboard#a live progress page for a long task: tasks, questions, deliverables, blockersClaude, before any task of more than five steps
  • exa#semantic web search, markdown outClaude
  • firecrawl#scrape a URL to clean markdownClaude, feeds-sync
  • gcal#today, a given day, what overlapped a time, search and add — every calendarClaude, /transcripts
  • gdrive#search, download, upload and share Google Drive filesClaude
  • gmail#search, read, draft, send and label Gmail, save attachments; send asks firstClaude, feeds-sync
  • jina#read a URL as markdown, or search, via Jina ReaderClaude
  • project-import#snapshot a GitHub repo into the vault through gh api, no cloneClaude, vault-nightly, you
  • tavily#web search, markdown outClaude
  • tg-send#send one plain-text Telegram line, prefixed with the machine namehooks, map-check, Claude

A slash command8

  • gtasks#Google Tasks: list, hand a task to a brain, mark it done/review, Claude
  • https-check#check that a public domain redirects http:// to https://; --fix on Cloudflare/graduate, /review, you
  • new-app#scaffold a project, init git, create a private GitHub repo/new-app
  • new-client#make ~/clients/<name> a private repo, new or adopted/new-client
  • security-check#check FileVault, firewall, sshd, browse profiles, Tailscale, private reposmap-check, /setup
  • settings-build#build ~/.claude/settings.json from the template's base and your overlay/setup, map-check, you
  • vault-lint#check vault notes against the vault's schema; warn on an unknown property/transcripts, /inbox, vault-nightly
  • vault-setup#create ~/vault from the template and install its three Obsidian plugins/setup, or you

A hook2

  • docs-build#check a project's docs/ and build llms.txt and one offline reading pagejust lint, SessionStart hook, Claude
  • tasks-sync#collect every brain's TASKS.md into read-only vault copies and project hubsSessionStart hook, schedule hourly

A schedule7

  • capture#your Telegram messages and Gmail's vault label into the vault inboxschedule, every 5 minutes, on one machine
  • feeds-sync#build today's reading digest from RSS and newsletter emailschedule, daily 06:00
  • library-push#copy ~/library/books and ~/library/comics to R2, verified, never deletingschedule weekly, or you
  • map-check#diff packages, extensions, launchd jobs, ports and settings against the mapschedule daily 09:00, /setup, /review
  • resources-sync#two-way encrypted sync of ~/resources with R2schedule, hourly
  • transcripts-sync#export completed MacParakeet transcriptions into the vault inboxlaunchd watch on the database, SessionStart hook
  • vault-nightly#the night shift: /inbox unattended, landed only past the vault-lint gateschedule, daily 04:30

The process#

Four forms, one rule: if it can be a script, it is a script. A slash command is for a step that needs judgment; it orchestrates scripts rather than reimplementing them. A hook is for what must happen every time without asking. A scheduled job is for what must happen with no session open.

Slash commands#

Linked into ~/.claude/commands/ from claude-global/commands/.

  • /setup#a new machine, or the first run of a fresh instanceBrewfiles, setup-tools.sh, map-check
  • /today#start of the day: open or draft today's note from tasks and commitmentstasks-sync, commitments brief
  • /inbox#empty the vault inbox: your thinking to notes/, the rest to sources//transcripts, vault-lint, commitments
  • /transcripts#a meeting finished: meeting note, people, decisions, commitments, taskstranscripts-sync, gcal at, vault-lint
  • /review#weekly: what changed, what's stuck, what's overdue, where the map driftedtasks-sync --json, gtasks, commitments, map-check
  • /new-app#a new project: pick the target, scaffold it, write its brainnew-app
  • /new-client#a new client, or an existing client folder that needs its own reponew-client, tasks-sync
  • /graduate#a project reached production and moves to ~/productsgit, tasks-sync, project-import
  • /archive#push folders to R2 cold storage and remove the local copyarchive-push, project-import
  • /retrieve#find something in the archive and restore itarchive-pull
  • /rotate#a key needs replacing, and everything using it re-testedthe wrappers, wrangler, gh
  • /upstream#a lesson worth sharing becomes a generic PR against the templategh, gitleaks

Hooks#

These run every session, without asking. That is the point: the syncing does not depend on discipline.

  • session-start.sh#SessionStartpulls the repo, reports secrets status, syncs transcripts and tasks, rebuilds the docs page
  • prompt-submit.sh#UserPromptSubmitnotes when the turn started, so the Stop hook can tell a long run
  • stop.sh#Stop, end of every turncommits and pushes docs/ (and secrets/, only if all encrypted); pings after 10 minutes
  • notify.sh#NotificationTelegram line when Claude is waiting on you

Permissions come from the same folder, but ~/.claude/settings.json is built, not linked. settings-build writes it from the template's claude-global/settings.json and your own claude-global/settings.overlay.json, so your rules survive every release instead of conflicting with it. The base sets defaultMode: auto and puts git push, rm, brew uninstall, sudo, every rclone verb that writes, configures or serves (and rclone -*, for a flag before the verb), archive-push, resources-sync, library-push, new-app, new-client, agent-reach configure and every secrets command that writes (init, set, import-env, admit, revoke, push, exec) on the ask list. It puts force-push, every sops command that prints or edits a value, age -d, secrets env, the age key itself, the Keychain commands, .env files, SSH private keys, rclone.conf, the browse profiles and Agent Reach's config.yaml on the deny list. Read-only work is allowed outright: rclone listings (lsf, lsjson, lsl, size, check), vault-lint, gmail search and get, launchctl list, defaults read. Ask prompts even in auto mode; deny blocks in every mode. Neither is a sandbox.

The overlay adds rules, sets preferences, and removes a template rule only with a written why; it cannot remove a deny rule or an ask that guards secrets. It is committed with the rest of your instance, and CI checks that it builds on the template's base. When Claude Code changes ~/.claude/settings.json itself — "don't ask again", /model, /config — map-check reports the drift, settings-build --adopt keeps it in the overlay and --force drops it. hooks/rm-guard.py ships as an optional PreToolUse hook: wired in through the overlay, with rm taken off the ask list, it lets a plain rm inside /tmp or $TMPDIR run unprompted and asks about every other rm. The base also sets PAGER=cat and NO_COLOR=1 for every command Claude runs, so nothing pages and no colour codes reach the context.

Scheduled jobs#

Installed as launchd user agents by bin/schedule, prefixed local.claude-computer., logging to ~/Library/Logs/claude-computer/. map-check treats an unrecorded job as drift.

Through the day4

  1. daily 04:30

    vault-nightly#

    the night shift: files transcripts and captures into the memory graph

  2. daily 06:00

    feeds-sync#

    writes today's reading digest into the vault

  3. daily 06:30

    daily-note#

    drafts today's note with claude -p, fenced to ~/vault and a short tool list

  4. daily 09:00

    map-check#

    drift report; sends Telegram only when there is drift

Every few minutes1

  1. every 5 minutes, on one machine

    capture#

    your Telegram messages and vault-labelled email into the vault inbox

Every hour2

  1. hourly

    tasks-sync#

    refreshes the read-only task copies in the vault

  2. hourly

    resources-sync#

    encrypted two-way sync of ~/resources with R2

Once a week1

  1. weekly, Sunday 03:00

    library-push#

    cold copy of the Calibre libraries to R2; rclone copy, never sync

When something changes1

  1. when MacParakeet's database changes

    transcripts-sync#

    exports finished transcriptions to the vault inbox

library-push is the one job most machines have nothing to do for: it skips a folder that isn't there rather than failing, so it is harmless on a machine with no Calibre library.

daily-note and vault-nightly are the two jobs that run Claude with nobody to answer a prompt, so each is fenced. daily-note has ~/vault as its working directory and the only tree it can edit, and --allowedTools is Read, Edit, Write, Glob, Grep, the read-only commitments brief and git status/add/commit. vault-nightly works in a throwaway worktree of the vault with --permission-mode dontAsk, and lands nothing unless vault-lint passes (the night shift). Everything else is refused outright.

capture runs on one machine only: Telegram hands each message to whichever machine asks first.

A normal day#

  1. 04:30

    vault-nightly files yesterday's transcripts and captures into the memory graph, in a worktree, and merges only if vault-lint passes.
  2. 06:00

    feeds-sync writes the reading digest into vault/sources/feeds/.
  3. 06:30

    daily-note drafts vault/daily/<today>.md from the task picture, unattended, under the night shift's ## Overnight.
  4. You open a session.

    The SessionStart hook pulls the fleet repo, reports whether the secrets store can be opened, exports any new transcript, and refreshes the vault's task copies.
  5. /today

    review the draft, add what you know, and every task you mention goes to the TASKS.md of the brain that owns it, not into the note.
  6. Work.

    Claude reads the machine file first, uses the bin/ wrappers instead of MCP servers, and asks before anything destructive, credential-touching or billable. A long task gets a dashboard first; questions go on it with a proposed default, and the work carries on with whatever doesn't depend on the answer.
  7. 09:00

    map-check runs; if the machine and the map disagree, Telegram says so, and fixing it is this session's job.
  8. Through the day

    a thought sent to your Telegram bot, or an email labelled vault, is in the inbox within five minutes. After a meeting, transcripts-sync drops the transcript there too; /transcripts writes the meeting note, links the people and routes every action item to an owning brain — or the night shift does it at 04:30.
  9. Every turn ends

    with the Stop hook committing and pushing docs/, so the next machine starts from a true picture. Once a week, /review empties ## Unassigned.

Getting it#

The template is on GitHub: narendranag/claude-computer. You need a Mac, a GitHub account and a Claude Max subscription; the quick start is the short version. One line, pasted into Terminal:

/bin/bash -c "$(curl -fsSL https://claude-computer.com/install.sh)"

It asks one question — what your private repo should be called — then installs whatever you're missing and hands over. Want a different name, the same on every machine? Pass it explicitly: -- --name sys-admin --dir ~/claude-computer. docs/INSTALL.md covers the installer end to end — flags, exit codes, and the by-hand equivalent — and how to read it before you run it. What the setup does not protect against is written down too — the Trust section of the README is the part to read closely.

Staying current is one script. An instance made with "Use this template" shares no history with the template, so git merge refuses; template-pull lists the releases, and template-pull <tag> applies the template's own diff from the release you are on (.template-version) to the one you name, deciding each file on its own: a file you never touched takes the template's version, one you both changed merges three-way, and one that can't be merged is left as yours and listed with the command that takes the template's. The rest of the release applies either way. --dry-run reports the same lists from a throwaway worktree. It commits nothing, and ends with the CHANGELOG for those releases — read each "Migrating from" section, because some steps happen on every machine.