diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c28ed0..7fd225a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: - name: ShellCheck run: | - find bin/ setup.sh start.sh -type f \( -name '*.sh' -o -name 'baudbot-safe-bash' -o -name 'baudbot-docker' \) \ + find bin/ setup.sh start.sh install.sh -type f \( -name '*.sh' -o -name 'baudbot-safe-bash' -o -name 'baudbot-docker' -o -name 'baudbot' \) \ | xargs shellcheck -s bash -S warning test: diff --git a/bin/baudbot b/bin/baudbot new file mode 100755 index 0000000..512afca --- /dev/null +++ b/bin/baudbot @@ -0,0 +1,215 @@ +#!/bin/bash +# Baudbot CLI dispatcher +# Routes subcommands to internal scripts. Installed as /usr/local/bin/baudbot. +# +# Usage: baudbot [options] + +set -euo pipefail + +# Find the baudbot source root. Resolution order: +# 1. BAUDBOT_ROOT env var (explicit override) +# 2. Resolve from this script's real location (follow symlinks, then ../) +if [ -z "${BAUDBOT_ROOT:-}" ]; then + SCRIPT="$0" + # Follow symlinks to find the real script location + while [ -L "$SCRIPT" ]; do + DIR="$(cd "$(dirname "$SCRIPT")" && pwd)" + SCRIPT="$(readlink "$SCRIPT")" + # Handle relative symlinks + [[ "$SCRIPT" != /* ]] && SCRIPT="$DIR/$SCRIPT" + done + BAUDBOT_ROOT="$(cd "$(dirname "$SCRIPT")/.." && pwd)" +fi + +# Colors (disabled if not a terminal) +if [ -t 1 ]; then + BOLD='\033[1m' + RESET='\033[0m' +else + BOLD='' RESET='' +fi + +version() { + if [ -f "$BAUDBOT_ROOT/package.json" ]; then + grep '"version"' "$BAUDBOT_ROOT/package.json" | head -1 | sed 's/.*: *"\(.*\)".*/\1/' + else + echo "unknown" + fi +} + +usage() { + echo -e "${BOLD}baudbot${RESET} — hardened infrastructure for always-on AI agents" + echo "" + echo -e "${BOLD}Usage:${RESET} baudbot [options]" + echo "" + echo -e "${BOLD}Lifecycle:${RESET}" + echo " start Start the agent (systemd, or --direct for foreground)" + echo " stop Stop the agent" + echo " restart Restart the agent" + echo " status Show agent status" + echo " logs Tail agent logs" + echo "" + echo -e "${BOLD}Setup:${RESET}" + echo " setup One-time system setup (user, deps, firewall, systemd)" + echo " config Interactive secrets and config setup" + echo " deploy Deploy source + config to agent runtime" + echo "" + echo -e "${BOLD}Operations:${RESET}" + echo " doctor Health check (perms, firewall, secrets, deps)" + echo " audit Security posture audit" + echo " test Run test suite" + echo " update Pull latest and redeploy" + echo " uninstall Remove everything" + echo "" + echo -e "${BOLD}Options:${RESET}" + echo " --version Show version" + echo " --help, -h Show this help" +} + +require_root() { + if [ "$(id -u)" -ne 0 ]; then + echo "❌ baudbot $1 requires root. Run: sudo baudbot $1" + exit 1 + fi +} + +# Detect systemd +has_systemd() { + command -v systemctl &>/dev/null && [ -d /run/systemd/system ] +} + +case "${1:-}" in + start) + shift + if [ "${1:-}" = "--direct" ]; then + # Foreground mode: run start.sh directly (for dev/CI/debugging) + shift + require_root "start --direct" + exec sudo -u baudbot_agent "$BAUDBOT_ROOT/start.sh" "$@" + else + require_root "start" + if has_systemd; then + exec systemctl start baudbot "$@" + else + echo "systemd not available. Use: baudbot start --direct" + exit 1 + fi + fi + ;; + + stop) + shift + require_root "stop" + if has_systemd; then + exec systemctl stop baudbot "$@" + else + echo "systemd not available. Kill the agent process manually." + exit 1 + fi + ;; + + restart) + shift + require_root "restart" + if has_systemd; then + exec systemctl restart baudbot "$@" + else + echo "systemd not available." + exit 1 + fi + ;; + + status) + shift + if has_systemd && systemctl is-enabled baudbot &>/dev/null 2>&1; then + exec systemctl status baudbot "$@" + else + # Fallback: check if baudbot_agent has pi running + if pgrep -u baudbot_agent -f "pi --session-control" &>/dev/null; then + echo "baudbot is running (no systemd unit)" + pgrep -u baudbot_agent -af "pi --session-control" + else + echo "baudbot is not running" + fi + fi + ;; + + logs) + shift + if has_systemd && systemctl is-enabled baudbot &>/dev/null 2>&1; then + exec journalctl -u baudbot -f "$@" + else + echo "No systemd unit. Check tmux sessions:" + echo " sudo -u baudbot_agent tmux ls" + fi + ;; + + setup) + shift + require_root "setup" + exec "$BAUDBOT_ROOT/setup.sh" "$@" + ;; + + config) + shift + # config writes to ~/.baudbot/ on the calling user + # For now, point to install.sh's config section + echo "Config management is not yet extracted into a standalone command." + echo "Use: sudo $BAUDBOT_ROOT/install.sh" + exit 1 + ;; + + deploy) + shift + require_root "deploy" + exec "$BAUDBOT_ROOT/bin/deploy.sh" "$@" + ;; + + audit) + shift + exec "$BAUDBOT_ROOT/bin/security-audit.sh" "$@" + ;; + + test) + shift + exec "$BAUDBOT_ROOT/bin/test.sh" "$@" + ;; + + update) + shift + # For now: git pull + deploy + require_root "update" + echo "=== Pulling latest ===" + cd "$BAUDBOT_ROOT" + git pull origin main + echo "" + echo "=== Deploying ===" + exec "$BAUDBOT_ROOT/bin/deploy.sh" "$@" + ;; + + uninstall) + shift + require_root "uninstall" + exec "$BAUDBOT_ROOT/bin/uninstall.sh" "$@" + ;; + + doctor) + shift + exec "$BAUDBOT_ROOT/bin/doctor.sh" "$@" + ;; + + --version|-v) + echo "baudbot $(version)" + ;; + + --help|-h|"") + usage + ;; + + *) + echo "Unknown command: $1" + echo "" + usage + exit 1 + ;; +esac diff --git a/bin/baudbot.service b/bin/baudbot.service new file mode 100644 index 0000000..9289f21 --- /dev/null +++ b/bin/baudbot.service @@ -0,0 +1,36 @@ +[Unit] +Description=Baudbot AI Agent +After=network.target +Documentation=https://github.com/modem-dev/baudbot + +[Service] +Type=simple +User=baudbot_agent +Group=baudbot_agent +WorkingDirectory=/home/baudbot_agent + +# Pre-start: lock down perms and scrub secrets from old logs +ExecStartPre=/home/baudbot_agent/runtime/bin/harden-permissions.sh +ExecStartPre=/bin/bash -c '/home/baudbot_agent/runtime/bin/redact-logs.sh 2>/dev/null || true' + +# Main process +ExecStart=/home/baudbot_agent/runtime/start.sh + +# Restart on failure, but not on clean exit (agent chose to stop) +Restart=on-failure +RestartSec=10 + +# Environment +Environment=PATH=/home/baudbot_agent/.varlock/bin:/home/baudbot_agent/opt/node-v22.14.0-linux-x64/bin:/usr/local/bin:/usr/bin:/bin +Environment=HOME=/home/baudbot_agent + +# Security hardening +NoNewPrivileges=yes +ProtectSystem=strict +ProtectHome=tmpfs +BindPaths=/home/baudbot_agent +ReadOnlyPaths=/opt/baudbot +PrivateTmp=yes + +[Install] +WantedBy=multi-user.target diff --git a/bin/ci/setup-arch.sh b/bin/ci/setup-arch.sh index 184a2c8..a1106e1 100755 --- a/bin/ci/setup-arch.sh +++ b/bin/ci/setup-arch.sh @@ -35,6 +35,11 @@ test -d /home/baudbot_agent/.pi/agent/extensions grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env +# CLI installed +test -L /usr/local/bin/baudbot +baudbot --version +HELP_OUT=$(baudbot --help) +echo "$HELP_OUT" | grep -q "baudbot" echo " ✓ install.sh verification passed" echo "=== Installing test dependencies ===" diff --git a/bin/ci/setup-ubuntu.sh b/bin/ci/setup-ubuntu.sh index 8fc3771..edf172f 100755 --- a/bin/ci/setup-ubuntu.sh +++ b/bin/ci/setup-ubuntu.sh @@ -46,6 +46,11 @@ test -d /home/baudbot_agent/.pi/agent/extensions grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env +# CLI installed +test -L /usr/local/bin/baudbot +baudbot --version +HELP_OUT=$(baudbot --help) +echo "$HELP_OUT" | grep -q "baudbot" echo " ✓ install.sh verification passed" echo "=== Installing test dependencies ===" diff --git a/bin/doctor.sh b/bin/doctor.sh new file mode 100755 index 0000000..3ed0f74 --- /dev/null +++ b/bin/doctor.sh @@ -0,0 +1,239 @@ +#!/bin/bash +# Baudbot Doctor — health check for the baudbot installation. +# Checks deps, perms, secrets, firewall, and agent status. +# +# Usage: baudbot doctor [--fix] + +set -euo pipefail + +for arg in "$@"; do + case "$arg" in + -h|--help) + echo "Usage: baudbot doctor" + exit 0 + ;; + esac +done + +BAUDBOT_HOME="/home/baudbot_agent" +PASS=0 +FAIL=0 +WARN=0 + +pass() { echo " ✓ $1"; PASS=$((PASS + 1)); } +fail() { echo " ✗ $1"; FAIL=$((FAIL + 1)); } +warn() { echo " ⚠ $1"; WARN=$((WARN + 1)); } + +echo "Baudbot Doctor" +echo "" + +# ── User ───────────────────────────────────────────────────────────────────── + +echo "User:" +if id baudbot_agent &>/dev/null; then + pass "baudbot_agent user exists" +else + fail "baudbot_agent user does not exist (run: baudbot setup)" +fi + +# ── Dependencies ───────────────────────────────────────────────────────────── + +echo "" +echo "Dependencies:" + +NODE_BIN="$BAUDBOT_HOME/opt/node-v22.14.0-linux-x64/bin/node" +if [ -x "$NODE_BIN" ]; then + NODE_VER=$("$NODE_BIN" --version 2>/dev/null || echo "unknown") + pass "Node.js $NODE_VER" +else + fail "Node.js not found at $NODE_BIN" +fi + +PI_BIN="$BAUDBOT_HOME/opt/node-v22.14.0-linux-x64/bin/pi" +if [ -x "$PI_BIN" ] || [ -L "$PI_BIN" ]; then + pass "pi is installed" +else + fail "pi not found at $PI_BIN" +fi + +if command -v varlock &>/dev/null || [ -x "$BAUDBOT_HOME/.varlock/bin/varlock" ]; then + pass "varlock is installed" +else + fail "varlock not found" +fi + +if command -v docker &>/dev/null; then + pass "docker is available" +else + warn "docker not found (optional, needed for container tasks)" +fi + +# ── Secrets ────────────────────────────────────────────────────────────────── + +echo "" +echo "Secrets:" + +ENV_FILE="$BAUDBOT_HOME/.config/.env" +if [ -f "$ENV_FILE" ]; then + PERMS=$(stat -c '%a' "$ENV_FILE" 2>/dev/null || echo "unknown") + OWNER=$(stat -c '%U' "$ENV_FILE" 2>/dev/null || echo "unknown") + if [ "$PERMS" = "600" ]; then + pass ".env has 600 permissions" + else + fail ".env has $PERMS permissions (should be 600)" + fi + if [ "$OWNER" = "baudbot_agent" ]; then + pass ".env owned by baudbot_agent" + else + fail ".env owned by $OWNER (should be baudbot_agent)" + fi + + # Check for at least one LLM key + HAS_LLM=false + for key in ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENCODE_ZEN_API_KEY; do + if grep -q "^${key}=.\+" "$ENV_FILE" 2>/dev/null; then + HAS_LLM=true + break + fi + done + if [ "$HAS_LLM" = true ]; then + pass "at least one LLM API key is set" + else + fail "no LLM API key set (need ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, or OPENCODE_ZEN_API_KEY)" + fi + + # Check required keys + for key in GITHUB_TOKEN SLACK_BOT_TOKEN SLACK_APP_TOKEN SLACK_ALLOWED_USERS; do + if grep -q "^${key}=.\+" "$ENV_FILE" 2>/dev/null; then + pass "$key is set" + else + warn "$key is not set" + fi + done +else + fail ".env not found at $ENV_FILE" +fi + +# ── Runtime ────────────────────────────────────────────────────────────────── + +echo "" +echo "Runtime:" + +if [ -f "$BAUDBOT_HOME/runtime/start.sh" ]; then + pass "start.sh deployed" +else + fail "start.sh not found (run: baudbot deploy)" +fi + +if [ -d "$BAUDBOT_HOME/.pi/agent/extensions" ]; then + EXT_COUNT=$(find "$BAUDBOT_HOME/.pi/agent/extensions" -maxdepth 1 -name '*.ts' -o -name '*.mjs' 2>/dev/null | wc -l) + pass "extensions deployed ($EXT_COUNT files)" +else + fail "extensions not deployed (run: baudbot deploy)" +fi + +if [ -d "$BAUDBOT_HOME/.pi/agent/skills" ]; then + pass "skills deployed" +else + fail "skills not deployed (run: baudbot deploy)" +fi + +if [ -d "$BAUDBOT_HOME/runtime/slack-bridge" ] && [ -f "$BAUDBOT_HOME/runtime/slack-bridge/bridge.mjs" ]; then + pass "slack bridge deployed" +else + fail "slack bridge not deployed (run: baudbot deploy)" +fi + +# ── Security ───────────────────────────────────────────────────────────────── + +echo "" +echo "Security:" + +# Firewall +if command -v iptables &>/dev/null && iptables -w -L BAUDBOT_OUTPUT -n &>/dev/null 2>&1; then + RULE_COUNT=$(iptables -w -L BAUDBOT_OUTPUT -n 2>/dev/null | tail -n +3 | wc -l) + pass "firewall active ($RULE_COUNT rules)" +else + warn "firewall not active (run: baudbot setup)" +fi + +# /proc hidepid +if mount | grep -q 'hidepid=2'; then + pass "/proc hidepid=2 active" +else + warn "/proc hidepid not active" +fi + +# Safe bash wrapper +if [ -f /usr/local/bin/baudbot-safe-bash ]; then + if [ "$(stat -c '%U' /usr/local/bin/baudbot-safe-bash)" = "root" ]; then + pass "baudbot-safe-bash installed (root-owned)" + else + fail "baudbot-safe-bash not root-owned" + fi +else + warn "baudbot-safe-bash not installed" +fi + +# Tool-guard read-only +TOOL_GUARD="$BAUDBOT_HOME/.pi/agent/extensions/tool-guard.ts" +if [ -f "$TOOL_GUARD" ]; then + if [ ! -w "$TOOL_GUARD" ] 2>/dev/null; then + pass "tool-guard.ts is read-only" + else + # Check if writable by agent + PERMS=$(stat -c '%a' "$TOOL_GUARD" 2>/dev/null || echo "unknown") + if echo "$PERMS" | grep -qE '^[0-4]'; then + pass "tool-guard.ts is read-only" + else + warn "tool-guard.ts may be writable (perms: $PERMS)" + fi + fi +else + fail "tool-guard.ts not found" +fi + +# ── Agent Status ───────────────────────────────────────────────────────────── + +echo "" +echo "Agent:" + +if command -v systemctl &>/dev/null && [ -d /run/systemd/system ]; then + if systemctl is-enabled baudbot &>/dev/null 2>&1; then + pass "systemd unit enabled" + if systemctl is-active baudbot &>/dev/null 2>&1; then + pass "agent is running (systemd)" + else + warn "agent is not running" + fi + else + warn "systemd unit not installed (run: baudbot setup)" + fi +else + # No systemd — check for pi process + if pgrep -u baudbot_agent -f "pi --session-control" &>/dev/null; then + pass "agent is running (direct mode)" + else + warn "agent is not running" + fi +fi + +# ── Summary ────────────────────────────────────────────────────────────────── + +echo "" +echo "────────────────────────────" +echo " $PASS passed, $FAIL failed, $WARN warnings" + +if [ "$FAIL" -gt 0 ]; then + echo "" + echo "Fix failures before starting the agent." + exit 1 +elif [ "$WARN" -gt 0 ]; then + echo "" + echo "Warnings are non-blocking but should be reviewed." + exit 0 +else + echo "" + echo "All checks passed." + exit 0 +fi diff --git a/bin/uninstall.sh b/bin/uninstall.sh index 6a1cc24..8c5ba0f 100755 --- a/bin/uninstall.sh +++ b/bin/uninstall.sh @@ -168,6 +168,34 @@ fi # ── 5. Remove sudoers ─────────────────────────────────────────────────────── +echo "=== Removing baudbot systemd unit ===" +if systemctl is-enabled baudbot &>/dev/null 2>&1; then + run systemctl stop baudbot || true + run systemctl disable baudbot + removed "baudbot service (stopped + disabled)" +else + skipped "baudbot service (not enabled)" +fi + +if [ -f /etc/systemd/system/baudbot.service ]; then + run rm -f /etc/systemd/system/baudbot.service + run systemctl daemon-reload + removed "baudbot.service unit file" +else + skipped "baudbot.service (not found)" +fi + +echo "=== Removing baudbot CLI ===" +if [ -L /usr/local/bin/baudbot ]; then + run rm -f /usr/local/bin/baudbot + removed "/usr/local/bin/baudbot symlink" +elif [ -f /usr/local/bin/baudbot ]; then + run rm -f /usr/local/bin/baudbot + removed "/usr/local/bin/baudbot" +else + skipped "/usr/local/bin/baudbot (not found)" +fi + echo "=== Removing sudoers ===" if [ -f /etc/sudoers.d/baudbot-agent ]; then run rm -f /etc/sudoers.d/baudbot-agent diff --git a/install.sh b/install.sh index 373356c..69a5f48 100755 --- a/install.sh +++ b/install.sh @@ -412,18 +412,27 @@ else ask "Start the agent now? [Y/n]: " read -r launch if [ -z "$launch" ] || [[ "$launch" =~ ^[Yy] ]]; then - info "Launching in tmux session 'baudbot'..." - sudo -u baudbot_agent tmux new-session -d -s baudbot "$BAUDBOT_HOME/runtime/start.sh" 2>/dev/null || true - sleep 2 - if sudo -u baudbot_agent tmux has-session -t baudbot 2>/dev/null; then - info "Agent is running ✓" + info "Launching agent..." + if command -v systemctl &>/dev/null && [ -d /run/systemd/system ]; then + systemctl start baudbot 2>/dev/null || true + sleep 2 + if systemctl is-active baudbot &>/dev/null 2>&1; then + info "Agent is running ✓" + else + warn "Agent didn't start — check: baudbot logs" + fi else - warn "tmux session didn't start — try manually:" - echo -e " ${DIM}sudo -u baudbot_agent ~/runtime/start.sh${RESET}" + sudo -u baudbot_agent tmux new-session -d -s baudbot "$BAUDBOT_HOME/runtime/start.sh" 2>/dev/null || true + sleep 2 + if sudo -u baudbot_agent tmux has-session -t baudbot 2>/dev/null; then + info "Agent is running ✓" + else + warn "Agent didn't start — try: baudbot start --direct" + fi fi else info "Skipped. Start later with:" - echo -e " ${DIM}sudo -u baudbot_agent ~/runtime/start.sh${RESET}" + echo -e " ${DIM}sudo baudbot start${RESET}" fi fi @@ -435,11 +444,13 @@ SSH_PUB="$BAUDBOT_HOME/.ssh/id_ed25519.pub" echo -e "🐝 ${BOLD}Baudbot is installed.${RESET}" echo "" +echo -e " ${BOLD}Start agent:${RESET} sudo baudbot start" +echo -e " ${BOLD}Agent status:${RESET} sudo baudbot status" +echo -e " ${BOLD}View logs:${RESET} sudo baudbot logs" echo -e " ${BOLD}Edit secrets:${RESET} sudo -u baudbot_agent vim $ENV_FILE" -echo -e " ${BOLD}Start agent:${RESET} sudo -u baudbot_agent ~/runtime/start.sh" -echo -e " ${BOLD}Attach to tmux:${RESET} sudo -u baudbot_agent tmux attach -t baudbot" -echo -e " ${BOLD}Update runtime:${RESET} $REPO_DIR/bin/deploy.sh" -echo -e " ${BOLD}Security audit:${RESET} $REPO_DIR/bin/security-audit.sh" +echo -e " ${BOLD}Deploy changes:${RESET} sudo baudbot deploy" +echo -e " ${BOLD}Health check:${RESET} sudo baudbot doctor" +echo -e " ${BOLD}Security audit:${RESET} sudo baudbot audit" echo "" if [ -f "$SSH_PUB" ]; then echo -e " ${YELLOW}⚠${RESET} Add the agent's SSH key to GitHub:" diff --git a/package.json b/package.json index c7d4f9b..dd1c34b 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "baudbot", + "version": "0.1.0", "private": true, "scripts": { "test": "bin/test.sh", diff --git a/setup.sh b/setup.sh index b7f248f..eb35531 100755 --- a/setup.sh +++ b/setup.sh @@ -218,6 +218,24 @@ systemctl daemon-reload systemctl enable baudbot-firewall echo "Firewall will be restored on boot via systemd" +echo "=== Installing baudbot CLI ===" +if [ ! -f /usr/local/bin/baudbot ] || [ "$(readlink -f /usr/local/bin/baudbot 2>/dev/null)" != "$REPO_DIR/bin/baudbot" ]; then + ln -sf "$REPO_DIR/bin/baudbot" /usr/local/bin/baudbot + echo "Installed /usr/local/bin/baudbot → $REPO_DIR/bin/baudbot" +else + echo "baudbot CLI already installed, skipping" +fi + +echo "=== Installing baudbot systemd unit ===" +# Template the service file with the correct paths +sed \ + -e "s|/home/baudbot_agent|$BAUDBOT_HOME|g" \ + "$REPO_DIR/bin/baudbot.service" > /etc/systemd/system/baudbot.service +systemctl daemon-reload +systemctl enable baudbot +echo "Installed baudbot.service (enabled, not started)" +echo "Start with: baudbot start" + echo "=== Setting up /proc isolation (hidepid) ===" # Create a group whose members can still see all processes. # The admin user is added; baudbot_agent is NOT — it only sees its own processes. @@ -252,27 +270,17 @@ echo "=== Setup complete ===" echo "" echo "Remaining manual steps:" echo " 1. sudo passwd baudbot_agent" -echo " 2. Add secrets to $BAUDBOT_HOME/.config/.env:" -echo " GITHUB_TOKEN=..." -echo " OPENCODE_ZEN_API_KEY=..." -echo " AGENTMAIL_API_KEY=..." -echo " KERNEL_API_KEY=..." -echo " BAUDBOT_SECRET=..." -echo " SLACK_BOT_TOKEN=..." -echo " SLACK_APP_TOKEN=..." -echo " SLACK_ALLOWED_USERS=U... (REQUIRED — bridge refuses to start without this)" -echo " SENTRY_CHANNEL_ID=C... (Slack channel ID for Sentry alerts)" -echo " SENTRY_ORG=... (Sentry organization slug)" -echo " BAUDBOT_EMAIL=... (AgentMail address for email monitor)" -echo " BAUDBOT_ALLOWED_EMAILS=you@example.com (comma-separated sender allowlist)" -echo " BAUDBOT_SOURCE_DIR=$REPO_DIR (admin source repo path, for tool-guard)" -echo " 3. Add SSH key to your agent's GitHub account" +echo " 2. Add secrets: sudo baudbot config" +echo " Or manually edit: $BAUDBOT_HOME/.config/.env" +echo " 3. Add SSH key to your agent's GitHub account:" +echo " cat $BAUDBOT_HOME/.ssh/id_ed25519.pub" echo " 4. Log out and back in for group membership to take effect" -echo " (both baudbot_agent group and procview group)" -echo " 5. Launch: sudo -u baudbot_agent ~/runtime/start.sh" -echo "" -echo "To update runtime after editing source:" -echo " $REPO_DIR/bin/deploy.sh" echo "" -echo "To verify security posture:" -echo " $REPO_DIR/bin/security-audit.sh" +echo "Commands:" +echo " baudbot start Start the agent" +echo " baudbot stop Stop the agent" +echo " baudbot status Check agent status" +echo " baudbot logs Tail agent logs" +echo " baudbot deploy Deploy source changes to agent runtime" +echo " baudbot doctor Health check" +echo " baudbot audit Security posture audit"