Local development

Get the control plane and the agent building, running, and tested on your machine — the exact commands CI runs.

Local development

Two codebases you'll work in: the control plane (control-plane/web, Next.js/TypeScript, npm) and the agent (agent, Go, zero dependencies). This page gets both running and shows the exact verification commands — which are the same ones CI runs, so "green locally" means "green in CI."


Prerequisites

  • Node 22 and npm (control plane; the secondary dashboard/ app uses pnpm 9).
  • Go 1.23+ (agent; CI pins the 1.24 toolchain).
  • Docker (to actually run a deploy locally; not needed for the test suites, which fake it).
  • Optional: Postgres (the control plane runs against an in-memory backend without DATABASE_URL, which is how the tests run).

Control plane

cd control-plane/web
npm ci
npm run dev          # Next.js dev server

Without DATABASE_URL the app uses a seeded in-memory backend — the dashboard and Slot Board are real even in a fresh checkout. Point it at Postgres by setting DATABASE_URL (and, for the least-privilege model, MIGRATIONS_DATABASE_URL).

Verification (run before every PR — this is the CI order):

npm run lint         # eslint .
npm run typecheck    # tsc --noEmit
npm test             # vitest run
npm run build        # next build

Focused test file: npx vitest run lib/platform/store.test.ts (or npm test -- <path>).

Key environment variables for local runs (all optional; features stay dark until set):

VarEnables
DATABASE_URL / MIGRATIONS_DATABASE_URLPostgres persistence + the app/migrator role split
AUTH_SECRETsession signing (required in production)
HOSTSSH_ENC_KEYsealing/unsealing secret env
HOSTSSH_LICENSE_KEYSwhich license the control plane dispatches jobs for
ANTHROPIC_API_KEYthe AI copilot (read-only fallback without it)
REDIS_REST_URL / REDIS_REST_TOKENRedis-backed rate limiting + scheduler lock (memory fallback otherwise)

Agent

cd agent
go build ./...       # build everything (module root is `.`, NOT ./cmd/...)

Build note: build from the module root .. The only cmd/ subcommand is cmd/hsmcp (the MCP scaffolder); main.go at the root is the agent binary.

Verification (the CI order):

cd agent
gofmt -l .                       # must print nothing
go build ./...
go vet ./...
go test ./... -race -count=1

Focused package: go test ./internal/deploy/ -race -count=1.

The agent has zero third-party dependenciesgo.mod is just the module + go lines, no require block. CI enforces this (a license-compliance gate rejects forbidden/restricted deps). If you need functionality, use the standard library or shell out to a system tool (docker, restic, nftables); don't add a module.

Running the agent against a box

Normal operation is the systemd service running hostssh agent. For local iteration you can run CLI commands directly (hostssh doctor, hostssh status), point at a control plane with HOSTSSH_CONTROL_PLANE_URL, and use HOSTSSH_CONFIG to select a config file. See docs/user/cli-reference.md for the command surface.


Migrations

Migrations live in control-plane/web/lib/migrations/, are forward-only and append-only, and are registered in list.ts. The runner checksums shipped migrations — never edit or reorder a shipped one. To add one, create the next number (check list.ts for the max), export a migration, append it to the array, and make sure list.test.ts passes. Details in Database & migrations.


Repo-wide checks

CI (.github/workflows/) runs:

  • hygiene — no secret-looking tracked files.
  • licenses — permissive-only deps (npm license-checker + go-licenses).
  • agent — build/vet/test -race + golangci-lint.
  • control-plane — lint/typecheck/test/build.
  • dashboard — pnpm lint/build/test.
  • security — gitleaks secret scan.

Match these locally and your PR is green before you push. See Testing & CI.


The workflow loop

The project tracks work in planning/:

  1. Read planning/MIGRATION-MASTER-PLAN.md (the program) and planning/TODO.md (the task board).
  2. Implement at the most upstream layer (see Build guards).
  3. Add the regression test.
  4. Run the verification commands above.
  5. Update the TODO and, if you fixed a class of bug, the build-guards catalog.

See Contributing for commit conventions and the PR checklist.