Wire

The harborloop CLI: wire Harbor into your coding agents.

harborloop is the command line for Harbor: it wires your agents up, keeps them current, and tells you the truth about whether any of it is working. The first command needs no account.

Start here, with no account

harbor context needs no account, no token and no network. It reads the files your agents already load on every turn, prices them, and says who put each one there. Run it before you decide whether any of the rest of this is worth your time.

bash
npx harborloop context
harbor context~/acme-api
  always-on budget on this machine   at least ~542 tok / turn
    skills index (6)                 ~219   0 managed by harbor · 6 unowned · 0 from other tools
    skill files not indexed (2)         —   no description — nothing can select them, and nothing here can price them
    agent definitions (2)            ~115
    agent files (4)                  ~208
    MCP tools (0)                       —   tool descriptions live on the server — connect to price them
    injected context                    —   varies per session — no on-disk record to read

  managed by harbor: 0 of 6 · unowned: 6 · other tools: 0
  2 more files in a skills root carry no description — write one, or they are shelf-ware

Three of those lines carry a dash rather than a number, and the dash is the point. A skill with no description cannot be selected by anything, so nothing here can price it. Tool descriptions live on the server, so a machine with no connection cannot count them. Injected context varies per session and leaves no on-disk record. A zero in those places would be a claim we did not measure, and it would be the flattering one.

--verbose lists every skill with its own cost and owner. --json prints the same measurement for a script.

Install

You need a workspace first, because init signs in to it: sign up and name one. Then, with Node 18 or newer. The install is two packages: a small launcher and the compiled binary for your platform, picked by npm from the optional dependencies. There is nothing else to install and no desktop app required.

bash
npx harborloop init

init does three things: signs you in through your browser, installs Harbor’s MCP server and hooks for every agent it finds on the machine, and turns Harbor on in this repository, in your workspace’s only Space (it asks which when there are several). Run from npx, it also offers to install the harbor command, so the rest of this page works in any terminal.

On the way it may ask up to three questions:

  • Which Space does this repo belong to? With more than one Space. Enter is none for now: Harbor is on in no Space, and what the repo’s sessions learn waits in Review until harbor bind --project <Space> names one.
  • Turn Harbor on in https://github.com/acme/acme-api? Only in a workspace with other people in it and one Space, because what the agent learns here is shared with them. Enter is yes; --no-bind leaves the repo off without asking.
  • Send their rules to your team’s review queue? When the repo commits a CLAUDE.md, an AGENTS.md, a .cursorrules, Cursor rules in .cursor/rules/*.mdc, or a .github/copilot-instructions.md: at most 10 files a run, 64 KB each, the text as committed. Enter is yes. --import-rules sends without asking and --no-import-rules neither asks nor sends. Every rule waits in Review for a person.

Which config files does harborloop change?

Each agent’s own user-level config, and its own folder, ~/.harbor. It writes nothing into your repo. init adds a harbor MCP server entry and Harbor’s hooks to the files below, and leaves every other entry in them as it was.

Where init writes, per agent. These are the paths harbor doctor names when something is wrong.
AgentMCP configHooks
Claude Code~/.claude.json~/.claude/settings.json
Codex~/.codex/config.toml~/.codex/hooks.json
Cursor~/.cursor/mcp.json~/.cursor/hooks.json
GitHub Copilot~/.copilot/mcp-config.json~/.copilot/hooks/harbor.json

~/.harbor holds the hook scripts (in ~/.harbor/bin), your sign-in, and the list of repos Harbor is on in, which the hooks read before every prompt with no network call. Devin reads Claude Code’s hooks by default, so it gets Harbor through Claude Code’s entry; Gemini CLI and OpenCode run none of them, and harbor doctor says so.

harbor uninstall takes all of it back out: the hooks, the MCP entries and ~/.harbor. First it asks Harbor to cancel this machine’s sign-in and each agent’s key, so a copy kept anywhere else stops working, and it names any it could not cancel with the date it expires. Your config files keep everything else, and your workspace and its knowledge stay. If you installed the harbor command with npm, it ends by naming the one step it cannot run itself: npm uninstall -g harborloop.

Every command

harborloop has eighteen commands, in the order harbor help prints them.

CommandWhat it doesFlags
harbor initSign in, install the hooks, and turn Harbor on in this repo. Configures every agent it finds.--no-browser, --workspace <id>, --no-bind, --codex, --no-codex, --cursor, --no-cursor, --copilot, --no-copilot, --import-rules, --no-import-rules, --plugin <agent>
harbor install-hooksPut the hook scripts in ~/.harbor/bin and nothing else. What a cloud agent’s hook runs.--repo <path>
harbor updateBring this machine to the latest release, hooks included.--check
harbor doctorIs it actually working?--offline, --days <n>
harbor statusThis repo, from local files only.none
harbor contextWhat this machine pays for on every turn, and who put it there.--verbose
harbor bind [Space]Turn Harbor on in this repo. On a repo that is already bound, naming another Space moves it there.--project <Space>, --import-rules, --no-import-rules
harbor workspacesWhich workspaces you can reach, and the one this machine uses.none
harbor dailyWhat the hooks run once a day: renew the sign-in, report this machine’s version, send repo facts, check for a newer release.none
harbor offPause this repo. In a folder that is not a repo, pause every such folder on this machine.--capture, --receipt, --global
harbor onResume.--receipt, --global
harbor check "<cmd>"Which guardrail stops this command here, and what the agent would read. Runs nothing, sends nothing.--
harbor guardrail test [rule]How often each rule would have fired over this machine’s agent history.--days <n>, --share
harbor allow-once <code>Let the one call a guardrail just refused run once, with your reason on the rule’s record.--because "<why>"
harbor dispute <code> "<why>"Tell a guardrail’s author it refused something it should not.none
harbor loginSign in again, or switch this machine to another workspace.--no-browser, --workspace <id>
harbor logoutRemove every credential on this machine, including the one in each agent’s config that the hooks read, after asking Harbor to cancel them.none
harbor uninstallTake Harbor off this machine: hooks, MCP entries and ~/.harbor. Your workspace and its knowledge stay.none

Two more answer without a row of their own. harbor help prints this list, and --help on any command prints it without running anything. harbor version (or --version) prints the release.

What each flag does

FlagOnWhat it does
--no-browserinit, loginPrint a sign-in URL instead of opening a browser. Open it on any machine, sign in, and paste the code the page shows back into the terminal. For a remote shell or a container; it needs a terminal to paste into.
--workspace <id>init, loginUse that workspace, with no picker. harbor workspaces lists the ids. With login it switches the workspace and needs no browser.
--no-bindinitSet up the machine and leave this repo off.
--codex, --cursor, --copilotinitWire that agent even though init did not find it, for example because you are about to install it.
--no-codex, --no-cursor, --no-copilotinitLeave that agent alone even though it is installed. harbor update keeps the choice when it re-runs init.
--import-rulesinit, bindSend the repo’s committed rules files to Review without asking.
--no-import-rulesinit, bindNeither ask nor send.
--plugin claude|codex|cursorinitWhat Harbor’s plugin runs when you sign in from inside the agent (/harbor:login, or $harbor:login in Codex). It wires that one agent and leaves the hooks to the plugin. You do not type it yourself.
--repo <path>install-hooksThe repo whose .harbor/ files name where Harbor is. What a cloud agent’s hook passes.
--project <Space>bindThe Space to turn Harbor on in, or to move a bound repo to. harbor bind <Space> is the same.
--checkupdateReport whether this machine is current and change nothing. The form for a scheduled job or a shell prompt.
--offlinedoctorSkip the network. The lines that need it say not checked or are left out.
--days <n>doctor, guardrail testThe window, in days. For guardrail test it is 30 unless you set it, and at most 365.
--verbosecontextList every skill with its own cost and owner.
--captureoffKeep recall, record nothing.
--receiptoff, onHide or show the receipt and the save chip on this machine. Recall and recording stay as they are.
--globaloff, onEvery repo on this machine. on --global leaves a repo you paused by itself paused.
--shareguardrail testSend the rule, the window and the two counts to the workspace, so the rule’s row on Guardrails shows the dry run. Nothing else is sent.
--because "<why>"allow-onceYour reason, written on the rule’s record. Required.
--checkEverything after it is the command to check, flags included: harbor check -- git push --force.
--jsonevery command but helpThe same answer as JSON, for a script or a CI step. harbor bind --json asks no questions.
--cwd <dir>every commandRun as if from that folder.
--debugevery commandWhen a command fails, print the full stack trace instead of one line.
--help, -hevery commandPrint the usage and run nothing, whatever the command. harbor help is the same.
--version, -vno commandPrint the release. harbor version is the same, and takes --json.

Commands only you can run

allow-once, bind, dispute, login, logout, off, on and uninstall each change what Harbor does on this machine or carry your word, so Harbor’s own hook refuses them when an agent runs them. The agent is told harbor bind is a person’s decision, so a person types it in their own terminal, and asks you instead. --help on any of them still works for an agent, because it only prints.

What does harbor doctor check?

harbor doctor checks the whole chain, from the endpoint and your sign-in to whether a prompt in this repo actually received anything, and it is built to be able to say no. It is the one command worth running when something feels wrong.

harbor doctor --offline~/acme-api
  Endpoint        ✓ https://app.gethrbr.com/v1
  MCP target      ⚠ no harbor MCP server registered — tool calls reach no graph
                    ↳ harbor init
  Signed in       ✗ no credential on this machine
                    ↳ harbor init
  Token           ✗ no MCP bearer in ~/.claude.json or ~/.codex/config.toml or ~/.cursor/mcp.json or ~/.copilot/mcp-config.json
                    ↳ harbor init
  Hooks           ✗ not installed — nothing runs on a prompt
                    ↳ harbor init
  Codex           ⚠ installed on this machine, but not configured — its sessions get nothing
                    ↳ harbor init
  Cursor          ⚠ installed on this machine, but not configured — its sessions get nothing
                    ↳ harbor init
  Copilot         ⚠ installed on this machine, but not configured: its sessions get nothing
                    ↳ harbor init
  This repo       ✗ Harbor is off here: https://github.com/acme/acme-api is not bound
                    ↳ harbor bind (if this repo should use Harbor)
  Sent to harbor  ✓ once a day: this machine's id, hostname, OS and harborloop version, and the tools, scripts and deny rules each connected repo commits. Never file contents.
  Recording       · not configured
  Version         · not checked (--offline)
  Recall          · not checked (--offline)
  Fit             · not checked (--offline)
  Attribution     · not checked (--offline)
  Contributed     · not checked (--offline)
  Recall delivery · no prompts recorded yet

That is a machine with Claude Code, Codex, Cursor and Copilot installed and nothing set up, which is the run worth printing: every failing line carries the command that fixes it, and no line claims a state it did not check. A dot means not measured: Recording has nothing to record yet, and Recall delivery has seen no prompt.

Three things doctor refuses to do

  • Report a partial install as healthy. Hooks registered for only some of their events is a warning naming the ones that are missing and what each of them would have done, not a green tick.
  • Report a deliberate pause as a fault. A repo you turned off with harbor off reads as paused, on purpose. An error there would train you to ignore the output.
  • Print a number it did not measure. Under --offline the five measured lines say not checked. A dash is not a zero, and the two must never render the same.

When This repo is not a tick

It saysWhat it means, and the fix
Harbor is off here: https://github.com/acme/acme-api is not boundNobody bound this repo. harbor bind, if it should use Harbor; a personal or client repo can stay off.
not a repo: Harbor is off hereA folder with no git origin, and the workspace sends such work nowhere. An admin can turn it on: Settings, Spaces, Work outside a repo. Your home folder stays off either way.
https://github.com/acme/acme-api: you're not in Payments, so its rules and guardrails are offThe repo is bound to a Space you cannot read. Ask an admin to add you.

What the measured lines mean

The lines below are the reason doctor is more than a config linter. Every one of them needs the network, which is why the run above either marks them not checked or omits them. Apart from Version, each covers a recent window, which --days sets. Recall names its window and whether it counts this project or the whole workspace, because a reader who assumes the wrong one is reading a smaller number than they think; Corpus and Cost are always workspace-wide.

LineWhat it answers
RecallHow many sessions there were, and how many of them received anything.
FitThe average bundle size, and how many served rules went uncited. Warns when fewer than half were cited.
AttributionWhether every session here is being counted at all. An unkeyed recall is invisible to the loop, so this line is about the instrument rather than the result.
SurfacesWhich surfaces the recalls arrived on, each with how many of them were counted.
ContributedWhat this repo has captured: how many learnings, how many approved, how many still pending review.
CorpusWhat the brain added and retired, and the commonest reason a rule left. Always workspace-wide.
CostWhat Harbor’s own model calls spent writing rules, per rule an agent cited. Always workspace-wide.
VersionWhether this machine is behind the current release. It asks the npm registry every time.

Fit is the one worth staring at, and checking whether your agent follows team rules explains what to do about it. A rule that is served every day and never cited is a rule to retire, not a rule to reword. A cite is what the agent says it used, and agents claim more uses than really changed their work, so read a cited count as an upper bound.

Receipt, and Guardrails

Two more lines appear once init has run, and they are about things you can see rather than things you can measure. Receipt says whether this machine shows you the receipt. On a machine with all four agents it reads on (not in Cursor and Copilot - those hosts have no line for it). Switched off, it reads off - rules still reach the agent; you do not see which ones it used, marked ⏸ with harbor on --receipt as the fix, because a choice is not a fault.

Guardrails reports what this machine would refuse. none on, nothing counted is the resting state of a new workspace: no rule is on, so no command is watched or blocked. The counts beside it separate the two reasons a rule might not fire, which are that this machine has not fetched the workspace’s rules yet and that the workspace has turned none on. While a rule is refusing commands, Claude sandbox and Codex sandbox lines say whether the agent could write ~/.harbor and so switch those rules off itself, and the settings that stop it. What a rule is, what a refusal hands back and the switch that has to be on for any of it to happen are in blocking risky agent commands with hooks.

Lines for other agents

init wires Claude Code, Codex, Cursor and GitHub Copilot. doctor names the other agents it finds too, so a gap is a printed line and not a silence.

LineIt saysFix
Devinruns Harbor through Claude Code's hooks, guardrails includedNone needed: Devin reads Claude Code’s hooks by default.
Devinset not to read Claude Code's config, so Harbor's rules and guardrails do not run in itset read_config_from.claude to true in ~/.config/devin/config.json
Gemini CLI, OpenCodeon this machine, and Harbor does not cover it yet: its sessions get no team rules and no guardrailsNone yet.
VS Codeagent hooks are turned off ("chat.useHooks": false), so Harbor runs nothing in VS Code's agent modeset "chat.useHooks": true in VS Code's settings

Sent to harbor

The line reading Sent to harbor is an inventory of what leaves the machine once a day: its id, hostname, OS and harborloop version, and the tools, scripts and deny rules each connected repo commits. Never file contents. It is printed on every run rather than buried in a policy page, because a tool that reads your repository should say what it takes every single time you ask it anything.

--json gives the same checks as structured output, for a CI step that should fail when the loop is broken.

What does the receipt show?

The receipt is the short note Harbor prints into your own Claude Code or Codex session to say what it did. The agent does not write it. It comes in two places.

After an answer: the team rules it used. The rules Harbor hands your agent are numbered, and an answer that used any ends with a line like harbor-applied: #3 #7. At the end of the turn, Harbor prints what those numbers were, each with what kind of rule it is and where it came from:

end of turnClaude Code · ~/acme-api
⚓ Harbor: your agent used 2 team rules
   #3 Money is integer cents
      rule · via GitHub · acme/acme-api#312
   #7 Validate input with zod
      rule

It names up to five, then a line like + 2 more for the rest. Only rules this session was sent count: a number the agent read in a search result is left out rather than guessed at. A turn that used none prints nothing.

Under a save: where it went. When the agent saves a learning, the line under the call says what Harbor did with it:

after a saveClaude Code · ~/acme-api
⚓ Harbor saved a rule
   No default exports
   Your team's agents get it from their next session.

The other endings: It replaced an older rule. Your team’s agents get it from their next session.; held a rule for review with It reaches your team once someone approves it in Review. or It contradicts a live rule, so both wait for a decision in Review.; and saved your preference with Only your own sessions get it.

Both are on by default since harborloop 0.6.12. harbor off --receipt turns both off on this machine, and harbor on --receipt turns them back on. Recall and recording are not touched, and the reply says so:

harbor off --receipt~/acme-api
This machine: the receipt is off. Rules still reach your agent, and its answers still end with harbor-applied.
This machine: recall on, recording on.

Read the count as an upper bound. It lists what the agent says it used, and agents claim more uses than really changed their work.

harbor status

status is the small, local, no-network answer to “is this repo wired up?” It reads files on disk and nothing else, so it is instant and it works on a plane. It prints one line per agent it finds, Copilot included.

harbor status~/acme-api
  Workspace ✗ not signed in
              ↳ harbor init
  Repo      ✗ https://github.com/acme/acme-api: not bound
              ↳ harbor bind
  Hooks     ✗ not installed
              ↳ harbor init
  Codex     ⚠ installed here, but not configured
              ↳ harbor init
  Cursor    ⚠ installed here, but not configured
              ↳ harbor init
  Copilot   ⚠ installed here, but not configured
              ↳ harbor init
  Recording · not configured

Binding a repo

Harbor is on only in repos you bind. Run harbor bind inside a repo to turn it on.

With one Space in the workspace, the repo goes into it. With several, bind asks which, or you name one: harbor bind --project <Space>. If the repo commits rules files it asks the same question init does, once, before anything leaves the machine:

harbor bind~/acme-api
This repo commits CLAUDE.md and AGENTS.md.
Send their rules to your team's review queue? Harbor reads the text
with a model (keys and tokens are blanked first), and nothing reaches an
agent until someone on your team approves it. [Y/n] n
Harbor is on in https://github.com/acme/acme-api, Space "Backend".
1 repo in this workspace has Harbor on.
Rules: CLAUDE.md and AGENTS.md not sent, as you chose. `harbor bind --import-rules` sends it later

Enter is yes, and the summary then says how many rules wait in Review, with the link. On a repo that is already bound, naming a different Space moves it there. Moving a repo takes the repo.bind capability, which owners, admins and curators hold. Scoping rules by repo and team with Spaces has the rest.

In a repo Harbor is off in, Claude Code and Codex say so once, on the first prompt there: ⚓ Harbor is off in this repo, so your agent gets nothing from Harbor here. To turn it on, run harbor bind. An agent cannot run bind for you; it hands you the command.

Pausing a repo

Plenty of sessions are throwaway, and none of that belongs in your team’s graph. harbor off stops both halves: no context in, nothing recorded.

harbor off~/acme-api
This repo (https://github.com/acme/acme-api): paused. No context in, nothing recorded.

--capture pauses only the recording, so you keep recall while you experiment.

harbor off --capture~/acme-api
This repo (https://github.com/acme/acme-api): recall on, recording off.
harbor on~/acme-api
This repo (https://github.com/acme/acme-api): recall on, recording on.

--global applies the pause to every repo on the machine. The pause is read from a local file before any network call, so it takes effect immediately and holds with no connection. Only you can pause or resume: an agent’s harbor off or harbor on is refused.

In a folder that is not a git repo, harbor off pauses every such folder on this machine: Harbor is off in folders outside a repo on this machine. Run harbor on in one of them to turn it back on. In your home folder itself neither verb changes anything: Harbor is already off in your home folder.

Workspaces

harbor workspaces lists the workspaces this account can reach, with their ids, and marks the one this machine is using with a *. Switching needs no browser:

bash
harbor login --workspace <id>

--no-browser prints a sign-in URL instead of opening a browser: open it on any machine, sign in, and paste the code the page shows back into the terminal. That is the path for a remote shell or a container.

Staying current

harbor update brings the machine to the latest release and re-points the installed hooks at it. That second half matters more than it sounds: hooks are recorded by path, so a binary that moved leaves scripts that are listed, enabled, and doing nothing.

harbor update --check~/acme-api
harborloop 0.6.15 is the latest release.
The installed hooks do not point at this binary. `harbor update` re-wires them.
No agent on this machine is set up to run the hooks, so nothing is recalled or recorded.
`harbor update` re-runs `harbor init`, which registers them. `harbor doctor` has the detail.

--check reports and installs nothing, which is the form for a scheduled job or a shell prompt.

You also hear about a new release without running anything. When one is out, Claude Code and Codex show ⚓ harbor <version> is available. Run: harbor update when you submit a prompt. On a machine that did not install harborloop with npm, it names npx harborloop@latest init instead. harbor off --receipt does not hide it, because on a machine where nobody runs a harbor command, it is how you hear about an update.