@marcusrbrown/infra
Personal infrastructure management — deploy automation, operational CLI, and tooling.
Overview
Bun workspace monorepo for managing personal infrastructure. Hosts KeeWeb deploy automation, the CLIProxyAPI proxy that routes Fro Bot agents to Claude via the Claude Code OAuth subscription, the Fro Bot gateway Discord client and workspace runner, a Fro Bot monitoring dashboard, self-hosted Umami analytics, an OIDC credential broker for CI runs, a WireGuard VPN egress box on AWS Lightsail, an operator-run AWS provisioner for fro-bot/agent durable storage, and a CLI for operational health checks, deploy triggers, and MCP tool exposure.
Prerequisites
- Bun v1.0+
- GitHub CLI (
gh) — required for the remotekeeweb/cliproxydeploy triggers and status commands
Quick Start
bun install
bun run lint
bunx tsc --noEmit
bun test --recursive
Apps
Each app is a self-contained deploy unit, except apps/agent — an operator-run provisioner with no deploy step. See its README for build, deploy, provisioning, and configuration detail; see its AGENTS.md for operational runbooks.
- KeeWeb (
apps/keeweb) — self-hosted KeeWeb password manager at kw.igg.ms; static site deployed over SSH/rsync to a Mail-in-a-Box server. - CLIProxyAPI (
apps/cliproxy) — CLIProxyAPI Claude proxy at cliproxy.fro.bot; Docker Compose + Caddy on DigitalOcean, issuing per-repo API keys backed by one Claude subscription. - Gateway (
apps/gateway) — Fro Bot Discord client and workspace runner at gateway.fro.bot; a 3-service Docker Compose stack on DigitalOcean, pinned tofro-bot/agentviaapps/gateway/upstream.json. - Umami (
apps/umami) — self-hosted Umami privacy-respecting analytics at metrics.fro.bot; Docker Compose (Umami + Postgres + Caddy) on DigitalOcean. - Dashboard (
apps/dashboard) — Fro Bot monitoring dashboard at dashboard.fro.bot; Docker Compose (dashboard + Caddy) on DigitalOcean; image built fromfro-bot/dashboard(digest-pinned inapps/dashboard/docker-compose.yaml) and pushed to GHCR by CI before deploy. Seeapps/dashboard/AGENTS.mdfor the operator runbook. - VPN (
apps/vpn) — WireGuard egress box on AWS Lightsail (eu-west-1, Ireland); nativewg-quick@wg0+ systemd, no Docker; provisioned via@aws-sdk/client-lightsail, deployed over SSH. - Broker (
apps/broker) — OIDC-authenticated credential broker at broker.fro.bot; exchanges a GitHub Actions OIDC token for a short-lived cliproxy API key so the durable provider key never lands on a CI runner; Docker Compose (Caddy + Bun) on DigitalOcean. - Agent (
apps/agent) — operator-run AWS provisioner forfro-bot/agentS3 durable session storage: an account-level GitHub OIDC provider, a dedicated S3 bucket, and one least-privilege IAM role per consumer repository. Not deployable — nosrc/deploy.ts,src/host.ts, Docker Compose stack, deploy workflow, or GitHub Environment. Entry point:bun run provision:agent. Seedocs/runbooks/agent-s3-durable-storage.md.
CLI
The @marcusrbrown/infra CLI (packages/cli) is the unified operator surface — one command group per app, a unified status dashboard, and an MCP bridge. See packages/cli/README.md for the full command reference.
bunx @marcusrbrown/infra --help
bunx @marcusrbrown/infra status # all deployments, human-readable
bunx @marcusrbrown/infra status --json # machine-readable
bunx @marcusrbrown/infra mcp # stdio MCP server for coding agents
bunx @marcusrbrown/infra cliproxy monitor runs the Anthropic auth monitor from the CLI; see apps/cliproxy/README.md for setup and recovery.
CI/CD
Workflows
Deploy Pipeline
The Deploy router uses dorny/paths-filter (predicate-quantifier: every) to deploy only when an app's files change (docs, tests, fixtures, and snapshots are excluded from the filter). Each per-app deploy runs in its own GitHub Environment and requires approval.
- Deploy KeeWeb runs in the
keewebenvironment. - Deploy CLIProxy runs in the
cliproxyenvironment. - Deploy Gateway runs in the
gatewayenvironment. - Deploy Umami runs in the
umamienvironment. - Deploy Dashboard runs in the
dashboardenvironment. - Deploy VPN runs in the
vpnenvironment. - Deploy Broker runs in the
brokerenvironment.
apps/agent has no deploy workflow and no GitHub Environment — it is an operator-run provisioner triggered locally via bun run provision:agent.
Manual deploys are available either per-app (workflow_dispatch on each dedicated workflow) or together via the umbrella Deploy workflow.
Required Secrets
keeweb environment:
cliproxy environment:
gateway environment:
See apps/gateway/README.md for the complete contract including CI-injected image digests and OpenCode supervisor tuning.
umami environment:
See apps/umami/README.md and apps/umami/AGENTS.md for the DB-password rotation runbook.
dashboard environment:
See apps/dashboard/AGENTS.md for the operator runbook.
vpn environment:
AWS provisioning credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) are operator-local only — not in the vpn Environment and not used by deploy or status. See apps/vpn/README.md and apps/vpn/AGENTS.md.
broker environment:
See apps/broker/README.md and apps/broker/AGENTS.md.
apps/agent has no GitHub Environment or deploy secrets. It is a local-only provisioner; its AGENT_AWS_*, AGENT_S3_* and AGENT_REPOSITORY_* inputs live in the operator's root .env only and are never written to GitHub. See apps/agent/AGENTS.md.
Repository secrets:
Repository variables:
Server Setup
The KeeWeb deploy target uses a dedicated deploy-kw user with scoped sudo for the nginx activation script. To provision or re-provision the user:
bun run apps/keeweb/server/setup-deploy-user.ts
Host keys for box.heatvision.co, cliproxy.fro.bot, gateway.fro.bot, dashboard.fro.bot, metrics.fro.bot, broker.fro.bot, and the VPN static IP are pinned in .github/known_hosts — no runtime ssh-keyscan.
Repository Structure
For the directory layout and where to put new code, see STRUCTURE.md. For system shape, data flow, and invariants, see ARCHITECTURE.md.
Testing
bun test --recursive # Run all tests from repo root
bun test # Run tests in current package
Tests are colocated alongside source files (*.test.ts). Fixtures live in __fixtures__/, snapshots in __snapshots__/. Tests mock at boundaries (fetch, Bun.spawn) and use NO_COLOR=1 for deterministic subprocess output. CI runs tests as a parallel job alongside lint and type-check.
Development
bun run lint # ESLint
bun run fix # ESLint --fix (includes Prettier)
bunx tsc --noEmit # Type check
Pre-commit hook runs lint-staged → eslint --fix on staged files via simple-git-hooks.
Tooling
License
MIT