Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion .c8rc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"all": false,
"include": [
"slack-bridge/security.mjs",
"broker-gateway/security.mjs",
"bin/scan-extensions.mjs"
],
"exclude": [
Expand Down
90 changes: 90 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Nightly

on:
schedule:
# 06:00 UTC daily (1 AM EST / 10 PM PST)
- cron: "0 6 * * *"
workflow_dispatch:
inputs:
inference_smoke:
description: "Run inference smoke test"
type: boolean
default: true

concurrency:
group: nightly
cancel-in-progress: true

jobs:
inference-smoke:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- distro: ubuntu
image: ubuntu-24-04-x64
setup_script: bin/ci/setup-ubuntu.sh
- distro: arch
image: "217410218"
setup_script: bin/ci/setup-arch.sh

name: ${{ matrix.distro }} (inference)
timeout-minutes: 15

steps:
- uses: actions/checkout@v4

- name: Generate ephemeral SSH key
run: |
mkdir -p ~/.ssh
ssh-keygen -t ed25519 -f ~/.ssh/ci_key -N "" -q

- name: Create droplet
id: droplet
env:
DO_API_TOKEN: ${{ secrets.DO_API_TOKEN }}
run: |
output=$(bash bin/ci/droplet.sh create \
"nightly-${{ matrix.distro }}-${{ github.run_id }}" \
"${{ matrix.image }}" \
~/.ssh/ci_key.pub)
echo "$output" >> "$GITHUB_OUTPUT"
echo "$output"

- name: Wait for SSH
env:
DO_API_TOKEN: ${{ secrets.DO_API_TOKEN }}
run: |
bash bin/ci/droplet.sh wait-ssh \
"${{ steps.droplet.outputs.DROPLET_IP }}" \
~/.ssh/ci_key

- name: Upload source
run: |
tar czf /tmp/baudbot-src.tar.gz \
--exclude=node_modules --exclude=.git .
scp -o StrictHostKeyChecking=no -o BatchMode=yes \
-i ~/.ssh/ci_key \
/tmp/baudbot-src.tar.gz \
"root@${{ steps.droplet.outputs.DROPLET_IP }}:/tmp/baudbot-src.tar.gz"

- name: Setup and test (with inference smoke)
run: |
bash bin/ci/droplet.sh run \
"${{ steps.droplet.outputs.DROPLET_IP }}" \
~/.ssh/ci_key \
"${{ matrix.setup_script }}" \
"BAUDBOT_CI_INFERENCE_SMOKE=1" \
"BAUDBOT_CI_INFERENCE_SMOKE_OPTIONAL=1" \
"CI_ANTHROPIC_API_KEY=${{ secrets.CI_ANTHROPIC_API_KEY }}"

- name: Cleanup
if: always()
env:
DO_API_TOKEN: ${{ secrets.DO_API_TOKEN }}
run: |
bash bin/ci/droplet.sh destroy \
"${{ steps.droplet.outputs.DROPLET_ID }}" \
"${{ steps.droplet.outputs.SSH_KEY_ID }}" \
"nightly-${{ matrix.distro }}-${{ github.run_id }}"
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
*.key
*.pem
node_modules/
# Slack bridge
slack-bridge/node_modules/
slack-bridge/.env
# Broker gateway
broker-gateway/node_modules/
broker-gateway/.env
.pi/
# Coverage
coverage/
Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Baudbot is hardened infrastructure for running always-on AI agents.
Use this file for **repo-wide** guidance. For directory-specific rules, use the nearest nested `AGENTS.md`:
- [`bin/AGENTS.md`](bin/AGENTS.md)
- [`pi/extensions/AGENTS.md`](pi/extensions/AGENTS.md)
- [`slack-bridge/AGENTS.md`](slack-bridge/AGENTS.md)
- [`broker-gateway/AGENTS.md`](broker-gateway/AGENTS.md)

## How Baudbot works

Expand All @@ -16,7 +16,7 @@ Baudbot is a persistent, team-facing coding agent system. It connects to Slack,
```text
Slack
slack-bridge (broker pull-mode or legacy Socket Mode)
broker-gateway (broker pull-mode or legacy Socket Mode)
control-agent (always-on, manages todo/routing/Slack threads)
├── dev-agent(s) — ephemeral coding workers in isolated worktrees
Expand All @@ -36,7 +36,7 @@ git commits → PRs → CI feedback → thread updates back to Slack
- `dev-agent/` — coding worker persona
- `sentry-agent/` — incident triage persona
- `pi/settings.json` — pi agent settings
- `slack-bridge/` — Slack integration bridges + security module
- `broker-gateway/` — Slack integration bridges + security module
- `docs/` — architecture/operations/security documentation
- `test/` — vitest wrappers for shell scripts, integration, and legacy Node tests
- `hooks/` — git hooks (security-critical `pre-commit` protecting admin-managed files)
Expand Down
16 changes: 12 additions & 4 deletions bin/ci/droplet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,20 @@ cmd_wait_ssh() {

# ── run <ip> <ssh_private_key_file> <script> ──────────────────────────────────
cmd_run() {
local ip="${1:?Usage: droplet.sh run <ip> <ssh_private_key_file> <script>}"
local ip="${1:?Usage: droplet.sh run <ip> <ssh_private_key_file> <script> [env_vars...]}"
local key_file="${2:?}"
local script="${3:?}"

ssh -o StrictHostKeyChecking=no -o BatchMode=yes \
-i "$key_file" "root@$ip" bash -s < "$script"
shift 3

# Remaining args are KEY=VALUE env vars forwarded to the remote script.
# Prepend export statements so the remote bash -s session inherits them.
{
for var in "$@"; do
printf 'export %s\n' "$var"
done
cat "$script"
} | ssh -o StrictHostKeyChecking=no -o BatchMode=yes \
-i "$key_file" "root@$ip" bash -s
}

# ── list ──────────────────────────────────────────────────────────────────────
Expand Down
16 changes: 15 additions & 1 deletion bin/ci/setup-arch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,25 @@ bash /home/baudbot_admin/baudbot/bin/ci/smoke-cli.sh
echo "=== Running runtime smoke checks ==="
bash /home/baudbot_admin/baudbot/bin/ci/smoke-agent-runtime.sh

if [[ "${BAUDBOT_CI_INFERENCE_SMOKE:-}" == "1" ]]; then
echo "=== Running inference smoke check ==="
if bash /home/baudbot_admin/baudbot/bin/ci/smoke-agent-inference.sh; then
echo " ✓ inference smoke passed"
elif [[ "${BAUDBOT_CI_INFERENCE_SMOKE_OPTIONAL:-}" == "1" ]]; then
echo " ⚠ inference smoke failed (optional — continuing)"
else
echo " ✗ inference smoke failed"
exit 1
fi
else
echo "=== Inference smoke check skipped (set BAUDBOT_CI_INFERENCE_SMOKE=1 to enable) ==="
fi

echo "=== Installing test dependencies ==="
export PATH="/home/baudbot_agent/opt/node/bin:$PATH"
cd /home/baudbot_admin/baudbot
npm install --ignore-scripts 2>&1 | tail -1
cd slack-bridge && npm install 2>&1 | tail -1
cd broker-gateway && npm install 2>&1 | tail -1
cd ..

echo "=== Running tests ==="
Expand Down
16 changes: 15 additions & 1 deletion bin/ci/setup-ubuntu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,25 @@ bash /home/baudbot_admin/baudbot/bin/ci/smoke-cli.sh
echo "=== Running runtime smoke checks ==="
bash /home/baudbot_admin/baudbot/bin/ci/smoke-agent-runtime.sh

if [[ "${BAUDBOT_CI_INFERENCE_SMOKE:-}" == "1" ]]; then
echo "=== Running inference smoke check ==="
if bash /home/baudbot_admin/baudbot/bin/ci/smoke-agent-inference.sh; then
echo " ✓ inference smoke passed"
elif [[ "${BAUDBOT_CI_INFERENCE_SMOKE_OPTIONAL:-}" == "1" ]]; then
echo " ⚠ inference smoke failed (optional — continuing)"
else
echo " ✗ inference smoke failed"
exit 1
fi
else
echo "=== Inference smoke check skipped (set BAUDBOT_CI_INFERENCE_SMOKE=1 to enable) ==="
fi

echo "=== Installing test dependencies ==="
export PATH="/home/baudbot_agent/opt/node/bin:$PATH"
cd /home/baudbot_admin/baudbot
npm install --ignore-scripts 2>&1 | tail -1
cd slack-bridge && npm install 2>&1 | tail -1
cd broker-gateway && npm install 2>&1 | tail -1
cd ..

echo "=== Running tests ==="
Expand Down
Loading