Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ Agent runtime layout:
## Development Workflow

```bash
# First-time install (interactive — handles everything)
sudo ~/hornet/install.sh

# Edit source files directly in ~/hornet/

# Deploy to agent runtime
Expand Down Expand Up @@ -116,6 +119,38 @@ Add new test files to `bin/test.sh` — don't scatter test invocations across CI
- **When changing behavior, update all docs.** Check and update: `README.md`, `CONFIGURATION.md`, skill files (`pi/skills/*/SKILL.md`), and `AGENTS.md`. Inline code examples in docs must match the actual implementation.
- **No distro-specific commands.** Scripts must work on both Arch and Ubuntu (and any standard Linux). Use `grep -E` (not `grep -P`), POSIX-compatible tools, and avoid package manager calls (`pacman`, `apt`, etc.). If a package is needed, document it as a prerequisite rather than auto-installing it.

## Testing on Droplets

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.

```bash
# Generate a throwaway SSH key
ssh-keygen -t ed25519 -f /tmp/ci_key -N "" -q

# Create a droplet (Ubuntu or Arch)
eval "$(bin/ci/droplet.sh create my-test ubuntu-24-04-x64 /tmp/ci_key.pub)"
# → sets DROPLET_ID, DROPLET_IP, SSH_KEY_ID

# Or Arch (custom image):
eval "$(bin/ci/droplet.sh create my-test 217410218 /tmp/ci_key.pub)"

# Wait for SSH, upload source, run a CI script
bin/ci/droplet.sh wait-ssh "$DROPLET_IP" /tmp/ci_key
tar czf /tmp/hornet-src.tar.gz --exclude=node_modules --exclude=.git .
scp -i /tmp/ci_key /tmp/hornet-src.tar.gz "root@$DROPLET_IP:/tmp/"
bin/ci/droplet.sh run "$DROPLET_IP" /tmp/ci_key bin/ci/setup-ubuntu.sh

# Or SSH in for manual poking
ssh -i /tmp/ci_key "root@$DROPLET_IP"

# Clean up when done (~$0.003/run)
bin/ci/droplet.sh destroy "$DROPLET_ID" "$SSH_KEY_ID"
```

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.

The CI scripts (`bin/ci/setup-ubuntu.sh`, `bin/ci/setup-arch.sh`) run `install.sh` with simulated input, verify the result, then run the full test suite. Use them as-is or SSH in and test manually.

## Security Notes

- `tool-guard.ts` blocks: writes outside `/home/hornet_agent/`, writes to source repo, writes to protected runtime files, dangerous bash patterns (reverse shells, fork bombs, rm -rf /, etc.), credential exfiltration.
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,21 @@ Agents work on real files in real repos — no sandbox friction. They make real
## Quick Start

```bash
# Clone (as admin — source lives in admin's home, not agent's)
git clone <your-hornet-repo-url> ~/hornet
git clone https://github.com/modem-dev/hornet.git ~/hornet
sudo ~/hornet/install.sh
```

The installer detects your distro, installs dependencies, creates the agent user, sets up the firewall, and walks you through API keys interactively. Takes ~2 minutes.

<details>
<summary>Manual setup (without installer)</summary>

```bash
# Setup (creates user, firewall, permissions — run as root)
sudo bash ~/hornet/setup.sh <admin_username>

# Add secrets
sudo su - hornet_agent -c 'vim ~/.config/.env'
sudo -u hornet_agent vim ~/.config/.env

# Deploy source → agent runtime
~/hornet/bin/deploy.sh
Expand All @@ -49,6 +56,9 @@ sudo su - hornet_agent -c 'vim ~/.config/.env'
sudo -u hornet_agent ~/runtime/start.sh
```

See [CONFIGURATION.md](CONFIGURATION.md) for the full list of secrets and how to obtain them.
</details>

## Configuration

Secrets and configuration live in `~hornet_agent/.config/.env` (not in repo, 600 perms).
Expand Down
29 changes: 22 additions & 7 deletions bin/ci/setup-arch.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/bin/bash
# CI setup script for Arch Linux droplets.
# Runs as root on a fresh droplet. Installs prereqs, uploads source,
# runs setup.sh, and executes the test suite.
# Runs as root on a fresh droplet. Tests the interactive installer,
# then runs the test suite.
#
# Expects: /tmp/hornet-src.tar.gz already uploaded via scp.

set -euo pipefail

echo "=== [Arch] Installing prerequisites ==="
pacman -Syu --noconfirm --needed git curl tmux iptables docker sudo 2>&1 | tail -10
echo "=== [Arch] Installing git (needed to init test repo) ==="
pacman -Sy --noconfirm --needed git sudo 2>&1 | tail -3

echo "=== Preparing source ==="
useradd -m -s /bin/bash hornet_admin
Expand All @@ -18,9 +18,24 @@ tar xzf /tmp/hornet-src.tar.gz
chown -R hornet_admin:hornet_admin /home/hornet_admin/
sudo -u hornet_admin bash -c 'cd ~/hornet && git init -q && git config user.email "ci@test" && git config user.name "CI" && git add -A && git commit -q -m "init"'

echo "=== Running setup.sh ==="
cd /
bash /home/hornet_admin/hornet/setup.sh hornet_admin
echo "=== Running install.sh ==="
# Simulate interactive input: admin user, required secrets, skip optionals, decline launch
printf 'hornet_admin\nsk-test-key\nghp_testtoken\nxoxb-test\nxapp-test\nU01TEST\n\n\n\n\n\nn\n' \
| bash /home/hornet_admin/hornet/install.sh

echo "=== Verifying install ==="
# .env exists with correct permissions
test -f /home/hornet_agent/.config/.env
test "$(stat -c '%a' /home/hornet_agent/.config/.env)" = "600"
test "$(stat -c '%U' /home/hornet_agent/.config/.env)" = "hornet_agent"
# Runtime deployed
test -f /home/hornet_agent/runtime/start.sh
test -d /home/hornet_agent/.pi/agent/extensions
# Required secrets written
grep -q "OPENCODE_ZEN_API_KEY=sk-test-key" /home/hornet_agent/.config/.env
grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/hornet_agent/.config/.env
grep -q "HORNET_SOURCE_DIR=" /home/hornet_agent/.config/.env
echo " ✓ install.sh verification passed"

echo "=== Installing test dependencies ==="
export PATH="/home/hornet_agent/opt/node-v22.14.0-linux-x64/bin:$PATH"
Expand Down
29 changes: 22 additions & 7 deletions bin/ci/setup-ubuntu.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
# CI setup script for Ubuntu droplets.
# Runs as root on a fresh droplet. Installs prereqs, uploads source,
# runs setup.sh, and executes the test suite.
# Runs as root on a fresh droplet. Tests the interactive installer,
# then runs the test suite.
#
# Expects: /tmp/hornet-src.tar.gz already uploaded via scp.

Expand All @@ -17,9 +17,9 @@ for _ in $(seq 1 60); do
sleep 2
done

echo "=== [Ubuntu] Installing prerequisites ==="
echo "=== [Ubuntu] Installing git (needed to init test repo) ==="
apt-get update -qq
apt-get install -y -qq git curl tmux iptables docker.io 2>&1 | tail -3
apt-get install -y -qq git 2>&1 | tail -1

echo "=== Preparing source ==="
useradd -m -s /bin/bash hornet_admin
Expand All @@ -29,9 +29,24 @@ tar xzf /tmp/hornet-src.tar.gz
chown -R hornet_admin:hornet_admin /home/hornet_admin/
sudo -u hornet_admin bash -c 'cd ~/hornet && git init -q && git config user.email "ci@test" && git config user.name "CI" && git add -A && git commit -q -m "init"'

echo "=== Running setup.sh ==="
cd /
bash /home/hornet_admin/hornet/setup.sh hornet_admin
echo "=== Running install.sh ==="
# Simulate interactive input: admin user, required secrets, skip optionals, decline launch
printf 'hornet_admin\nsk-test-key\nghp_testtoken\nxoxb-test\nxapp-test\nU01TEST\n\n\n\n\n\nn\n' \
| bash /home/hornet_admin/hornet/install.sh

echo "=== Verifying install ==="
# .env exists with correct permissions
test -f /home/hornet_agent/.config/.env
test "$(stat -c '%a' /home/hornet_agent/.config/.env)" = "600"
test "$(stat -c '%U' /home/hornet_agent/.config/.env)" = "hornet_agent"
# Runtime deployed
test -f /home/hornet_agent/runtime/start.sh
test -d /home/hornet_agent/.pi/agent/extensions
# Required secrets written
grep -q "OPENCODE_ZEN_API_KEY=sk-test-key" /home/hornet_agent/.config/.env
grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/hornet_agent/.config/.env
grep -q "HORNET_SOURCE_DIR=" /home/hornet_agent/.config/.env
echo " ✓ install.sh verification passed"

echo "=== Installing test dependencies ==="
export PATH="/home/hornet_agent/opt/node-v22.14.0-linux-x64/bin:$PATH"
Expand Down
Loading