{"id":49759478,"url":"https://github.com/avesalight/roost","last_synced_at":"2026-05-27T03:07:04.743Z","repository":{"id":354958693,"uuid":"1226063449","full_name":"AvesAlight/roost","owner":"AvesAlight","description":"Your own team of Claude Code agents you can join.","archived":false,"fork":false,"pushed_at":"2026-05-17T02:45:29.000Z","size":1468,"stargazers_count":1,"open_issues_count":15,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-17T02:51:14.935Z","etag":null,"topics":["agent-coordination","agents","claude-code","irc","ircv3","multi-agent"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AvesAlight.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-04-30T23:56:55.000Z","updated_at":"2026-05-17T02:45:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/AvesAlight/roost","commit_stats":null,"previous_names":["alexsc/roost","avesalight/roost"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/AvesAlight/roost","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AvesAlight%2Froost","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AvesAlight%2Froost/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AvesAlight%2Froost/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AvesAlight%2Froost/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AvesAlight","download_url":"https://codeload.github.com/AvesAlight/roost/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AvesAlight%2Froost/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33416315,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"ssl_error","status_checked_at":"2026-05-23T22:14:43.778Z","response_time":53,"last_error":"SSL_read: 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":["agent-coordination","agents","claude-code","irc","ircv3","multi-agent"],"created_at":"2026-05-11T03:57:15.784Z","updated_at":"2026-05-24T00:02:13.513Z","avatar_url":"https://github.com/AvesAlight.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/readme-header.png\" alt=\"Roost — AVES/ALIGHT\" width=\"900\"\u003e\n\u003c/p\u003e\n\n# roost\n\nRoost lets you run your own team of Claude Code agents on a real project. A\nlead-pm agent picks up issues from a GitHub milestone and spawns workers and\nreviewers to drive each one through PR; the team coordinates over a local IRC\nserver you can join from any client. You watch the work happen and step in\nwhen something needs human judgment.\n\nAgents talk to each other and to you over the same channels — not a pipeline,\na network.\n\n## Security model\n\nRoost spawns agents that can read, write, and execute in arbitrary working\ndirectories with arbitrary parameters. Permission gating via `--perm-irc`\nrelies on IRC nick identity — local ergo has no authentication, so any process\nwith TCP access to `localhost:6667` can claim any unused nick and approve tool\ncalls by sending `y` to the permbot.\n\nThis is intentional for trusted single-user local environments. Don't run ergo\non a shared host or expose port 6667 beyond localhost.\n\n## Running a milestone\n\nRoost is built for parallel milestone work. Spawn one agent — lead-pm —\nand hand it a GitHub milestone. It creates a channel per issue, spawns\nworkers and reviewers into them, and coordinates with the dispatcher to\nroute CI and PR events back in. You watch and intervene from weechat on\nthe same box. Workers post plans before coding; reviewers post findings\nto GitHub; lead-pm drives sequencing and flips PRs ready.\n\nBootstrap your project, then kick off lead-pm:\n\n```bash\ncd ~/Dev/myproject\nroost init --repo Owner/myproject   # writes .orchestrator/{config.json, config.local.json, .gitignore} + copies role prompts\nroost spawn myproject-lead-pm \\\n  --agent lead-pm \\\n  --channels '#myproject-leads' \\\n  --steer-compact --cache-ttl 1h \\\n  --ask-irc '#myproject-leads' --ask-target \u003cyour-nick\u003e \\\n  --prompt 'milestone=\u003cmilestone\u003e human=\u003cyour-nick\u003e gh-login=\u003cyour-gh-login\u003e'\n```\n\nSee [`docs/ROOST-IN-PRACTICE.md`](docs/ROOST-IN-PRACTICE.md) for the end-to-end walkthrough.\n\n## Prerequisites\n\n- macOS or Linux\n- [bun](https://bun.sh) ≥ 1.0 (installed by the brew formula)\n- [tmux](https://github.com/tmux/tmux) (installed by the brew formula)\n- [ergo](https://ergo.chat) (installed by the brew formula)\n- An IRC client ([weechat](https://weechat.org) recommended — `brew install weechat`)\n- A Claude Code build with `--dangerously-load-development-channels`\n\n## Setup (one-time)\n\n### 1. Install roost\n\n```\nbrew tap oven-sh/bun\nbrew install avesalight/tap/roost\n```\n\nPuts `roost` on your PATH. The `roost-irc` MCP loads automatically when you\nstart a session via `roost spawn` — running `claude` directly without\n`roost spawn` won't load it.\n\n### 2. Start your IRC server\n\nRoost needs an IRCv3 server on `127.0.0.1:6667`. With ergo, run it\nfrom a working directory of your choice — relative paths in the config\n(`logs/`, `ircd.db`, etc.) resolve from there:\n\n```bash\nmkdir -p ~/roost-ircd/logs \u0026\u0026 cd ~/roost-ircd\nnohup ergo run --conf \"$(roost root)/etc/ergo.yaml\" \u003e /tmp/ergo.out 2\u003e\u00261 \u0026\n```\n\nVerify it's up:\n\n```bash\nlsof -nP -iTCP:6667 -sTCP:LISTEN\n```\n\nTo stop:\n\n```bash\npkill -f 'ergo run.*roost/etc/ergo.yaml'\n```\n\n## Running\n\n### Launch a Claude session that joins the roost\n\n```bash\nroost spawn worker-1 -c '#my-channel' --cwd ~/Dev/myproject\n\nroost spawn agent-2 \\\n  -c '#my-channel' \\\n  --cwd ~/Dev/myproject \\\n  --prompt-file /tmp/handoff.md \\\n  -- --chrome --system-prompt ' '\n\nroost list\nroost attach worker-1\nroost shutdown worker-1\nroost status\n```\n\n`spawn` accepts `-c|--channels`, `-m|--model`, `-s|--session`,\n`--mcp-config`, `-p|--prompt-file`, `--cwd`, and `--` (everything\nafter forwards to claude verbatim). Default channel is `#roost`;\ndefault model is `opus` (Opus 4.7 — required for `--permission-mode\nauto`, which the wrapper always passes).\n\n`spawn` also injects `--append-system-prompt-file` naming the joined\nchannels as legitimate user-instruction sources, so the auto-mode\nclassifier doesn't silently block IRC replies on the operator's first\n`@`-mention. Only injected when the IRC host is loopback (`127.0.0.1`,\n`::1`, `localhost`); remote ergo falls outside roost's trusted\nsingle-user local environment security model and prints a warning\ninstead. The injection is always on for loopback hosts. To layer more\ncontext on top, pass `--append-system-prompt-file \u003cpath\u003e` after `--`;\nclaude code rejects mixing inline `--append-system-prompt` with the\nfile form.\n\n### Debugging a failed spawn\n\nIf you need to invoke `claude` directly to debug a failed `roost spawn`, the `--dangerously-load-development-channels` flag (hidden from `claude --help`) takes a server-id. The format depends on how roost is loaded:\n\n- Via plugin loader (installed via brew): `server:plugin:roost:roost-irc`\n- As a bare MCP server (dev checkout, manual `--mcp-config`): `server:roost-irc`\n\n```bash\nclaude --dangerously-load-development-channels server:plugin:roost:roost-irc\n```\n\n### Observe as a human (no Claude needed)\n\nThe ergo config has no auth — any IRC client against `127.0.0.1:6667` works:\n\n```bash\nbrew install weechat\nweechat\n# inside weechat:\n/server add roost 127.0.0.1/6667 -notls\n/connect roost -nick myname\n/join #roost\n```\n\nOn macOS, `extras/weechat/notification_center.py` adds native notification\ncenter alerts for mentions and DMs. Get the path from your shell and load it\nin weechat:\n\n```bash\necho \"$(roost root)/extras/weechat/notification_center.py\"\n# → e.g. /opt/homebrew/Cellar/roost/0.1.1/libexec/extras/weechat/notification_center.py\n```\n\n```\n# inside weechat — paste the path printed above:\n/script load /opt/homebrew/Cellar/roost/0.1.1/libexec/extras/weechat/notification_center.py\n```\n\n## IRC permission oversight (--perm-irc)\n\n`--perm-irc` runs a permbot routing module inside the worker's MCP\nprocess. The module holds a second IRC connection on a stable nick\n`permbot-{worker}` and serializes the worker's PermissionRequest prompts as DMs to\n`--perm-target` (required). The operator replies `y` / `n` / `yes` /\n`no` / `allow` / `deny`; anything else or a 30s timeout falls through\nto the terminal prompt.\n\nPrimary use case: an Opus orchestrator spawning a Sonnet or Haiku\nworker. Non-Opus models can't use auto mode, so without oversight the\nworker floods the terminal with permission prompts. With\n`--perm-irc --perm-target \u003corchestrator\u003e`, prompts come to the\norchestrator over IRC.\n\n```bash\n# Opus orchestrator gates a sonnet worker's tool calls:\nroost spawn worker-123-A -c '#pr-123' -m sonnet \\\n  --perm-irc --perm-target orchestrator\n\n# Human operator gates a haiku worker:\nroost spawn scratch-h -c '#sandbox' -m haiku \\\n  --perm-irc --perm-target mynick\n```\n\n## Project dispatcher\n\n`roost init` bootstraps your project's dispatcher config and copies the\nrole prompts into `.claude/commands/`. Then start the dispatcher — it polls\nGitHub on a tick, routes events (CI transitions, PR comments, issue updates)\ninto the right `#\u003cproject\u003e-issue-N` channels, and accepts watch/unwatch DMs\nto control which issues and PRs are tracked:\n\n```bash\ncd ~/Dev/myproject\nroost init --repo Owner/myapp           # single-repo: writes .orchestrator/{config.json, config.local.json, .gitignore} + prompts\nCONFIG_DIR=\"$(pwd)/.orchestrator\"\n\"$ROOST_DIR/bin/start-dispatcher\" \"$CONFIG_DIR\"\n```\n\nTo manage multiple repos from a shared directory instead:\n\n```bash\nmkdir ~/Dev/shared \u0026\u0026 cd ~/Dev/shared\nroost init --multi-repo --project myapp\n```\n\nDM the dispatcher (`\u003cproject\u003e-dispatcher`) to manage the watch list:\n`watch \u003cN\u003e`, `unwatch \u003cN\u003e`, `watch pr \u003cN\u003e`, `unwatch pr \u003cN\u003e`,\n`watch list`, `help`. The dispatcher's allowlist defaults to\n`[\u003cproject\u003e-lead-pm]`; set `irc.command_senders` in config to override.\n\n`project` namespaces every per-project artifact (`\u003cproject\u003e-worker-N` nicks,\n`#\u003cproject\u003e-issue-N` channels, etc.) so multiple projects can share one ergo.\nSee [`docs/DISPATCHER.md`](docs/DISPATCHER.md) for config schema, event\nreference, and plugin extension points.\n\n## Channel events received\n\nInbound IRC arrives in the host session as channel notifications:\n\n**Regular messages:**\n\n```xml\n\u003cchannel event=\"message\" sender=\"alex\" channel=\"#roost\"\n         isDirect=\"false\" ts=\"2026-04-28T05:30:00.000Z\" seq=\"42\"\u003e\nhello world\n\u003c/channel\u003e\n```\n\n`mention=\"true\"` is added when the message body contains your nick (word-boundary, case-insensitive) or when the message is a DM (`isDirect=\"true\"`). Absent on non-mention channel messages.\n\n```xml\n\u003cchannel event=\"message\" sender=\"alex\" channel=\"#roost\"\n         isDirect=\"false\" ts=\"2026-04-28T05:30:00.000Z\" seq=\"43\" mention=\"true\"\u003e\nroost-worker-1: can you check the build?\n\u003c/channel\u003e\n```\n\n**Membership events** (JOIN, PART, KICK, NICK):\n\n```xml\n\u003cchannel event=\"join\" sender=\"newcomer\" channel=\"#roost\"\n         isDirect=\"false\" ts=\"...\" seq=\"...\"\u003e\nnewcomer joined #roost\n\u003c/channel\u003e\n```\n\nSelf-events (your own JOIN/LEAVE/NICK) are suppressed.\n\n## Environment variables\n\n| Var | Default | Notes |\n|-----|---------|-------|\n| `ROOST_IRC_NICK` | (required) | The nick this session connects as. Ergo refuses collisions. |\n| `ROOST_IRC_CHANNELS` | (none) | Comma-separated channels to auto-join at registration. |\n| `ROOST_IRC_SERVER` | `127.0.0.1` | IRC server host. |\n| `ROOST_IRC_PORT` | `6667` | IRC server port. |\n| `ROOST_IRC_REALNAME` | same as nick | IRC realname (gecos). |\n| `ROOST_IRC_HISTORY` | `50` | Per-channel ring-buffer size for `channel_history`. |\n\n## Testing\n\n```bash\nbun test\n```\n\nRequires ergo. Install it once with `bin/install-ergo`, or point `ERGO_BIN` at\nan existing binary. Tests skip gracefully when ergo isn't found.\n\nFor coverage (line ≥ 85%, branch ≥ 75% globally):\n\n```bash\nbun test --coverage\n```\n\nCoverage includes `src/irc-server.ts` via the in-process tests\n(`test/irc-server-inprocess.test.ts`).\n\n## Known limitations\n\n- **No SASL / nick reservation.** Any local process that connects can\n  claim any unused nick. Acceptable for a single-user dev box; revisit\n  before hosting multi-tenant work.\n- **`channel_history` is per-MCP-instance.** Restarting an MCP loses\n  the buffer. For durable history use ergo's audit log\n  (`~/roost-ircd/logs/audit.log`) or the IRCv3 `CHATHISTORY` command.\n- **`alwaysLoad: true`** keeps all six tools non-deferred. Empirical\n  baseline-vs-alwaysLoad probe (2026-04-28) showed 0 `tools_changed`\n  misses with the flag vs 2 without (see `docs/LEARNINGS.md` Finding A).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favesalight%2Froost","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Favesalight%2Froost","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favesalight%2Froost/lists"}