{"id":47665427,"url":"https://github.com/zdavison/deer","last_synced_at":"2026-04-14T12:01:35.905Z","repository":{"id":342606273,"uuid":"1161174791","full_name":"zdavison/deer","owner":"zdavison","description":"The simplest unattended coding agent orchestrator.","archived":false,"fork":false,"pushed_at":"2026-04-07T11:02:28.000Z","size":9476,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-07T11:02:33.109Z","etag":null,"topics":["ai","claude-code"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zdavison.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-18T20:20:17.000Z","updated_at":"2026-04-07T09:20:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"7341a6a2-2d74-4f5f-a103-2584ec4464e2","html_url":"https://github.com/zdavison/deer","commit_stats":null,"previous_names":["mm-zacharydavison/deer","zdavison/deer"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/zdavison/deer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zdavison%2Fdeer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zdavison%2Fdeer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zdavison%2Fdeer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zdavison%2Fdeer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zdavison","download_url":"https://codeload.github.com/zdavison/deer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zdavison%2Fdeer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31795334,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T11:13:53.975Z","status":"ssl_error","status_checked_at":"2026-04-14T11:13:53.299Z","response_time":153,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","claude-code"],"created_at":"2026-04-02T11:55:18.306Z","updated_at":"2026-04-14T12:01:35.899Z","avatar_url":"https://github.com/zdavison.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🦌 deer / deerbox\n\n`deer` is what I consider the simplest tool for running multiple unattended `claude` instances safely.\n\nIf you want to parallelize `claude` agents, but don't like the complexity of agent orchestrators like [`multiclaude`](https://github.com/dlorenc/multiclaude) and [`claude-squad`](https://github.com/smtg-ai/claude-squad), `deer` may be for you.\n\n![the deer dashboard TUI](assets/demo-dashboard.png)\n\n## Screencast\n\n[![snapshot from the screencast](assets/screencast-cover.png)](https://youtu.be/1hvmO04NFNc)\n\n## Goals\n\n1. Quickly run and work with multiple `claude` instances at once.\n2. Enable running with `--dangerously-skip-permissions` safely.\n3. Use the users Claude Code subscription for everything.\n4. Feel like `claude`.\n\n---\n\n## How it works\n\n1. Launch `deer`.\n2. Send prompts (each prompt is a worktree and agent isolated from filesystem and network).\n3. Monitor agents and attach into them if necessary.\n4. Press `p` to open a PR when finished.\n\n---\n\n## Installation\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/zdavison/deer/main/install.sh | bash\n```\n\nTo install a specific version:\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/zdavison/deer/main/install.sh | bash -s -- --version 0.8.1\n```\n\n### Supported platforms\n\n| OS    | Arch  |\n|-------|-------|\n| macOS | x64, arm64 |\n| Linux | x64, arm64 |\n\n---\n\n## Authentication\n\ndeer uses your Claude credentials to power the agent. It checks for credentials in this order:\n\n1. `CLAUDE_CODE_OAUTH_TOKEN` environment variable\n2. `~/.claude/agent-oauth-token` file (plain text token)\n3. macOS Keychain (automatically extracted from Claude Code's stored credentials)\n4. `ANTHROPIC_API_KEY` environment variable (fallback — API key)\n\nIf you have Claude Code installed and logged in, deer will use your subscription automatically on macOS with no extra setup.\n\nSubscriptions are prioritized over API keys, so if you have both setup, `deer` will use your subscription.\n\n---\n\n## Usage\n\n```sh\n# Run from inside a git repo\ncd your-project\ndeer\n```\n\nIf you just want the sandboxing part of `deer`, without the TUI, you can use `deerbox`:\n\n```sh\ncd your-project\ndeerbox\n```\n\nAfter Claude exits, `deerbox` prompts you with a menu of actions:\n\n| Key | Action |\n|-----|--------|\n| `p` | Create a pull request (or update an existing one if `--from` was used) |\n| `k` | Keep the worktree *(default)* |\n| `s` | Open a shell in the worktree |\n| `m` | Merge directly into your original branch (shown when applicable) |\n| `d` | Discard — remove the worktree and changes |\n\nBy default the worktree is cleaned up when you're done. The `m` option merges the session branch into the branch you were on when you invoked `deerbox`, without creating a PR.\n\n### deerbox options\n\n| Flag                        | Short | Description                                          |\n|-----------------------------|-------|------------------------------------------------------|\n| `--model \u003cmodel\u003e`           | `-m`  | Claude model to use                                  |\n| `--base-branch \u003cbranch\u003e`    | `-b`  | Branch to base the worktree on                       |\n| `--from \u003cbranch-or-PR\u003e`     | `-f`  | Continue work on an existing branch or PR            |\n| `--keep`                    | `-k`  | Keep the worktree after Claude exits                 |\n\n### Reviewing env var access\n\nOn every run, `deer`/`deerbox` detect environment variables that look like secrets.\n\n```\n  ⚠  Risky environment variables detected\n  ─────────────────────────────────────────────────────────────────\n  These env vars may contain secrets. Select which to allow in the\n  sandbox — unchecked vars will be blocked. Your choice is remembered.\n\n    [ ] GITHUB_TOKEN          (token)    ghp...\n  ▶ [ ] AWS_SECRET_ACCESS_KEY (key)      AKI...\n    [ ] DATABASE_PASSWORD     (password) hun...\n\n  ↑/↓ navigate  space toggle  enter confirm   unchecked = blocked\n```\n\nYour choices are saved for future runs.\n\nIf any new env vars are added that you haven't reviewed, you'll see this UI again.\n\nTo show this UI on demand at any time:\n\n```sh\ndeer env\n# or\ndeerbox env\n```\n\nThis re-runs the review over all currently-detected risky vars, with your previous choices pre-filled so you can adjust them.\n\n### `--from`: continuing work on an existing branch or PR\n\n`--from` lets you run `deerbox` against a branch that already exists, rather than starting fresh from the base branch. This is useful for iterating on a PR — for example, addressing review comments.\n\n```sh\n# Continue work on an existing branch\ndeerbox --from feature/my-branch \"add unit tests\"\n\n# Address review comments on a PR (by number or URL)\ndeerbox --from 42 \"address the review comments\"\ndeerbox --from https://github.com/owner/repo/pull/42 \"address the review comments\"\n```\n\n`--from` accepts:\n- A **branch name** — checks out that branch; if an open PR exists for it, `deerbox` will offer to update it when done\n- A **PR number** — fetches the PR's head branch and base branch automatically\n- A **GitHub PR URL** — same as a PR number\n\nWhen `--from` is used, only commits made during the session are considered when detecting changes and generating PR metadata.\n\n---\n\n### Dashboard\n\n#### Keyboard shortcuts\n\n**Input mode** (default — prompt bar is active):\n\n| Key | Action |\n|-----|--------|\n| `Enter` | Submit prompt and launch agent |\n| `↑` / `↓` | Navigate prompt history |\n| `Tab` | Switch focus to agent list |\n\n**Agent list mode** (press `Tab` from input to enter):\n\n| Key | Action |\n|-----|--------|\n| `Tab` | Switch focus back to input |\n| `j` / `↓` | Select next agent |\n| `k` / `↑` | Select previous agent |\n| `/` | Fuzzy-search agents |\n| `Enter` | Attach to agent's tmux session |\n| `x` | Kill running agent |\n| `r` | Retry (re-run agent from scratch) |\n| `p` | Create PR (or open PR if one exists) |\n| `u` | Update existing PR |\n| `s` | Open a shell in the agent's worktree |\n| `l` | Toggle log detail panel |\n| `c` | Copy logs to clipboard (when log panel open) |\n| `v` | Toggle verbose log mode (when log panel open) |\n| `Backspace` | Delete agent entry |\n| `q` | Quit (confirms if agents are still running) |\n\n**Search mode** (press `/` from agent list):\n\n| Key | Action |\n|-----|--------|\n| `j` / `↓` | Next match |\n| `k` / `↑` | Previous match |\n| `Enter` | Select highlighted match |\n| `Esc` | Cancel search |\n\n\u003e Actions that require confirmation (kill, delete with uncommitted work, retry while running) prompt `(y/n)` before executing.\n\n### Attaching to a running agent\n\nEach task runs in a named tmux session. You can attach directly to watch the agent in real time by pressing `Enter` while the agent is selected.\n\nWhile attached, a `tmux` status bar is displayed with basic instructions on how to detach (`Ctrl+b`, `d`).\n\n![the deer tmux status bar](assets/deer-status-bar.png)\n\n---\n\n## Language\n\nThe dashboard UI and generated PR content can be displayed in multiple languages:\n\n| Language | `--lang=` value | LLM-translated |\n|----------|----------------|:--------------:|\n| English | *(default)* | |\n| Japanese (日本語) | `ja` | ✓ |\n| Chinese Simplified (简体中文) | `zh` | ✓ |\n| Korean (한국어) | `ko` | ✓ |\n| Russian (русский) | `ru` | ✓ |\n\n```sh\ndeer --lang=zh\n```\n\nLanguage is detected in this order (first match wins):\n\n1. `--lang=\u003ccode\u003e` CLI flag\n2. `CLAUDE_CODE_LOCALE` environment variable (e.g. `CLAUDE_CODE_LOCALE=zh`)\n3. System `LANG` environment variable (e.g. `LANG=zh_CN.UTF-8`)\n4. Default: English\n\nSetting a non-English language also instructs the agent to write PR titles and descriptions in that language. Branch names remain short kebab-case ASCII English regardless of the selected language.\n\nLLM-translated languages may contain errors. PRs to improve translations are welcome — see [`src/i18n.ts`](src/i18n.ts).\n\n---\n\n## Configuration\n\nConfiguration is layered. Later sources override earlier ones:\n\n1. Built-in defaults\n2. `~/.config/deer/config.toml` — global config\n3. `deer.toml` in your repo root — repo-local config\n4. CLI flags\n\n### Global config (`~/.config/deer/config.toml`)\n\n```toml\n[defaults]\nbase_branch = \"main\"       # default base branch for PRs\ntimeout_ms = 1800000       # agent timeout in ms (default: 30 minutes)\nsetup_command = \"\"         # command to run inside the worktree before the agent starts\n\n[network]\n# Replaces the built-in allowlist entirely (see repo-local allowlist_extra to extend it)\nallowlist = [\n  \"api.anthropic.com\",\n  \"registry.npmjs.org\",\n  # ...\n]\n\n[sandbox]\nruntime = \"srt\"            # ths is the only runtime for now\nenv_passthrough = []       # host env vars to forward into the sandbox\n```\n\n### Repo-local config (`deer.toml`)\n\nPlace this in your repo root — it is safe to commit.\n\nYou only need this if the defaults are not sufficient for you.\n\n```toml\n# Override the base branch for this repo\nbase_branch = \"master\"\n\n# Run a setup command inside the worktree before the agent starts\nsetup_command = \"pnpm install\"\n\n# Extend the network allowlist (merged with global allowlist)\n[network]\nallowlist_extra = [\"npm.pkg.github.com\"]\n\n# Forward additional host env vars into the sandbox\n[sandbox]\nenv_passthrough_extra = [\"NODE_ENV\", \"MY_VAR\"]\n\n# Inject extra credentials via the host-side auth proxy.\n# The sandbox never sees the real token — the proxy injects it as an auth header.\n# [[sandbox.proxy_credentials_extra]]\n# domain = \"your-registry.example.com\"\n# target = \"https://your-registry.example.com\"\n# [sandbox.proxy_credentials_extra.hostEnv]\n# key = \"MY_REGISTRY_TOKEN\"\n# [sandbox.proxy_credentials_extra.headerTemplate]\n# authorization = \"Bearer ${value}\"\n# [sandbox.proxy_credentials_extra.sandboxEnv]\n# key = \"NPM_CONFIG_REGISTRY\"\n# value = \"http://your-registry.example.com\"\n```\n\nSee `deer.toml.example` for a full annotated example.\n\n---\n\n## Security model\n\n`deer` runs each agent in an isolated sandbox using the [Anthropic Sandbox Runtime (SRT)](https://github.com/anthropic-ai/sandbox-runtime):\n\n- **Filesystem**: the agent can only write to its git worktree; the rest of the filesystem is read-only or inaccessible.\n- **Network**: outbound traffic is filtered through a domain allowlist; only explicitly permitted domains are reachable.\n- **Credentials**: API keys and OAuth tokens never enter the sandbox — a host-side MITM proxy intercepts requests to credentialed domains and injects auth headers transparently. By default this applies to `claude` keys/OAuth tokens only, but you can add additional ones if necessary.\n- **Environment**: on every run, deer scans your environment for vars that look like secrets (API keys, tokens, passwords, etc.). If any new unreviewed vars are detected, you're prompted to choose which to allow in the sandbox. Your choices are saved to `~/.local/share/deer/env-policy.json` and applied to every session. Previously reviewed vars won't trigger the prompt again unless new ones appear. You can revisit all decisions at any time with `deer env` or `deerbox env`. Vars managed by the auth proxy (`ANTHROPIC_API_KEY`, `CLAUDE_CODE_OAUTH_TOKEN`) are excluded from this check since they never reach the sandbox in plaintext regardless.\n\n---\n\n## How PRs are created\n\nPress `p` on an idle task to create a pull request.\n\nThis will generate a branch name, PR title, and PR description that describes the work done and push it to the repo.\n\nYour PR template (`.github/PULL_REQUEST_TEMPLATE.md`) is conformed to automatically.\n\n---\n\n## Contributing\n\n```sh\nbun install\nbun test\nbun dev\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzdavison%2Fdeer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzdavison%2Fdeer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzdavison%2Fdeer/lists"}