Skip to content

Commit 8a914c8

Browse files
authored
arch: baudbot CLI dispatcher, systemd unit, and doctor command (#22)
1 parent 15787f3 commit 8a914c8

10 files changed

Lines changed: 583 additions & 35 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727

2828
- name: ShellCheck
2929
run: |
30-
find bin/ setup.sh start.sh -type f \( -name '*.sh' -o -name 'baudbot-safe-bash' -o -name 'baudbot-docker' \) \
30+
find bin/ setup.sh start.sh install.sh -type f \( -name '*.sh' -o -name 'baudbot-safe-bash' -o -name 'baudbot-docker' -o -name 'baudbot' \) \
3131
| xargs shellcheck -s bash -S warning
3232
3333
test:

bin/baudbot

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#!/bin/bash
2+
# Baudbot CLI dispatcher
3+
# Routes subcommands to internal scripts. Installed as /usr/local/bin/baudbot.
4+
#
5+
# Usage: baudbot <command> [options]
6+
7+
set -euo pipefail
8+
9+
# Find the baudbot source root. Resolution order:
10+
# 1. BAUDBOT_ROOT env var (explicit override)
11+
# 2. Resolve from this script's real location (follow symlinks, then ../)
12+
if [ -z "${BAUDBOT_ROOT:-}" ]; then
13+
SCRIPT="$0"
14+
# Follow symlinks to find the real script location
15+
while [ -L "$SCRIPT" ]; do
16+
DIR="$(cd "$(dirname "$SCRIPT")" && pwd)"
17+
SCRIPT="$(readlink "$SCRIPT")"
18+
# Handle relative symlinks
19+
[[ "$SCRIPT" != /* ]] && SCRIPT="$DIR/$SCRIPT"
20+
done
21+
BAUDBOT_ROOT="$(cd "$(dirname "$SCRIPT")/.." && pwd)"
22+
fi
23+
24+
# Colors (disabled if not a terminal)
25+
if [ -t 1 ]; then
26+
BOLD='\033[1m'
27+
RESET='\033[0m'
28+
else
29+
BOLD='' RESET=''
30+
fi
31+
32+
version() {
33+
if [ -f "$BAUDBOT_ROOT/package.json" ]; then
34+
grep '"version"' "$BAUDBOT_ROOT/package.json" | head -1 | sed 's/.*: *"\(.*\)".*/\1/'
35+
else
36+
echo "unknown"
37+
fi
38+
}
39+
40+
usage() {
41+
echo -e "${BOLD}baudbot${RESET} — hardened infrastructure for always-on AI agents"
42+
echo ""
43+
echo -e "${BOLD}Usage:${RESET} baudbot <command> [options]"
44+
echo ""
45+
echo -e "${BOLD}Lifecycle:${RESET}"
46+
echo " start Start the agent (systemd, or --direct for foreground)"
47+
echo " stop Stop the agent"
48+
echo " restart Restart the agent"
49+
echo " status Show agent status"
50+
echo " logs Tail agent logs"
51+
echo ""
52+
echo -e "${BOLD}Setup:${RESET}"
53+
echo " setup One-time system setup (user, deps, firewall, systemd)"
54+
echo " config Interactive secrets and config setup"
55+
echo " deploy Deploy source + config to agent runtime"
56+
echo ""
57+
echo -e "${BOLD}Operations:${RESET}"
58+
echo " doctor Health check (perms, firewall, secrets, deps)"
59+
echo " audit Security posture audit"
60+
echo " test Run test suite"
61+
echo " update Pull latest and redeploy"
62+
echo " uninstall Remove everything"
63+
echo ""
64+
echo -e "${BOLD}Options:${RESET}"
65+
echo " --version Show version"
66+
echo " --help, -h Show this help"
67+
}
68+
69+
require_root() {
70+
if [ "$(id -u)" -ne 0 ]; then
71+
echo "❌ baudbot $1 requires root. Run: sudo baudbot $1"
72+
exit 1
73+
fi
74+
}
75+
76+
# Detect systemd
77+
has_systemd() {
78+
command -v systemctl &>/dev/null && [ -d /run/systemd/system ]
79+
}
80+
81+
case "${1:-}" in
82+
start)
83+
shift
84+
if [ "${1:-}" = "--direct" ]; then
85+
# Foreground mode: run start.sh directly (for dev/CI/debugging)
86+
shift
87+
require_root "start --direct"
88+
exec sudo -u baudbot_agent "$BAUDBOT_ROOT/start.sh" "$@"
89+
else
90+
require_root "start"
91+
if has_systemd; then
92+
exec systemctl start baudbot "$@"
93+
else
94+
echo "systemd not available. Use: baudbot start --direct"
95+
exit 1
96+
fi
97+
fi
98+
;;
99+
100+
stop)
101+
shift
102+
require_root "stop"
103+
if has_systemd; then
104+
exec systemctl stop baudbot "$@"
105+
else
106+
echo "systemd not available. Kill the agent process manually."
107+
exit 1
108+
fi
109+
;;
110+
111+
restart)
112+
shift
113+
require_root "restart"
114+
if has_systemd; then
115+
exec systemctl restart baudbot "$@"
116+
else
117+
echo "systemd not available."
118+
exit 1
119+
fi
120+
;;
121+
122+
status)
123+
shift
124+
if has_systemd && systemctl is-enabled baudbot &>/dev/null 2>&1; then
125+
exec systemctl status baudbot "$@"
126+
else
127+
# Fallback: check if baudbot_agent has pi running
128+
if pgrep -u baudbot_agent -f "pi --session-control" &>/dev/null; then
129+
echo "baudbot is running (no systemd unit)"
130+
pgrep -u baudbot_agent -af "pi --session-control"
131+
else
132+
echo "baudbot is not running"
133+
fi
134+
fi
135+
;;
136+
137+
logs)
138+
shift
139+
if has_systemd && systemctl is-enabled baudbot &>/dev/null 2>&1; then
140+
exec journalctl -u baudbot -f "$@"
141+
else
142+
echo "No systemd unit. Check tmux sessions:"
143+
echo " sudo -u baudbot_agent tmux ls"
144+
fi
145+
;;
146+
147+
setup)
148+
shift
149+
require_root "setup"
150+
exec "$BAUDBOT_ROOT/setup.sh" "$@"
151+
;;
152+
153+
config)
154+
shift
155+
# config writes to ~/.baudbot/ on the calling user
156+
# For now, point to install.sh's config section
157+
echo "Config management is not yet extracted into a standalone command."
158+
echo "Use: sudo $BAUDBOT_ROOT/install.sh"
159+
exit 1
160+
;;
161+
162+
deploy)
163+
shift
164+
require_root "deploy"
165+
exec "$BAUDBOT_ROOT/bin/deploy.sh" "$@"
166+
;;
167+
168+
audit)
169+
shift
170+
exec "$BAUDBOT_ROOT/bin/security-audit.sh" "$@"
171+
;;
172+
173+
test)
174+
shift
175+
exec "$BAUDBOT_ROOT/bin/test.sh" "$@"
176+
;;
177+
178+
update)
179+
shift
180+
# For now: git pull + deploy
181+
require_root "update"
182+
echo "=== Pulling latest ==="
183+
cd "$BAUDBOT_ROOT"
184+
git pull origin main
185+
echo ""
186+
echo "=== Deploying ==="
187+
exec "$BAUDBOT_ROOT/bin/deploy.sh" "$@"
188+
;;
189+
190+
uninstall)
191+
shift
192+
require_root "uninstall"
193+
exec "$BAUDBOT_ROOT/bin/uninstall.sh" "$@"
194+
;;
195+
196+
doctor)
197+
shift
198+
exec "$BAUDBOT_ROOT/bin/doctor.sh" "$@"
199+
;;
200+
201+
--version|-v)
202+
echo "baudbot $(version)"
203+
;;
204+
205+
--help|-h|"")
206+
usage
207+
;;
208+
209+
*)
210+
echo "Unknown command: $1"
211+
echo ""
212+
usage
213+
exit 1
214+
;;
215+
esac

bin/baudbot.service

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
[Unit]
2+
Description=Baudbot AI Agent
3+
After=network.target
4+
Documentation=https://github.com/modem-dev/baudbot
5+
6+
[Service]
7+
Type=simple
8+
User=baudbot_agent
9+
Group=baudbot_agent
10+
WorkingDirectory=/home/baudbot_agent
11+
12+
# Pre-start: lock down perms and scrub secrets from old logs
13+
ExecStartPre=/home/baudbot_agent/runtime/bin/harden-permissions.sh
14+
ExecStartPre=/bin/bash -c '/home/baudbot_agent/runtime/bin/redact-logs.sh 2>/dev/null || true'
15+
16+
# Main process
17+
ExecStart=/home/baudbot_agent/runtime/start.sh
18+
19+
# Restart on failure, but not on clean exit (agent chose to stop)
20+
Restart=on-failure
21+
RestartSec=10
22+
23+
# Environment
24+
Environment=PATH=/home/baudbot_agent/.varlock/bin:/home/baudbot_agent/opt/node-v22.14.0-linux-x64/bin:/usr/local/bin:/usr/bin:/bin
25+
Environment=HOME=/home/baudbot_agent
26+
27+
# Security hardening
28+
NoNewPrivileges=yes
29+
ProtectSystem=strict
30+
ProtectHome=tmpfs
31+
BindPaths=/home/baudbot_agent
32+
ReadOnlyPaths=/opt/baudbot
33+
PrivateTmp=yes
34+
35+
[Install]
36+
WantedBy=multi-user.target

bin/ci/setup-arch.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ test -d /home/baudbot_agent/.pi/agent/extensions
3535
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env
3636
grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env
3737
grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env
38+
# CLI installed
39+
test -L /usr/local/bin/baudbot
40+
baudbot --version
41+
HELP_OUT=$(baudbot --help)
42+
echo "$HELP_OUT" | grep -q "baudbot"
3843
echo " ✓ install.sh verification passed"
3944

4045
echo "=== Installing test dependencies ==="

bin/ci/setup-ubuntu.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ test -d /home/baudbot_agent/.pi/agent/extensions
4646
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env
4747
grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env
4848
grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env
49+
# CLI installed
50+
test -L /usr/local/bin/baudbot
51+
baudbot --version
52+
HELP_OUT=$(baudbot --help)
53+
echo "$HELP_OUT" | grep -q "baudbot"
4954
echo " ✓ install.sh verification passed"
5055

5156
echo "=== Installing test dependencies ==="

0 commit comments

Comments
 (0)