Skip to content

Commit 9cb71cf

Browse files
committed
docs: rewrite README — generic agent framework, security-first positioning
1 parent 8ef131d commit 9cb71cf

1 file changed

Lines changed: 105 additions & 128 deletions

File tree

README.md

Lines changed: 105 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,174 +1,151 @@
1-
# Hornet
1+
# 🐝 Hornet
22

3-
Autonomous coding agent running as an isolated Linux user.
3+
**Hardened autonomous agent infrastructure. Careful — you might get stung.**
44

5-
## Architecture
6-
7-
```
8-
hornet_agent (uid)
9-
├── ~/.config/.env # secrets (not in repo)
10-
├── ~/.ssh/ # SSH key for GitHub (not in repo)
11-
├── ~/.pi/agent/
12-
│ ├── settings.json # pi config
13-
│ ├── skills/ → ~/hornet/pi/skills/
14-
│ └── extensions/ → ~/hornet/pi/extensions/
15-
├── ~/hornet/ # this repo
16-
│ ├── start.sh # launch script
17-
│ ├── setup.sh # install from scratch
18-
│ ├── SECURITY.md # trust boundaries & threat model
19-
│ ├── hooks/
20-
│ │ └── pre-commit # self-modification guardrail (installed root-owned)
21-
│ ├── bin/ # security scripts (all protected)
22-
│ │ ├── hornet-docker # Docker wrapper (blocks escalation)
23-
│ │ ├── hornet-safe-bash # Bash wrapper (blocks dangerous commands)
24-
│ │ ├── harden-permissions.sh # Lock down pi state files
25-
│ │ ├── security-audit.sh # 24-check security audit
26-
│ │ ├── scan-extensions.mjs # Cross-pattern static analysis
27-
│ │ ├── setup-firewall.sh # Port-based network lockdown
28-
│ │ └── redact-logs.sh # Secret scrubber for session logs
29-
│ ├── slack-bridge/
30-
│ │ ├── bridge.mjs # Slack ↔ pi bridge (Socket Mode)
31-
│ │ ├── security.mjs # Security functions (protected)
32-
│ │ └── package.json
33-
│ └── pi/
34-
│ ├── settings.json
35-
│ ├── skills/
36-
│ │ ├── control-agent/SKILL.md
37-
│ │ ├── dev-agent/SKILL.md
38-
│ │ └── sentry-agent/SKILL.md
39-
│ └── extensions/
40-
│ ├── tool-guard.ts # Tool call interception (protected)
41-
│ ├── sentry-monitor.ts # Sentry API integration
42-
│ ├── zen-provider.ts # OpenCode Zen LLM provider
43-
│ ├── auto-name.ts # Session naming via env var
44-
│ ├── control.ts, context.ts, files.ts, loop.ts, todos.ts
45-
│ ├── agentmail/, email-monitor/, kernel/
46-
│ └── ...
47-
├── ~/workspace/ # project repos + worktrees
48-
│ ├── modem/ # product app
49-
│ ├── website/ # marketing site
50-
│ └── worktrees/ # git worktrees for dev-agent branches
51-
└── ~/scripts/ # agent-authored operational scripts
52-
```
5+
Hornet is an open framework for running AI coding agents as isolated Linux processes with defense-in-depth security. It assumes the worst: that the agent *will* be prompt-injected, and builds kernel-level walls that hold even when the LLM is fully compromised.
536

54-
## Identity
7+
## Why
558

56-
| | |
57-
|---|---|
58-
| **Unix user** | `hornet_agent` |
59-
| **GitHub** | [hornet-fw](https://github.com/hornet-fw) |
60-
| **Email** | hornet@modem.codeshornet@agentmail.to |
61-
| **LLM** | Claude Opus 4.6 via OpenCode Zen |
62-
| **Pi agent** | control-agent (spawns dev-agent + sentry-agent) |
9+
Every AI agent framework gives the model shell access and hopes for the best. Hornet doesn't hope — it enforces:
6310

64-
## Security
11+
- **OS-level isolation** — dedicated Unix user, no sudo, can't see other processes
12+
- **Kernel-enforced network control** — iptables per-UID egress allowlist
13+
- **Tamper-proof security** — root-owned hooks prevent the agent from weakening its own defenses
14+
- **Dual-layer command blocking** — dangerous shell patterns caught before execution at two independent layers
15+
- **Self-healing** — permissions hardened on every boot, secrets redacted from logs automatically
6516

66-
See [SECURITY.md](SECURITY.md) for full trust boundaries and threat model.
17+
## Security Stack
6718

68-
- Runs as unprivileged `hornet_agent` user — no sudo
69-
- Cannot read admin home directory
70-
- Docker access via wrapper that blocks privilege escalation
71-
- External content (Slack, email) wrapped with security boundaries before reaching LLM
72-
- Prompt injection detection logging in the Slack bridge
73-
- Secrets in `~/.config/.env` (600 perms, not in repo)
74-
- SSH key owner-only (700/600 perms)
75-
- **Self-modification guardrails**: root-owned pre-commit hook + tool-guard rules prevent agent from weakening its own security tooling
19+
| Layer | What | Survives prompt injection? |
20+
|-------|------|---------------------------|
21+
| **iptables egress** | Per-UID firewall chain. Allowlisted ports only, no listeners, no reverse shells. | ✅ Kernel-enforced |
22+
| **Process isolation** | `/proc` mounted `hidepid=2`. Agent can't see other PIDs. | ✅ Kernel-enforced |
23+
| **Self-modification guard** | Root-owned pre-commit hook + tool-guard extension. Agent can't edit security files. | ✅ Root-owned |
24+
| **Shell deny list** | `hornet-safe-bash` blocks rm -rf, reverse shells, fork bombs, curl\|sh. Root-owned. | ✅ Root-owned |
25+
| **Tool call interception** | Pi extension blocks dangerous tool calls before they hit disk or shell. | ✅ Compiled into runtime |
26+
| **Content wrapping** | External messages wrapped with security boundaries + Unicode homoglyph sanitization. | ⚠️ LLM-dependent |
27+
| **Injection detection** | 12 regex patterns flag suspicious content. Log-only. | ⚠️ Detection, not prevention |
28+
| **Filesystem hardening** | 700 dirs, 600 secrets, enforced on every boot. | ✅ Cron/boot script |
29+
| **Log redaction** | Scrubs API keys, tokens, private keys from session logs. | ✅ Boot script |
30+
| **Extension scanning** | Static analysis for exfiltration, obfuscation, crypto-mining patterns. | ✅ Audit-time |
7631

77-
### Security Scripts
32+
**202 tests** across 6 test suites. CI runs all tests + `detect-secrets` on every push.
7833

79-
```bash
80-
# Check security posture
81-
~/hornet/bin/security-audit.sh
82-
83-
# Lock down pi state file permissions (run on startup)
84-
~/hornet/bin/harden-permissions.sh
34+
## Architecture
8535

86-
# Apply port-based network restrictions (run as root)
87-
sudo ~/hornet/bin/setup-firewall.sh
36+
```
37+
hornet_agent (unprivileged uid)
38+
39+
├── ~/hornet/ ← this repo
40+
│ ├── bin/ ← 🔒 security scripts (all root-protected)
41+
│ │ ├── security-audit.sh 24-check security audit
42+
│ │ ├── setup-firewall.sh iptables per-UID lockdown
43+
│ │ ├── hornet-safe-bash shell command deny list
44+
│ │ ├── hornet-docker Docker wrapper (blocks escalation)
45+
│ │ ├── harden-permissions.sh filesystem hardening
46+
│ │ ├── scan-extensions.mjs extension static analysis
47+
│ │ └── redact-logs.sh secret scrubber for logs
48+
│ ├── hooks/pre-commit ← 🔒 self-modification guardrail
49+
│ ├── pi/extensions/
50+
│ │ ├── tool-guard.ts ← 🔒 tool call interception
51+
│ │ └── ... agent-modifiable extensions
52+
│ ├── pi/skills/ agent-modifiable operational knowledge
53+
│ ├── slack-bridge/
54+
│ │ ├── bridge.mjs Slack ↔ agent bridge
55+
│ │ └── security.mjs ← 🔒 content wrapping, rate limiting, auth
56+
│ ├── setup.sh ← 🔒 system setup (creates user, firewall, etc.)
57+
│ └── SECURITY.md ← 🔒 threat model
58+
59+
├── ~/workspace/ project repos + git worktrees
60+
└── ~/.config/.env secrets (600 perms, not in repo)
8861
```
8962

90-
## Setup
63+
🔒 = protected by root-owned pre-commit hook + tool-guard rules. Agent cannot modify.
64+
65+
## Quick Start
9166

9267
```bash
93-
# Clone the repo (need SSH key + known_hosts first)
94-
sudo su - hornet_agent -c 'ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null'
68+
# Clone
9569
sudo su - hornet_agent -c 'git clone git@github.com:modem-dev/hornet.git ~/hornet'
9670

97-
# Run setup (as root)
71+
# Setup (creates user, firewall, permissions — run as root)
9872
sudo bash /home/hornet_agent/hornet/setup.sh <admin_username>
9973

10074
# Add secrets
10175
sudo su - hornet_agent -c 'vim ~/.config/.env'
102-
# GITHUB_TOKEN=...
103-
# OPENCODE_ZEN_API_KEY=...
104-
# AGENTMAIL_API_KEY=...
105-
# KERNEL_API_KEY=...
106-
# HORNET_SECRET=...
107-
# SLACK_BOT_TOKEN=xoxb-...
108-
# SLACK_APP_TOKEN=xapp-...
109-
# SLACK_ALLOWED_USERS=U01234,U56789
110-
# SENTRY_AUTH_TOKEN=...
111-
# HORNET_ALLOWED_EMAILS=you@example.com
112-
```
11376

114-
## Launch
115-
116-
```bash
77+
# Launch
11778
sudo -u hornet_agent /home/hornet_agent/hornet/start.sh
11879
```
11980

120-
This starts the **control-agent**, which automatically spawns a **dev-agent** and **sentry-agent** in tmux sessions, and starts the Slack bridge.
121-
122-
## Monitoring
123-
124-
Hornet uses tmux to manage sub-agent sessions. All commands run as `hornet_agent`.
81+
## Configuration
12582

126-
### List sessions
83+
Secrets live in `~/.config/.env` (not in repo, 600 perms):
12784

12885
```bash
129-
sudo -u hornet_agent tmux ls
86+
GITHUB_TOKEN=...
87+
OPENCODE_ZEN_API_KEY=...
88+
SLACK_BOT_TOKEN=xoxb-...
89+
SLACK_APP_TOKEN=xapp-...
90+
SLACK_ALLOWED_USERS=U01234,U56789 # fail-closed: bridge exits if empty
91+
AGENTMAIL_API_KEY=...
92+
KERNEL_API_KEY=...
93+
SENTRY_AUTH_TOKEN=...
94+
HORNET_SECRET=...
95+
HORNET_ALLOWED_EMAILS=you@example.com
13096
```
13197

132-
### Watch the control-agent
98+
## Operations
13399

134-
The control-agent runs in the foreground terminal where you launched `start.sh`.
100+
```bash
101+
# Check security posture (24 checks + optional deep extension scan)
102+
sudo -u hornet_agent ~/hornet/bin/security-audit.sh --deep
135103

136-
### Watch the dev-agent / sentry-agent
104+
# Harden file permissions (runs on every boot)
105+
sudo -u hornet_agent ~/hornet/bin/harden-permissions.sh
137106

138-
```bash
139-
sudo -u hornet_agent tmux attach -t dev-agent
140-
sudo -u hornet_agent tmux attach -t sentry-agent
141-
```
107+
# Apply network firewall (run as root)
108+
sudo ~/hornet/bin/setup-firewall.sh
142109

143-
Detach without killing: `Ctrl+b` then `d`
110+
# Redact secrets from session logs
111+
sudo -u hornet_agent ~/hornet/bin/redact-logs.sh
144112

145-
### Kill everything
113+
# Monitor agent sessions
114+
sudo -u hornet_agent tmux ls
115+
sudo -u hornet_agent tmux attach -t dev-agent # Ctrl+b d to detach
146116

147-
```bash
117+
# Kill everything
148118
sudo -u hornet_agent pkill -u hornet_agent
119+
120+
# Restart
121+
sudo -u hornet_agent /home/hornet_agent/hornet/start.sh
149122
```
150123

151-
### Restart
124+
## Tests
152125

153126
```bash
154-
sudo -u hornet_agent pkill -u hornet_agent
155-
sudo -u hornet_agent /home/hornet_agent/hornet/start.sh
127+
# All 202 tests
128+
sudo -u hornet_agent bash -c "export PATH=~/opt/node-v22.14.0-linux-x64/bin:\$PATH && \
129+
cd ~/hornet/slack-bridge && node --test security.test.mjs && \
130+
cd ~/hornet/pi/extensions && node --test tool-guard.test.mjs && \
131+
cd ~/hornet/bin && node --test scan-extensions.test.mjs && \
132+
bash hornet-safe-bash.test.sh && bash redact-logs.test.sh && bash security-audit.test.sh"
156133
```
157134

158-
## Updating
135+
## How It Works
159136

160-
Changes to skills, extensions, or config are tracked in this repo. After pulling:
137+
Hornet runs a **control-agent** that spawns sub-agents (dev-agent, sentry-agent) in tmux sessions and starts a Slack bridge. Messages flow:
161138

162-
```bash
163-
# settings.json needs to be copied (not symlinked, pi writes to it)
164-
sudo -u hornet_agent cp ~/hornet/pi/settings.json ~/.pi/agent/settings.json
165-
166-
# Extension deps (if package.json changed)
167-
sudo -u hornet_agent bash -c '
168-
export PATH=~/opt/node-v22.14.0-linux-x64/bin:$PATH
169-
cd ~/hornet/pi/extensions/kernel && npm install
170-
cd ~/hornet/pi/extensions/agentmail && npm install
171-
'
172139
```
140+
Slack → bridge (access control + content wrapping) → pi agent → tools (tool-guard + safe-bash) → workspace
141+
```
142+
143+
Every layer assumes the previous one failed. The bridge wraps content and rate-limits, but tool-guard blocks dangerous commands even if wrapping is bypassed. Safe-bash blocks patterns even if tool-guard is somehow evaded. The firewall blocks exfiltration even if all software layers fail. Defense in depth, all the way down.
144+
145+
## Security Details
146+
147+
See [SECURITY.md](SECURITY.md) for the full threat model and trust boundary diagram.
148+
149+
## License
173150

174-
Skills and extensions are symlinked and update automatically.
151+
MIT

0 commit comments

Comments
 (0)