|
1 | 1 | # Baudbot — Agent Guidelines |
2 | 2 |
|
3 | | -Baudbot is hardened infrastructure for running always-on AI agents. Source is admin-owned; agents run from deployed copies. |
| 3 | +Baudbot is hardened infrastructure for running always-on AI agents. |
4 | 4 |
|
5 | | -## Repo Layout |
| 5 | +Use this file for **repo-wide** guidance. For directory-specific rules, use the nearest nested `AGENTS.md`: |
| 6 | +- [`bin/AGENTS.md`](bin/AGENTS.md) |
| 7 | +- [`pi/extensions/AGENTS.md`](pi/extensions/AGENTS.md) |
| 8 | +- [`slack-bridge/AGENTS.md`](slack-bridge/AGENTS.md) |
6 | 9 |
|
7 | | -``` |
8 | | -bin/ security & operations scripts |
9 | | - baudbot CLI (attach, sessions, update, deploy) |
10 | | - deploy.sh deploys a prepared source tree → agent runtime |
11 | | - update-release.sh temp checkout → git-free /opt release snapshot → deploy |
12 | | - rollback-release.sh rollback to previous or specified /opt release snapshot |
13 | | - security-audit.sh security posture audit |
14 | | - setup-firewall.sh iptables per-UID egress allowlist |
15 | | - baudbot-safe-bash shell command deny list (installed to /usr/local/bin) |
16 | | - baudbot-docker Docker wrapper (blocks privilege escalation) |
17 | | - harden-permissions.sh filesystem hardening (runs on boot) |
18 | | - scan-extensions.mjs extension static analysis |
19 | | - redact-logs.sh secret scrubber for session logs |
20 | | - prune-session-logs.sh retention cleanup for old pi session logs |
21 | | - config.sh interactive secrets/config setup |
22 | | - broker-register.mjs Slack broker workspace registration CLI |
23 | | - doctor.sh system health checks |
24 | | - uninstall.sh clean removal of baudbot |
25 | | - test.sh runs all test suites |
26 | | - baudbot-firewall.service systemd unit for firewall persistence |
27 | | - baudbot.service systemd unit for agent process |
28 | | - ci/ CI integration scripts |
29 | | - droplet.sh ephemeral DigitalOcean droplet lifecycle (create/destroy/ssh) |
30 | | - setup-ubuntu.sh Ubuntu droplet: prereqs + setup + tests |
31 | | - setup-arch.sh Arch Linux droplet: prereqs + setup + tests |
32 | | - lib/ shared shell helpers sourced by CLI/release scripts |
33 | | - shell-common.sh strict mode + shared logging/error/root-check helpers |
34 | | - paths-common.sh shared path constants (bb_init_paths, bb_refresh_release_paths) |
35 | | - release-common.sh shared update/rollback helpers |
36 | | - deploy-common.sh deploy/runtime helper functions |
37 | | - doctor-common.sh doctor status/check formatting helpers |
38 | | - json-common.sh shared JSON field extraction helper (jq) |
39 | | - baudbot-runtime.sh runtime/status/session/attach helper module for bin/baudbot |
40 | | -hooks/ |
41 | | - pre-commit blocks agent from modifying security files in git |
42 | | -pi/ |
43 | | - extensions/ source of truth for pi agent extensions |
44 | | - tool-guard.ts 🔒 tool call interception (blocks dangerous patterns) |
45 | | - tool-guard.test.mjs 🔒 86 tests for tool-guard |
46 | | - heartbeat.ts periodic health check loop |
47 | | - auto-name.ts session naming |
48 | | - control.ts inter-session communication |
49 | | - idle-compact.ts compact context during idle periods (default 25% threshold) |
50 | | - ... |
51 | | - skills/ source of truth for agent skill templates |
52 | | - control-agent/ orchestration agent |
53 | | - HEARTBEAT.md health check checklist (deployed to ~/.pi/agent/) |
54 | | - memory/ seed files for persistent memory |
55 | | - dev-agent/ coding agent |
56 | | - sentry-agent/ monitoring/triage agent |
57 | | - settings.json pi agent settings |
58 | | -slack-bridge/ |
59 | | - bridge.mjs Slack ↔ agent bridge (legacy Socket Mode) |
60 | | - broker-bridge.mjs Slack ↔ agent bridge (broker pull mode — preferred) |
61 | | - security.mjs 🔒 content wrapping, rate limiting, auth |
62 | | - security.test.mjs 🔒 tests for security module |
63 | | -setup.sh one-time system setup (creates user, firewall, etc.) |
64 | | -start.sh agent launcher (deployed to ~/runtime/start.sh) |
65 | | -``` |
66 | | - |
67 | | -🔒 = security-critical files. Protected at runtime (read-only perms + tool-guard blocks writes). |
| 10 | +## How Baudbot works |
68 | 11 |
|
69 | | -See [CONFIGURATION.md](CONFIGURATION.md) for all env vars and how to obtain them. |
| 12 | +Baudbot is a persistent, team-facing coding agent system. It connects to Slack, receives work requests from developers, and autonomously executes coding tasks (branch, code, test, PR, CI) on a Linux server. |
70 | 13 |
|
71 | | -## Architecture: Source / Runtime Separation |
| 14 | +**Runtime model:** A long-running **control agent** stays connected to Slack, triages incoming requests, and delegates work to ephemeral **dev agents** that each run in isolated git worktrees. A **sentry agent** handles on-demand incident triage. All agents run as an unprivileged `baudbot_agent` Unix user. |
72 | 15 |
|
73 | | -Live execution is release/runtime-based (`/opt/baudbot` + `baudbot_agent` runtime). |
74 | | - |
75 | | -Live operations are now release-based under `/opt/baudbot` (git-free): |
76 | | - |
77 | | -``` |
78 | | -/opt/baudbot/ |
79 | | -├── releases/<sha>/ immutable snapshot (no .git) |
80 | | -├── current -> releases/<sha> active release symlink |
81 | | -└── previous -> releases/<sha> previous release symlink (for rollback) |
| 16 | +```text |
| 17 | +Slack |
| 18 | + ↓ |
| 19 | +slack-bridge (broker pull-mode or legacy Socket Mode) |
| 20 | + ↓ |
| 21 | +control-agent (always-on, manages todo/routing/Slack threads) |
| 22 | + ├── dev-agent(s) — ephemeral coding workers in isolated worktrees |
| 23 | + └── sentry-agent — incident triage (Sentry alerts) |
| 24 | + ↓ |
| 25 | +git commits → PRs → CI feedback → thread updates back to Slack |
82 | 26 | ``` |
83 | 27 |
|
84 | | -`baudbot update` flow: |
85 | | -1) clone target ref into `/tmp/baudbot-update.*` |
86 | | -2) run preflight checks in temp checkout |
87 | | -3) publish git-free snapshot to `/opt/baudbot/releases/<sha>` |
88 | | -4) deploy runtime files from snapshot |
89 | | -5) restart + health check |
90 | | -6) atomically switch `/opt/baudbot/current` |
| 28 | +**Deployment model:** Admin-managed source (this repo) is deployed as immutable, git-free release snapshots under `/opt/baudbot`. The agent runtime (`/home/baudbot_agent`) receives deployed extensions, skills, and bridge code. Updates and rollbacks are atomic symlink switches. See `docs/architecture.md` for full details. |
91 | 29 |
|
92 | | -`baudbot rollback previous|<sha>` re-deploys an existing snapshot and flips `current`/`previous` without network access. |
| 30 | +## What this repo contains (high-level) |
93 | 31 |
|
94 | | -Agent runtime layout: |
95 | | -``` |
96 | | -/home/baudbot_agent/ |
97 | | -├── runtime/ |
98 | | -│ ├── start.sh deployed launcher |
99 | | -│ ├── bin/ harden-permissions.sh, redact-logs.sh, prune-session-logs.sh |
100 | | -│ └── slack-bridge/ deployed bridge |
101 | | -├── .pi/agent/ |
102 | | -│ ├── extensions/ deployed extensions |
103 | | -│ ├── skills/ agent-owned (can modify freely) |
104 | | -│ ├── HEARTBEAT.md periodic health check checklist (admin-managed) |
105 | | -│ ├── memory/ persistent agent memory (agent-owned, survives deploys) |
106 | | -│ ├── baudbot-version.json deploy version (git SHA, timestamp) |
107 | | -│ └── baudbot-manifest.json SHA256 hashes of all deployed files |
108 | | -├── workspace/ project repos + git worktrees |
109 | | -└── .config/.env secrets (600 perms) |
110 | | -``` |
| 32 | +- `bin/` — operational shell CLI, deploy/update/rollback, security and health scripts |
| 33 | +- `pi/extensions/` — tool extensions and runtime behaviors deployed into agent runtime |
| 34 | +- `pi/skills/` — agent personas and behavior (`SKILL.md` defines each agent's identity, rules, and tools) |
| 35 | + - `control-agent/` — orchestration/triage persona + persistent memory seeds |
| 36 | + - `dev-agent/` — coding worker persona |
| 37 | + - `sentry-agent/` — incident triage persona |
| 38 | +- `pi/settings.json` — pi agent settings |
| 39 | +- `slack-bridge/` — Slack integration bridges + security module |
| 40 | +- `docs/` — architecture/operations/security documentation |
| 41 | +- `test/` — vitest wrappers for shell scripts, integration, and legacy Node tests |
| 42 | +- `hooks/` — git hooks (security-critical `pre-commit` protecting admin-managed files) |
| 43 | +- `.github/` — CI workflows, PR template, issue templates |
| 44 | +- `.env.schema` — canonical schema for all environment variables (see `CONFIGURATION.md`) |
| 45 | +- `bootstrap.sh`, `setup.sh`, `install.sh`, `start.sh` — bootstrap installer, system setup, interactive install, and runtime launcher |
111 | 46 |
|
112 | | -## Development Workflow |
| 47 | +## Core workflow |
113 | 48 |
|
114 | 49 | ```bash |
115 | | -# First-time install (interactive — handles everything) |
116 | | -sudo ./install.sh |
117 | | - |
118 | | -# Edit source files in this repository checkout |
| 50 | +# JS/TS + shell tests + lint |
| 51 | +npm test |
| 52 | +npm run lint |
119 | 53 |
|
120 | | -# For source-only changes (extensions/skills/bridge), deploy directly: |
| 54 | +# Source-only deploy (extensions/skills/bridge changes) |
121 | 55 | ./bin/deploy.sh |
122 | 56 |
|
123 | | -# For operational updates from git (recommended for live bot): |
| 57 | +# Live operational update/rollback |
124 | 58 | sudo baudbot update |
125 | | - |
126 | | -# Roll back live bot to previous snapshot if needed: |
127 | 59 | sudo baudbot rollback previous |
128 | | - |
129 | | -# Register a server with Slack broker (after OAuth callback) |
130 | | -sudo baudbot broker register --broker-url https://broker.example.com --workspace-id T0123ABCD --registration-token <token> |
131 | | - |
132 | | -# Rotate an API key after setup (prompts hidden input) |
133 | | -sudo baudbot env set ANTHROPIC_API_KEY --restart |
134 | | - |
135 | | -# Optional: use external secret source instead of ~/.baudbot/.env |
136 | | -sudo baudbot env backend set-command 'your-secret-tool export baudbot-prod' |
137 | | -sudo baudbot env sync --restart |
138 | | - |
139 | | -# Launch agent directly (debug/dev) |
140 | | -sudo -u baudbot_agent ~/runtime/start.sh |
141 | | - |
142 | | -# Or in tmux |
143 | | -tmux new-window -n baudbot 'sudo -u baudbot_agent ~/runtime/start.sh' |
144 | 60 | ``` |
145 | 61 |
|
146 | | -## Slack broker pull-mode notes |
147 | | - |
148 | | -- Broker delivery is now pull-based. Registration is callback-free: |
149 | | - - `sudo baudbot broker register --broker-url ... --workspace-id T... --registration-token ...` |
150 | | -- After a successful broker registration, always restart to load new keys: |
151 | | - - `sudo baudbot restart` |
152 | | -- The runtime starts `broker-bridge.mjs` automatically when `SLACK_BROKER_*` vars are present. |
153 | | -- Quick troubleshooting when Slack replies stop: |
154 | | - - `sudo -u baudbot_agent tmux ls` (check `slack-bridge` session exists) |
155 | | - - `sudo baudbot attach --tmux slack-bridge` (bridge logs) |
156 | | - - `sudo journalctl -u baudbot.service -n 200 --no-pager` (startup/runtime errors) |
157 | | -- For local/semi-integration tests that spawn `slack-bridge/broker-bridge.mjs`, keep `libsodium-wrappers-sumo` available from root install (`npm install` at repo root). |
158 | | - |
159 | | -## Running Tests |
160 | | - |
161 | | -```bash |
162 | | -# All tests (unified Vitest runner) |
163 | | -npm test |
164 | | - |
165 | | -# Only JS/TS tests |
166 | | -npm run test:js |
167 | | - |
168 | | -# Only shell/security script tests |
169 | | -npm run test:shell |
170 | | - |
171 | | -# JS/TS coverage |
172 | | -npm run test:coverage |
173 | | - |
174 | | -# Lint (Biome + ShellCheck) |
175 | | -npm run lint |
176 | | -``` |
177 | | - |
178 | | -Add new test files to `vitest.config.mjs` (and shell wrappers under `test/` as needed) — don't scatter test invocations across CI or docs. |
179 | | - |
180 | | -## Conventions |
181 | | - |
182 | | -- Security functions must be pure, testable modules (no side effects, no env vars at module scope). |
183 | | -- All security code must have tests before merging. |
184 | | -- Run `bin/security-audit.sh --deep` after any security-relevant changes. |
185 | | -- Keep shell CLIs thin: move reusable logic to `bin/lib/*.sh`, and source shared helpers (`shell-common.sh`, `paths-common.sh`, `release-common.sh`, `deploy-common.sh`, `doctor-common.sh`) instead of duplicating logging/error/root-check patterns. |
186 | | -- For shell scripts, standardize on `bb_enable_strict_mode` and shared helper functions (`bb_log`, `bb_die`, etc.) rather than ad-hoc wrappers. |
187 | | -- Protected files (`tool-guard.ts`, `security.mjs`, their tests) are deployed read-only. The agent cannot modify them at runtime. |
188 | | -- New integrations get their own subdirectory (e.g. `discord-bridge/`). |
189 | | -- Extensions are deployed from `pi/extensions/` → agent's `~/.pi/agent/extensions/`. |
190 | | -- Skills are deployed from `pi/skills/` → agent's `~/.pi/agent/skills/`. |
191 | | -- Agent commits operational learnings to its own skills dir (not back to source). |
192 | | -- **When changing behavior, update all docs.** Check and update: `README.md`, relevant pages in `docs/`, `CONFIGURATION.md`, skill files (`pi/skills/*/SKILL.md`), and `AGENTS.md`. Inline code examples in docs must match the actual implementation. |
193 | | -- **Prefer distro-agnostic commands, but prioritize reliability.** Scripts should work on both Arch and Ubuntu (and standard Linux), but distro-specific branches are allowed when they improve setup reliability/UX. If you use distro-specific logic, include graceful fallbacks (or clear prereq docs), keep behavior consistent across distros, and add tests. Continue using portable shell patterns (`grep -E`, POSIX-compatible tools) wherever possible. |
194 | | - |
195 | | -## Testing on Droplets |
196 | | - |
197 | | -Use `bin/ci/droplet.sh` to spin up ephemeral DigitalOcean droplets for testing setup, install, or shell changes on real Linux. Requires `DO_API_TOKEN` env var. |
198 | | - |
199 | | -```bash |
200 | | -# Generate a throwaway SSH key |
201 | | -ssh-keygen -t ed25519 -f /tmp/ci_key -N "" -q |
202 | | - |
203 | | -# Create a droplet (Ubuntu or Arch) |
204 | | -eval "$(bin/ci/droplet.sh create my-test ubuntu-24-04-x64 /tmp/ci_key.pub)" |
205 | | -# → sets DROPLET_ID, DROPLET_IP, SSH_KEY_ID |
206 | | - |
207 | | -# Or Arch (custom image): |
208 | | -eval "$(bin/ci/droplet.sh create my-test 217410218 /tmp/ci_key.pub)" |
209 | | - |
210 | | -# Wait for SSH, upload source, run a CI script |
211 | | -bin/ci/droplet.sh wait-ssh "$DROPLET_IP" /tmp/ci_key |
212 | | -tar czf /tmp/baudbot-src.tar.gz --exclude=node_modules --exclude=.git . |
213 | | -scp -i /tmp/ci_key /tmp/baudbot-src.tar.gz "root@$DROPLET_IP:/tmp/" |
214 | | -bin/ci/droplet.sh run "$DROPLET_IP" /tmp/ci_key bin/ci/setup-ubuntu.sh |
215 | | - |
216 | | -# Or SSH in for manual poking |
217 | | -ssh -i /tmp/ci_key "root@$DROPLET_IP" |
218 | | - |
219 | | -# Clean up when done (~$0.003/run) |
220 | | -bin/ci/droplet.sh destroy "$DROPLET_ID" "$SSH_KEY_ID" |
221 | | -``` |
| 62 | +## Non-negotiable guardrails |
222 | 63 |
|
223 | | -Droplets take ~15s to create, ~10s for SSH, ~90s for full setup+tests. Always destroy after — they cost ~$0.003 per run but add up if forgotten. |
| 64 | +**Hard constraints (enforced by pre-commit hook or CI):** |
| 65 | +- Never commit directly to `main`; use feature branches + PRs. |
| 66 | +- Security-critical files are protected by `hooks/pre-commit` — the agent cannot modify them at runtime. |
| 67 | +- Security-sensitive changes MUST include or update tests. |
| 68 | +- Do NOT weaken runtime hardening (permissions, least privilege, egress restrictions). |
224 | 69 |
|
225 | | -The CI scripts (`bin/ci/setup-ubuntu.sh`, `bin/ci/setup-arch.sh`) run the bootstrap flow (`bootstrap.sh` → `baudbot install`) with simulated input, verify the result, then run the full test suite. Use them as-is or SSH in and test manually. |
| 70 | +**Strong defaults:** |
| 71 | +- When behavior changes, update docs in the same PR (`README.md`, `docs/*`, `CONFIGURATION.md`, and relevant `AGENTS.md` files). |
| 72 | +- Prefer distro-agnostic shell; distro-specific branches are acceptable when reliability improves. |
226 | 73 |
|
227 | | -## Security Notes |
| 74 | +## Tests and quality gates |
228 | 75 |
|
229 | | -- `tool-guard.ts` is a policy/guidance layer: it blocks many risky writes/bash patterns and provides safety-interruption reasoning, but it is not a hard sandbox boundary by itself. |
230 | | -- `baudbot-safe-bash` (root-owned, `/usr/local/bin/`) is a second deny-list layer at the shell level; hard containment still comes from OS permissions and runtime hardening. |
231 | | -- The firewall (`setup-firewall.sh`) restricts `baudbot_agent`'s network egress to an allowlist. |
232 | | -- `/proc` is mounted with `hidepid=2` — agent can only see its own processes. |
233 | | -- Secrets in `~/.config/.env` are `600` perms, never committed. |
234 | | -- Session logs are auto-pruned on startup (14-day retention) and auto-redacted for API keys/tokens. |
| 76 | +Before merge, run at minimum: `npm run lint` and `npm test`. |
235 | 77 |
|
236 | | -## Git Workflow |
| 78 | +## Git / PR expectations |
237 | 79 |
|
238 | | -- **Never commit directly to `main`.** All changes go on feature branches with PRs. |
239 | | -- One branch per todo/task. Branch names: `<gh-username>/<description>` (e.g. `youruser/add-uninstall-script`). |
240 | | -- Use `gh pr create` to open PRs (not the GitHub API with tokens). |
241 | | -- Concise, action-oriented commit messages: `security: add rate limiting to bridge API` |
242 | | -- Prefix with area: `security:`, `bridge:`, `deploy:`, `docs:`, `arch:`, `tests:` |
| 80 | +- Use concise commit messages with area prefix (`security:`, `bridge:`, `deploy:`, `docs:`, `tests:`, ...). |
| 81 | +- If a change is scoped to a subdirectory with its own `AGENTS.md`, follow that local file first. |
0 commit comments