# LLMs.md — Agent Reference for obm This file is written for AI agents (LLMs, coding assistants, autonomous agents) who need to understand the `obm` project and work with their human to deploy, configure, or develop it. If you're reading this, you're probably an agent trying to help someone. Here's what you need to know. --- ## What obm Is `obm` (OpenBoatMobile) is a Go CLI tool that deploys AI agents to cloud infrastructure. It generates Terraform-compatible `.env` files through an interactive walkthrough or a YAML config, validates API credentials against live endpoints, and wraps Terraform lifecycle commands. Think of it as: "Terraform for AI agents, with a friendly wizard instead of a 94-line `.env` template." --- ## Quick Orientation | Fact | Value | |------|-------| | Language | Go 1.22 | | Module path | `github.com/openboatmobile/obm` | | External deps | `gopkg.in/yaml.v3` only | | Binary type | Static, zero runtime deps | | Version file | `VERSION` (single line, e.g. `0.1.0`) | | Current version | 0.1.0 | | License | MIT | **Repos:** - `obm` (this repo) — the Go CLI - `openboatmobile-ai` — the Terraform configs that `obm` generates `.env` files for - `openboatmobile` (private) — live deployment with keys, do NOT touch --- ## Package Map Use this to find what you need: ``` cmd/obm/main.go → Entry point, subcommand routing, build-time version vars internal/config/ → All configuration types and I/O: config.go → Config struct, GetValue/SetValue deployment.go → DeploymentConfig (30+ fields), cost estimation schema.go → VarDef schema (all Terraform variables), VarGroup enum dotenv.go → DotEnvFile round-trip parser dotenv_writer.go → WriteDotEnv — grouped .env output tfvars.go → WriteTfVars — HCL-format output yaml.go → YAMLConfig, LoadYAMLConfig, ToDeploymentConfig internal/deploy/deploy.go → Walkthrough orchestrator (Run, RunFromFile, RunWithConfig) internal/destroy/destroy.go → Terraform destroy with state parsing internal/inference/ → Inference provider validation: client.go → HTTP client, ValidateAPIKey, ValidationResult inference.go → Provider enum, ProviderConfig, FallbackChain internal/prompt/prompt.go → Terminal I/O: Select, Confirm, Input, Password, colors internal/provider/ → Cloud provider abstraction: provider.go → Provider interface, BaseProvider, Registry hetzner/hetzner.go → Hetzner Cloud API: token validation, SSH key listing internal/terraform/terraform.go → Runner: Init, Plan, Apply, Destroy internal/validation/validation.go → Check interface, Runner, CheckResult, Status enum ``` --- ## CLI Commands Your Human Might Ask About | Command | What it does | When they'd use it | |---------|-------------|-------------------| | `obm deploy` | Interactive 8-step walkthrough | First-time setup or redeploy | | `obm deploy --config deploy.yaml` | Non-interactive from YAML | CI/CD, automation, repeat deploys | | `obm validate` | Check `.env` + validate API keys | "Did I configure this right?" | | `obm destroy` | Tear down infrastructure | "I'm done with this server" | | `obm version` | Print version with commit/build info | Debugging | --- ## Deploy Walkthrough Steps When your human runs `obm deploy`, they'll go through these in order: 1. **Framework** — Hermes or OpenClaw 2. **Cloud Provider** — Hetzner or DigitalOcean 3. **Provider Token** — API key for their cloud provider (validated live) 4. **SSH Key** — Select from provider or enter manually 5. **Server Config** — Name, location/region, size 6. **Inference Provider** — ZAI, Venice, or OpenRouter (API key validated live) 7. **Tailscale** — Optional VPN (auth key + tailnet) 8. **Discord** — Optional bot integration (token, server ID, user IDs) After all 8 steps: summary + cost estimate → confirm → `.env` written → optional `terraform init && apply`. --- ## What Your Human Needs Before Deploying Tell them to have these ready: 1. **Cloud provider account** with API token (Hetzner: console.hetzner.cloud → Security → API Tokens; DO: cloud.digitalocean.com → API) 2. **SSH public key** uploaded to their cloud provider 3. **Inference provider API key** (Venice, OpenRouter, or ZAI) 4. *(Optional)* Tailscale auth key 5. *(Optional)* Discord bot token + server ID --- ## Framework Differences When your human asks "Hermes or OpenClaw?": **Hermes Agent** — if they want: - Discord chat, voice, web search, many integrations - Python-based, Docker or direct install - More configurable (gateway, allowed users, auto-threading) **OpenClaw** — if they want: - Simpler setup, fewer moving parts - Node.js-based - Built-in security (fail2ban, unattended upgrades, swap) --- ## Configuration Files ### `.env` (Terraform input) All variables prefixed with `TF_VAR_`. Generated by `obm deploy` or `WriteDotEnv()`. This is the primary output of the tool. Groups: PROVIDER, SERVER, SSH, API KEYS, MODEL, DISCORD, TAILSCALE, HERMES-SPECIFIC, OPENCLAW-SPECIFIC, SECURITY, PROJECT. Special format for SSH keys: `TF_VAR_ssh_key_names='["key-name"]'` — single-quoted shell string containing JSON array. ### `deploy.yaml` (Non-interactive input) Full schema in `deploy.yaml.example`. Key sections: ```yaml framework: hermes provider: name: hetzner token: "..." ssh: names: ["my-key"] server: name: "agent" location: "ash" type: "cpx21" inference: provider: venice api_key: "..." primary_model: "zai-org-glm-5" tailscale: enabled: true auth_key: "..." discord: enabled: false ``` --- ## Build Commands ```bash make build # Build for current platform make test # Test with race detection + coverage make lint # go vet + gofmt make cross-compile # All platforms: linux-{amd64,arm64}, darwin-arm64, windows-{amd64,arm64} make clean # Remove binary + coverage ``` From source without make: ```bash go build -o obm ./cmd/obm go test ./... go vet ./... ``` Version injection at build time: ```bash go build -ldflags "-s -w -X main.version=$(cat VERSION) -X main.gitCommit=$(git rev-parse --short HEAD) -X main.buildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" -o obm ./cmd/obm ``` --- ## Common Tasks Your Human Might Ask For ### "Help me deploy an agent" 1. Make sure they have API keys ready (see "What Your Human Needs" above) 2. Run `obm deploy` 3. Walk them through the 8 steps if they have questions 4. The cost estimate at the end is approximate — cloud providers may vary ### "Check if my config is valid" ```bash obm validate ``` This loads `.env`, checks required variables, and validates inference API keys against live endpoints. ### "I want to tear down my server" ```bash obm destroy ``` It asks for confirmation. It reads `terraform.tfstate` to show what will be destroyed. ### "Set up CI/CD deployment" 1. Create a `deploy.yaml` from `deploy.yaml.example` 2. Store secrets in your CI secrets manager 3. In pipeline: `obm deploy --config deploy.yaml` ### "Add a new cloud provider" 1. Create `internal/provider//.go` implementing the `Provider` interface 2. Register via `init()`: `provider.Register("", func() provider.Provider { return New() })` 3. Add provider-specific fields to `DeploymentConfig` 4. Update `schema.go` with new `VarGroup` and `VarDef` entries 5. Add step function in `deploy.go` ### "Add a new inference provider" 1. Add `Provider` constant to `internal/inference/inference.go` 2. Add case to `Info()` method (name, env var, base URL) 3. Add case to `UnmarshalText()` for YAML parsing 4. Add case to `setAuthHeaders()` in `client.go` if auth differs from Bearer token 5. Update `AllProviders()` return slice --- ## Known Limitations - `obm status` is stubbed — not yet functional - DigitalOcean provider validation not yet implemented (only Hetzner) - No resumable deploy — interrupted walkthrough = start over - No cost preview before the summary step - `openai` and `anthropic` inference providers listed in schema but not fully implemented in the inference client (only ZAI, Venice, OpenRouter have live validation) --- ## Relationship to Terraform Configs `obm` generates the `.env` file. The Terraform configs that consume it live in the `openboatmobile-ai` repo. The variable schema in `internal/config/schema.go` must stay in sync with the Terraform variable definitions in `openboatmobile-ai/variables-*.tf`. If you add a variable to the Terraform configs, you must also add a corresponding `VarDef` to `schema.go`. --- ## Testing Strategy - Unit tests in each package (`*_test.go`) - Hetzner provider tested with mock HTTP servers (`WithHTTPClient` + `WithBaseURL` options) - Inference client tested with mock `/models` endpoints - Run with: `make test` or `go test -v -race -coverprofile=coverage.out ./...` --- ## File Locations Summary | File | Purpose | |------|---------| | `VERSION` | Single-line semver string | | `Makefile` | Build, test, lint, cross-compile targets | | `Dockerfile` | Multi-stage build for containerized obm | | `deploy.yaml.example` | Full YAML config reference | | `scripts/install.sh` | `curl \| sh` installer | | `scripts/release.sh` | Tag + push release automation | | `.github/workflows/ci.yml` | Test + build on push/PR | | `.github/workflows/release.yml` | Cross-compile + GitHub Release on tag | | `CHANGELOG.md` | Version history | | `CONTRIBUTING.md` | Dev setup, PR checklist, release process | | `README.md` | User-facing overview (casual tone) | | `DETAILS.md` | Full technical reference | | `LLMs.md` | This file — agent-oriented reference |