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.

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.

The setup itself#

Package What it is Why it's here
domt4/autoupdate Homebrew tap daily brew autoupdate keeps packages current
gh GitHub CLI repos, keys and PRs without a browser
bitwarden-cli bw, the secret store every key the scripts read comes from here
gitleaks secret scanner pre-commit backstop in every repo
rclone object-storage sync archive, camera cold copy, encrypted resources
syncthing peer-to-peer folder sync a working folder between my own machines
mas Mac App Store CLI installs Xcode on build machines
age file encryption optional; encrypt a file without a service
sops encrypted config files optional; config with secrets in it

CLI tools Claude reaches for (and I like as well)#

Package What it is Why it's here
ripgrep fast recursive grep the default way Claude searches code
fd fast file find finding paths without find syntax
fzf fuzzy finder interactive picking in the shell
jq JSON processor every hook parses its stdin with it
yq YAML processor frontmatter and config files
bat cat with highlighting readable file output
eza modern ls readable listings
tree directory tree showing layout in one command
git-delta git diff pager diffs you can actually read
shellcheck shell linter bin/ is bash; lint it
tlrc tldr client short examples instead of man pages
just command runner every project ships a justfile
coreutils GNU utilities gtimeout and friends, used by the hooks

Languages and runtimes#

Package What it is Why it's here
mise version manager one manager for Python and Node versions
uv Python packages, scripts uv run --script runs the Python in bin/
pnpm JS packages no npm, no yarn

Shell#

Package What it is Why it's here
starship prompt configured in a file, not a GUI
zsh-autosuggestions zsh suggestions fewer keystrokes
zsh-syntax-highlighting zsh highlighting catch a typo before you run it
zoxide smarter cd jump to folders by fragment
direnv per-folder env .envrc pulls secrets per project
lazygit git TUI reviewing a messy tree by hand

Ops and networking#

Package What it is Why it's here
btop process monitor what is eating the machine
tmux terminal multiplexer long jobs that outlive a window
watch repeat a command watching a job change something
nmap port scanner answering "why is this port open"
mtr traceroute + ping diagnosing a flaky link to a box
wget file downloader fetching a file in a script

Media and documents#

Package What it is Why it's here
ffmpeg audio and video transcode, trim, extract audio
imagemagick image conversion resize and convert in scripts
pandoc document conversion markdown to anything
poppler PDF tools text and pages out of PDFs
exiftool metadata reader the camera brain finds photos by metadata
ocrmypdf OCR for PDFs scanned family documents become searchable

Apps#

Cask What it is Why it's here
claude-code Claude Code the operator; installed first, listed for rebuilds
ghostty terminal its config is a text file the brain can own
tailscale-app private network how a manager machine reaches a headless box
bitwarden password manager the human's end of the only secret store
google-chrome browser the human's browser, never the headless one
visual-studio-code editor for the times you read code yourself
obsidian notes the second brain is plain markdown in a repo
claude Claude desktop app the chat window beside the terminal
telegram messaging where tg-send lands
iina media player playing what the camera brain ingests
libreoffice office suite soffice --headless converts generated documents
macparakeet on-device dictation transcripts without anything leaving the Mac
syncthing-app Syncthing menu bar seeing sync state without a terminal
font-jetbrains-mono-nerd-font monospace font the terminal and editor font
qlmarkdown Quick Look: markdown spacebar on a note shows the note
syntax-highlight Quick Look: source spacebar 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#

Package What it is Why it's here
orbstack containers on macOS Docker for Python services and self-hosting
darktable RAW processing the camera brain's edit step
calibre ebook library books and comics in library/
wrangler Cloudflare CLI Workers, D1, R2 and DNS from the terminal
biome JS/TS lint and format one tool instead of ESLint plus Prettier
ruff Python lint and format the Python half of the same rule
pyright Python types type hints checked, not decorative
mermaid-cli diagram renderer mmdc for quick diagrams
ccusage Claude Code usage seeing what all-day sessions cost
Xcode Apple toolchain (via mas) iOS builds; needs an Apple ID in the App Store

The server layer#

Package What it is Why it's here
cloudflared Cloudflare Tunnel exposing 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.

Extension What it is Why it's here
anthropic.claude-code Claude Code in VS Code the same operator, in the editor
ms-vscode-remote.remote-ssh remote editing editing on a headless box
eamodio.gitlens git blame and history who changed this line, and when
ms-python.python Python support one of the two languages
ms-python.vscode-pylance Python language server completions and types
charliermarsh.ruff Ruff in the editor same linter as the command line
biomejs.biome Biome in the editor same formatter as the command line
redhat.vscode-yaml YAML support config and CI files
tamasfe.even-better-toml TOML support pyproject.toml, starship.toml
timonwong.shellcheck ShellCheck in-editor bin/ is bash
yzhang.markdown-all-in-one markdown editing brains and notes are markdown
davidanson.vscode-markdownlint markdown linting keeps the docs consistent
mechatroner.rainbow-csv CSV viewer reading exports without a spreadsheet
usernamehw.errorlens inline errors problems where they happen
editorconfig.editorconfig EditorConfig one indent rule across editors
streetsidesoftware.code-spell-checker spell check the docs are the product here
gruntfuggly.todo-tree TODO index finding 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.

Step What it does
oh-my-zsh the zsh framework, keeping the linked ~/.zshrc
runtimes mise use --global [email protected] node@lts
playwright the pinned Playwright CLI and its bundled Chromium, profiles 700
macparakeet links macparakeet-cli from the app bundle onto PATH
vscode the extensions above
autoupdate the daily brew autoupdate agent (upgrade and cleanup)

Also linked or applied by /setup, not installed: dotfiles/ (zshrc, starship.toml, ghostty.config, gitconfig, gitignore_global, editorconfig) and macos-defaults.sh (keyboard repeat, Finder, Dock, hot corner, screenshots to ~/Pictures/Screenshots, ask for password on wake).

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.

Service Used for Required? Cost Could be replaced by
Claude Max Claude Code itself — the operator required paid subscription nothing; this is Claude Code
GitHub every repo, the SSH key, PRs, Actions required not stated nothing named in the repo
Homebrew packages on every Mac required free nothing named in the repo
Bitwarden the only secret store, read by bw required not stated 1Password, or KeePassXC + Syncthing
Tailscale the tailnet a manager uses to reach a box required for more than one machine not stated a swap invited by CONTRIBUTING
Cloudflare R2 archive, camera cold copy, encrypted resources required to use those folders cheap, no egress fees S3
Cloudflare (Workers, D1, Pages, DNS) shipping projects, domains optional not stated; set a spend alert Vercel; Fly.io or Railway for Python
Telegram bot tg-send — one line when a long job ends required for notifications free nothing named in the repo
Tavily tavily web search optional not stated exa, jina, firecrawl
Exa exa semantic search optional not stated tavily, jina
Firecrawl firecrawl page to markdown; feed full text optional not stated jina, or browse
Jina Reader jina page or search as markdown optional works keyless at a low rate limit firecrawl, browse
Google Cloud OAuth gcal, gmail, gdrive optional, added later not stated nothing named in the repo
PostHog analytics, replay, flags, errors in projects optional free tier: 1M events, 5K recordings, 100K exceptions a month self-hosted Bugsink
Turso SQLite off Cloudflare, embedded replicas optional free plan: 100 databases, 5 GB Cloudflare D1, a plain file, Supabase
Resend transactional email from a project optional not stated nothing named in the repo
Expo EAS mobile builds and submissions optional not stated nothing named in the repo
Mac App Store (Apple ID) Xcode through mas optional, build machines free downloading Xcode yourself

Syncthing is peer-to-peer and needs no account. MacParakeet transcribes on the machine; nothing leaves the Mac. There is no Dropbox 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.

Every value above lives in a Bitwarden item named claude-computer/<service>, listed in docs/SECRETS.md. Losing claude-computer/r2-crypt means losing ~/resources in R2; it cannot be recovered from the bucket.

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.

Machine What it is Role here
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:

Camera — a dumb device: it takes pictures and hands over a card. Claude does everything after the shutter except the creative edit. Card in → camera-ingest copies RAW and video into ~/library/camera/YYYY/YYYY-MM-DD_<shoot>/, renames each file by capture time and frame number, writes SHA256SUMS, adds one exiftool row per file to index.csv, pushes a cold copy to R2, and never deletes anything from the card. From there it finds photos by metadata and darktable ratings, exports with darktable-cli, restores a pruned folder from R2, and regenerates INDEX.md. The brain draws its own line here: Claude doesn't make creative edits and doesn't delete photos — ratings, culling and edits happen in darktable, by hand.

Folder structure#

Top-level folders are containers, not repos — except claude-computer and vault. Repos live one level down. Nothing is ever nested.

~/
  claude-computer/     the fleet brain — a private repo made from the template
  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 — a repo
  archive/             cold storage staging — pushed to R2, then removed
  library/             camera (RAW workflow), books and comics (Calibre)
  resources/<person>/  family key documents — encrypted two-way sync

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#

Path What
CLAUDE.md the fleet brain's operating instructions
install.sh the one-liner that puts the operator on a new Mac
bin/ every script; each answers --help and returns exit codes
lib/common.sh the cc_* helpers and EX_* exit codes every bash script sources
lib/cc.py, lib/google_auth.py the same for the uv run --script scripts; Google OAuth
claude-global/ linked into ~/.claude — global CLAUDE.md, settings, hooks, commands
Brewfile, Brewfile.dev, Brewfile.server packages, layered by role
setup-tools.sh what Homebrew cannot install
vscode-extensions.txt the editor extension list
dotfiles/ shell, prompt, terminal, git — linked by /setup
macos-defaults.sh defaults write for a new Mac
templates/ scaffolds for new apps (web, mobile, cli, desktop) and for the other brains
.githooks/pre-commit the gitleaks scan; enabled with git config core.hooksPath .githooks
tests/ what CI runs beyond ShellCheck, including an install.sh dry run
docs/INSTALL.md the one-line install, and how to read it before you run it
docs/FIRST-PROMPT.md the prompt a new user pastes
docs/DEV-GUIDELINES.md how every project is built
docs/SECRETS.md every Bitwarden item the scripts expect, and how to get each value
docs/FLEET.md index of machines
docs/DECISIONS.md append-only decision log, [host] [date] tagged
docs/TEMPLATE-DECISIONS.md why the template is built this way
docs/machines/ one file per machine, written only by that machine
docs/diagrams/render.py the hand-laid SVGs in the README
UPSTREAM the template's URL, for the fetch-only remote

The second brain#

Obsidian, over a git repo, with Claude doing the filing. Capture is free; filing, linking and retrieval are Claude's job.

vault/
  inbox/        everything lands here — dictation, web clips, quick notes
  daily/        one note per day, drafted from tasks
  notes/        flat. atomic ideas, meetings, decisions. no subfolders
  people/       one note per person who keeps coming up
  projects/     one hub note per brain
  sources/      transcripts, articles, feed digests
  maps/         maps of content, all tasks, weekly reviews
  _templates/   Templater templates

Structure lives in properties, not folders. Every note carries the same frontmatter, and Claude enforces it when it files.

Property What goes in it
type note, person, project, source, transcript, daily, map
created YYYY-MM-DD
tags a list
status active, done, archived, where it applies
people [[links]] to notes in people/
project the hub name
source a url, a book, dictation, clipper, feeds-sync

How things get in#

Capture Route Script or command
A thought, a to-do dictate into inbox/quick.md none — the cheapest capture wins
A meeting record it in MacParakeet transcripts-sync
A file, a URL, a podcast macparakeet-cli transcribe … --no-history none — it stays out of the database
A web page Obsidian Web Clipper, saving to inbox/ none
RSS and newsletters sources/feeds/feeds.txt feeds-sync, daily 06:00

What Claude does with it#

  • /inbox — empties inbox/: classifies, fixes frontmatter, files, links, routes tasks.
  • /transcripts — a five-line summary with decisions and open questions, people linked, action items routed, the raw transcript filed.
  • /today — the daily note, drafted from tasks rather than the calendar.
  • /review — the weekly pass; it empties ## Unassigned first.

Rules that keep it sane#

  • Tasks live with their brain; the vault gets copies. tasks-sync writes read-only copies into maps/tasks.md and each project hub. 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 tasks-sync markers or in notes marked generated. Everything else is yours, and no script overwrites it.
  • ## 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.

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 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). The Web Clipper is a browser extension: install it by hand and point it at inbox/.

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 Bitwarden is locked, 5 missing config or secret.

Script What it does Triggered by
archive-pull# search the R2 archive index and restore a file or folder you, or /retrieve
archive-push# move a folder from ~/archive to R2, verify, rebuild INDEX.md you, or /archive
browse# load a page in Playwright's Chromium: markdown, screenshot or PDF Claude, feeds-sync
camera-ingest# copy a memory card into the camera library, verified, then push to R2 you, when a card goes in
exa# semantic web search, markdown out Claude
feeds-sync# build today's reading digest from RSS and newsletter email schedule, daily 06:00
firecrawl# scrape a URL to clean markdown Claude, feeds-sync
gcal# list and add Google Calendar events Claude
gdrive# search, download, upload and share Google Drive files Claude
gmail# search and read Gmail, read-only scope Claude, feeds-sync
jina# read a URL as markdown, or search, via Jina Reader Claude
map-check# diff installed packages, extensions, launchd jobs and ports against the map schedule daily 09:00, /setup, /review
new-app# scaffold a project, init git, create a private GitHub repo /new-app
resources-sync# two-way encrypted sync of ~/resources with R2 schedule, hourly
schedule# install, remove and list the fleet's launchd jobs you, during /setup
secrets-unlock# unlock Bitwarden once; every wrapper shares the session you, in a terminal, once per login
security-check# check FileVault, firewall, sshd, browse profiles and Tailscale map-check, /setup
tasks-sync# collect every brain's TASKS.md into read-only vault copies SessionStart hook, schedule hourly
tavily# web search, markdown out Claude
tg-send# send one plain-text Telegram line, prefixed with the machine name hooks, map-check, Claude
transcripts-sync# export completed MacParakeet transcriptions into the vault inbox launchd watch on the database, SessionStart hook
vault-setup# create ~/vault from the template and install its three Obsidian plugins /setup, or you
wt# create a git worktree for a branch and open a session in it you

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/.

Command When you'd use it It calls
/setup# a new machine, or the first run of a fresh instance Brewfiles, setup-tools.sh, map-check
/today# start of the day: open or draft today's note from every brain's tasks tasks-sync
/inbox# empty the vault inbox — clean, file, link, route tasks /transcripts, then the vault brain
/transcripts# a meeting finished: summary, people, action items routed transcripts-sync
/review# weekly: what changed, what's stuck, where the map drifted tasks-sync --json, map-check
/new-app# a new project: pick the target, scaffold it, write its brain new-app
/graduate# a project reached production and moves to ~/products git, tasks-sync
/archive# push folders to R2 cold storage and remove the local copy archive-push
/retrieve# find something in the archive and restore it archive-pull
/rotate# a key needs replacing, and everything using it re-tested the wrappers, wrangler, gh
/upstream# a lesson worth sharing becomes a generic PR against the template gh, gitleaks

Hooks#

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

Hook Fires What it does
session-start.sh# SessionStart pulls the repo --rebase --autostash, reports Bitwarden, syncs transcripts and tasks
prompt-submit.sh# UserPromptSubmit notes when the turn started, so the Stop hook can tell a long run
stop.sh# Stop, end of every turn commits and pushes any docs/ change as [host] update …; pings Telegram after 10 minutes
notify.sh# Notification Telegram line when Claude is waiting on you

Permissions come from the same folder. claude-global/settings.json sets defaultMode: auto, puts git push, rm, brew uninstall, rclone, sudo, archive-push, resources-sync and new-app on the ask list, and puts force-push, bw get/list/export, the Keychain commands, .env files, SSH private keys, rclone.conf and the browse profiles on the deny list. Ask prompts even in auto mode; deny blocks in every mode. Neither is a sandbox.

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.

Job When What it does
tasks-sync# hourly refreshes the read-only task copies in the vault
resources-sync# hourly encrypted two-way sync of ~/resources with R2
feeds-sync# daily 06:00 writes today's reading digest into the vault
daily-note# daily 06:30 drafts today's note with claude -p, fenced to ~/vault and six tools
map-check# daily 09:00 drift report; sends Telegram only when there is drift
transcripts-sync# when MacParakeet's database changes exports finished transcriptions to the vault inbox

daily-note is the only job that runs Claude with nobody to answer a prompt, so it is fenced twice: ~/vault is its working directory and the only tree it can edit, and --allowedTools is Read, Edit, Write, Glob, Grep and git status/add/commit. Everything else is refused outright.

A normal day#

  1. 06:00feeds-sync writes the reading digest into vault/sources/feeds/.
  2. 06:30daily-note drafts vault/daily/<today>.md from the task picture, unattended.
  3. You open a session. The SessionStart hook pulls the fleet repo, says whether Bitwarden is unlocked, exports any new transcript, and refreshes the vault's task copies.
  4. /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.
  5. Work. Claude reads the machine file first, uses the bin/ wrappers instead of MCP servers, and asks before anything destructive, credential-touching or billable.
  6. 09:00map-check runs; if the machine and the map disagree, Telegram says so, and fixing it is this session's job.
  7. After a meetingtranscripts-sync drops the transcript in the inbox; /transcripts writes the summary, links the people and routes every action item to an owning brain.
  8. 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.