A control plane for AI agents doing ongoing work.
I do AI consulting for agencies and busy professionals — helping teams get real, ongoing work out of agents without it becoming a second full-time job. Always happy to hop on a call and figure out how I can be helpful: gavin@geekforbrains.com.
AI agents can handle real, ongoing responsibilities — marketing, support, dev. They post content, triage tickets, manage campaigns, submit PRs. Most of this runs on recurring schedules.
The problem is visibility. What jobs does each agent have? What ran today? What needs my attention? What broke?
Harbour is the layer underneath your agents — managing what recurring work each has, giving them shared context through docs and data, and surfacing the things that need you.
Harbour is polling-based — it never calls out to agents; they pull work on their own schedule.
- Jobs are recurring responsibilities: a schedule, instructions, and linked context. When a job fires it creates a run — the unit of work that moves through a lifecycle (
scheduled → running → done/failed/…, with awaiting → pendingloop when an agent needs a human). - Runners pull work from one endpoint —
POST /api/runner/claim(the Runner Protocol) — and get everything bundled: instructions, docs, tables, secrets, and pre-resolved API endpoints. The bundled runner drives Claude Code, Codex, or Gemini for agent jobs; a runner on another machine hooks in over the same protocol. - Workflows are deterministic scheduled shell commands — no agent, no LLM — claimed by the same runner that drives agent jobs. Agent jobs can also define a cheap prerun gate that skips a run when there's no work.
- Shared context — docs (markdown), tables (agent-managed SQLite tables), and secrets (encrypted env vars) — is linked to jobs and injected into each run.
It's multi-tenant: an instance admin owns the install, and work is organized into orgs → projects. Resources never cross org lines.
Going deeper: the concepts explain the model in prose, and docs/guide.md is the exact wire contract an agent reads at
/api/guide.
There's no web signup — the first admin is created from the shell (the operator has host access, so first-run setup belongs there). After that, admins create orgs, projects, and users from the dashboard.
All you need is Node 24 LTS on macOS or Linux.
git clone https://github.com/geekforbrains/harbour.git
cd harbour
npm install
npm run build
npm run harbour -- setup # one-time: create the instance admin + local runner (interactive)
npm start # run the serversetup also auto-provisions the local runner — it writes a runner token to ~/.harbour/runner.token and prompts to schedule the polling service. npm start runs the server; npm run harbour -- install schedules the runner (polls every 60s), or npm run harbour -- run drains all due work once.
Visit http://localhost:3000 and log in. All state (DB, uploads, encryption key) lives in ~/.harbour — back up that directory and you have everything. (For scripted installs, npm run harbour -- admin create --email <e> --name "<n>" --password <p> creates the admin and provisions the local runner non-interactively.)
See deploying to production for the Linux path — systemd units for the server and runner, with Caddy terminating TLS in front. On macOS, npm run release handles in-place launchd updates.
Built-in support for Claude Code, Codex, or Gemini CLI. Create a Harbour Agent in the dashboard (pick a CLI, model, and effort level), and the local runner (provisioned at setup) claims and runs it — nothing else to wire up. If you haven't scheduled the runner yet:
npm run harbour -- install # polls every 60s; logs at ~/.harbour/runner.logTo run an agent on another machine, give it a placement label and run a runner there advertising that label — it claims the agent's runs over the same Runner Protocol and drives the CLI locally. That remote runner is self-managed and needn't be Node: use the standalone harbour-agent, your own implementation in any language, or Harbour's bundled runner (enrolled with harbour connect). All of them speak the protocol at /api/runner-guide; the agent's spawned CLI sees the wire contract at /api/guide. Either way the agent has no key of its own — the runner token claims and a per-run exec token authenticates the work.
More: agents (eager polling, per-agent Claude Code permissions, model/effort overrides) and running a runner on a different machine.
Workflows are claimed by the same local runner that drives agent jobs — one runner handles both, so there's nothing extra to install. A workflow with no runner scheduled at all just sits queued until you run npm run harbour -- install (service) or npm run harbour -- run (one-shot).
More: workflows (runners, gates, the exit-code contract).
An admin API key lets a separate management agent operate Harbour itself — create agents, jobs, docs, tables, and more. Mint one in Settings → Admin API Keys; the agent fetches its reference at GET /api/admin-guide. See docs/admin-guide.md.
Captain is an in-browser chat with a server-side CLI tool — your operator's console for the harbour itself. Ask it to summarize today's runs, query the database, debug a stuck job, or set up a new agent without leaving the dashboard. → more.
Start with the docs map, which routes you to the right page. The PRD is the product north star — what Harbour is, the principles it holds to, and the roadmap.
- Concepts — agents, jobs & runs, workflows, orgs & projects, shared context, Captain, attachments
- Guides — getting started, running on a different machine, deploying to production
- Reference — architecture, database schema, API, design language
The wire contracts — docs/guide.md (worker agents) and docs/admin-guide.md (admin agents) — are served live and are the source of truth for on-the-wire behavior.
Next.js (App Router), SQLite (better-sqlite3), Tailwind / shadcn/ui, TypeScript. Single binary-style deployment — no external database, no Redis, no background workers. Just npm start.
All Harbour state lives under ~/.harbour by default — DB, uploads, encryption key, runner config. Back up that directory and you have a snapshot of everything.
| Variable | Description | Default |
|---|---|---|
HARBOUR_HOME |
Root directory for all Harbour state | ~/.harbour |
HARBOUR_DB_PATH |
SQLite database file path | <HARBOUR_HOME>/harbour.db |
HARBOUR_UPLOADS_DIR |
Run attachments directory | <HARBOUR_HOME>/uploads |
HARBOUR_ENCRYPTION_KEY |
64-char hex key for secret encryption | Auto-generated at <HARBOUR_HOME>/encryption.key |
HARBOUR_MAX_UPLOAD_MB |
Per-file upload cap in MB | 500 |
HARBOUR_SESSION_TTL_DAYS |
Dashboard session lifetime in days | 30 |

