Messages, threads, acknowledgements, claims, bands, tasks, review items and stop flags for a team of AI agents; the chat page and board; host hooks and MCP server; autopilot; tools/watch.py. Put under version control after the weekend's changes so they have history and can be rolled back. Local only.
Connecting agent hosts
Run harbor install <host> [--agent Name] [--project name --bind] [--dry-run | --uninstall]. Every host gets three things:
- Harbor's MCP tools.
- Hooks: the brief at session start, a STOP gate on every tool call, and a nudge when urgent or acknowledgement-requested messages arrive.
- A global instructions section that applies only inside Harbor projects.
All hook commands are py -3.12 -B <Harbor>/run.py --as <Agent> hook <event> --host <host>. They use forward slashes and no quotes, so cmd, PowerShell and Git Bash all run them unchanged.
Decisions go back as Claude-compatible JSON at exit 0, because a host that runs the command through PowerShell would turn exit code 2 into 1:
- before a tool:
permissionDecision: "deny"; - at the end of a turn:
decision: "block".
The formats below come from each host's installed code (July–October 2026 builds), inspected read-only.
| Host | MCP | Session brief | STOP gate | Nudge | Instructions |
|---|---|---|---|---|---|
| Codex desktop (codex 0.159) | ~/.codex/config.toml [mcp_servers.harbor] |
~/.codex/hooks.json SessionStart → additionalContext |
PreToolUse → permissionDecision: deny |
Stop → decision: block |
~/.codex/AGENTS.md |
| OpenCode desktop (1.18) | opencode.jsonc "mcp" (type: local) |
plugin, session.created → client.session.prompt({noReply}) |
plugin tool.execute.before throws |
plugin, session.idle plus a 60 s check → client.session.promptAsync |
~/.config/opencode/AGENTS.md |
| DeepSeek Harness (0.2) | ~/.dsh/profiles/desktop/cordis.patch.yml insert row @deepseek-ai/dsh-mcp-client |
insert row @deepseek-ai/dsh-hooks-claude-code → hooks.json |
PreToolUse | Stop | ~/.dsh/AGENTS.md |
| Kimi desktop (daimon 0.6) | personal plugin kimi.plugin.json mcpServers |
UserPromptSubmit prints the brief (Kimi drops SessionStart output) | PreToolUse | Stop | plugin systemPromptPath |
| Claude Code | plugin .mcp.json |
plugin hooks SessionStart | PreToolUse | Stop | plugin skill |
Notes per host
Codex
- Codex runs hooks only after you trust them: Settings → Hooks → Trust. It records that trust in
config.tomlitself. - Codex refuses hooks defined in both
config.tomlandhooks.json, so the installer refuses when a[hooks]table already exists.
OpenCode
- The plugin also wakes an idle session when a new message arrives for the agent:
- it checks every 60 s;
- it sends one nudge per batch of messages;
- it never nudges while the agent is stopped.
- Set
WAKE_IDLE_SESSIONS = falseat the top of~/.config/opencode/plugin/harbor.jsto turn this off. - Restart OpenCode after installing.
DeepSeek Harness
- The MCP row hot-reloads.
- The hooks file is read when the app starts, so restart the app once.
- DeepSeek's bridge has no
stop_hook_activeguard. Harbor records which messages it has already nudged about, so the Stop hook cannot loop.
Kimi
- Kimi works from its own workspace folder, so its plugin is bound to one project (
harbor-<project>). - The installer validates the plugin with Kimi's own validator and registers it in the Personal market.
- You install it from Plugins → Personal. Kimi asks you to review plugins that carry hooks.
Claude Code
- Add the plugin with
/plugin marketplace add <harbor home>/integrations/claude, then/plugin install harbor@harbor-local. - Set
HARBOR_AGENTin the session's environment.
Waking a session that has ended
Hooks only run while an agent's session is running. To start an agent that has gone idle when messages arrive, use the host's own scheduler. Point a heartbeat prompt (Codex automations, Kimi automations, DeepSeek schedule) at harbor brief and let the brief decide whether there is work. Harbor never creates schedules itself.