Skip to content

Local agents

Mossbear has two halves. Guides go out to your agent, and what the agent did comes back to be graded. The first half works anywhere your guide files are read. The second needs hooks, and hooks are per-agent.

This page covers the agents you run on your own machine. For the same setup inside an ephemeral container — Claude Code on the web, Codex cloud, CI — see cloud agents. The hook configuration is the same artifact in both places; what changes in a container is install, credentials, egress and freshness.

Which agents get delivery, logging and grading?

Section titled “Which agents get delivery, logging and grading?”
AgentGuide deliveryAction loggingSession closureGradingWired by
Claude Codeyesyesyesyesmossbear init
Claude Code on the webyesyesyesyesa setup script, then mossbear init
Codexyesyesyesyesmossbear init, then trust the project
Antigravity CLIyesyesserver’s idle sweepyes, latermossbear init --platform antigravity
OpenCodeyesyesserver’s idle sweepyes, latermossbear init
Cursoryesnonononothing to wire

Grading follows session closure, which follows action logging. A row cannot have a later column without the ones before it.

Antigravity CLI and OpenCode have no SessionEnd, so their sessions close through the server’s idle sweep and their verdicts arrive later. Codex uses its SessionEnd hook to close the session.

Transcript narration and token usage are extracted from Claude Code, Codex, Antigravity, and OpenCode transcripts (with user turns and closing self-reports also captured when a session closes through SessionEnd in Claude Code and Codex).

Bundles you pull or subscribe to with --deliver global land in your machine-wide skills folders, so they reach every repo you open. Each agent reads them from its own place:

AgentReads Mossbear’s global skills fromDelivered
Claude Code~/.claude/skills/yes
Claude Code on the web~/.claude/skills/yes
Codex~/.agents/skills/yes
OpenCode~/.agents/skills/ and ~/.claude/skills/yes
Antigravity CLI~/.agents/skills/ (via ~/.gemini/config/skills.json)yes
Cursor—no

Delivery starts when you turn on Deliver my global skills in your dashboard settings, or when you answer yes to mossbear init’s question on a machine. A machine’s own answer wins over the setting; to change it, run mossbear init --ask-global there.

Mossbear never writes into a skill folder it did not create. If you already have a skill with the same name, Mossbear leaves yours alone and names it when it syncs.

To let Codex or Claude Code use Mossbear’s MCP tools, install the chosen agent’s CLI and register the server once for your user account:

Terminal window
mossbear connect --platform codex --scope user
# Or:
mossbear connect --platform claude_code --scope user

Restart the agent client and check its MCP tools afterward. The command checks the saved registration; it does not test an active connection. An existing custom or disabled Mossbear entry is kept unless you pass --replace. Replacement removes that entry before installing the new one.

You can also include registration in unattended repo setup:

Terminal window
mossbear init --platform codex --yes --install-mcp --mcp-scope user

Without --install-mcp, unattended setup prints the registration command. Use --no-install-mcp to skip the interactive offer. Project-scope registration is not yet supported by these options.

If an agent still has no Mossbear tools, the server may be unregistered, disabled, failing to start, or waiting for the client to reload. The bundled skills tell the agent not to guess which one it is. They also tell it to finish what the CLI can do (mossbear search, artifact reads and updates, mossbear comments, mossbear pull) and to say plainly what needs the tools: the inbox, creating bundles, a finding’s evidence and resolving comments.

mossbear init writes everything. It registers a PostToolUse hook and a PostToolUseFailure hook that log each tool call, a Stop hook that runs mossbear report to upload them, a SessionEnd hook that runs mossbear complete to tell the dashboard the session is over so it can be graded and to send back the artifacts you edited under .mossbear/, and a SessionStart hook that installs the current release and then runs mossbear refresh, so a session opens with this repo’s subscribed bundles already current.

mossbear init --no-auto-update writes that last hook without the install clause, and rewrites an auto-updating entry init wrote earlier.

Every one of those goes into .claude/settings.json. The commands are bare, resolved through PATH, so the settings file carries nothing machine-specific and is safe to commit.

SessionStart earns its place twice over in a cloud session: the environment installs the CLI once and never re-runs that script, so the same hook is also what updates the CLI in a resumed container. It runs the same way on a laptop, so --no-auto-update is the way to keep a machine on the release you chose. See cloud agents.

After upgrading Mossbear, re-run mossbear init to refresh its settings. It merges its own entries without replacing settings you added.

Install Mossbear once, then set up each repository you want it to cover:

Terminal window
npm install -g mossbear@latest
cd your-project
mossbear init --platform codex

init writes the repository’s .codex/config.toml. Commit that file so teammates and other machines get the same hooks.

If you want Mossbear to run in every local Codex project, add these hooks to ~/.codex/config.toml. That skips each project’s trust step, but not the hook review: Codex runs a hook only after you trust it in /hooks, and asks again whenever it changes. The SessionStart hook refreshes the project’s context and checks for updates when Codex runs in an ephemeral environment.

[[hooks.SessionStart]]
matcher = "^(startup|resume)$"
[[hooks.SessionStart.hooks]]
type = "command"
command = "bash -lc 'mossbear update; mossbear refresh || true'"
[[hooks.PostToolUse]]
matcher = ".*"
[[hooks.PostToolUse.hooks]]
type = "command"
command = "bash -lc 'mossbear-hook --harness codex'"
[[hooks.Stop]]
matcher = ".*"
[[hooks.Stop.hooks]]
type = "command"
command = "bash -lc 'mossbear report || true' >/dev/null"
[[hooks.SessionEnd]]
[[hooks.SessionEnd.hooks]]
type = "command"
command = "bash -lc 'mossbear complete || true'"
timeout = 3

This is a machine-wide choice: it records and syncs activity from every local Codex project using your Mossbear account. Restart Codex after changing the file, then open /hooks and trust the Mossbear hooks. mossbear doctor names any it finds unreviewed.

  • SessionStart refreshes this project’s context and checks for updates in ephemeral environments.
  • PostToolUse records each tool call.
  • Stop syncs recorded activity.
  • SessionEnd marks the session complete so it can be graded. Codex allows a SessionEnd hook 3 seconds at most. The Stop hook has already uploaded each turn, so this is usually plenty; if it is not, the session closes a little later on its own.

The || true keeps an upload problem from interrupting your work. Mossbear leaves unsent activity queued and sends it on a later successful sync.

Guides in AGENTS.md and skills in .agents/skills/ work out of the box. agy reads AGENTS.md at your workspace root and discovers skills in .agents/skills/, so a repo that has run mossbear init --platform antigravity and mossbear refresh hands those over with no extra configuration. When global skill delivery is enabled and ~/.gemini/config/ exists on your machine, Mossbear also registers ~/.agents/skills in ~/.gemini/config/skills.json so Antigravity discovers your global skills across every workspace.

Hooks are wired with --platform antigravity. Run:

Terminal window
mossbear init --platform antigravity

That writes .agents/hooks.json with a SessionStart hook that keeps the CLI and this repo’s Mossbear files current, a PostToolUse hook that logs each tool call, and a Stop hook that runs mossbear report to upload them. The commands are bare, resolved through PATH, so the file carries nothing machine-specific and is safe to commit.

init does not turn Antigravity on automatically the way it does for Claude Code and Codex, and the reason is that .agents/ is not a reliable signal. It is Antigravity’s customization directory, and it is also where Mossbear projects skills and dashboard-authored guides — so a .agents/ directory in your repo may be one Mossbear itself created. Detection looks for agy on your PATH instead, which says the tool is installed but not that you want it wired here, so Antigravity is listed as an option and left for you to pick.

Why the hook entry names the harness. Every harness’s entry names itself — the flag is how a session records which tool produced it — and for Antigravity it also maps its payload and tool names onto Mossbear’s action vocabulary. Antigravity calls its payload fields conversationId, toolCall.name and toolCall.args (Path, AbsolutePath, TargetFile, SearchPath, SearchDirectory, CommandLine), and its built-in tools run_command, edit_file/replace_file_content, write_file/write_to_file, read_file/view_file, grep_search, find_by_name, read_url_content, and search_web. With --harness antigravity, mossbear-hook maps those to Bash, Edit, Write, Read, Grep, Glob, WebFetch, and WebSearch, records a read on a skill’s SKILL.md as a skill load, and reads Antigravity’s conversation transcripts under ~/.gemini/antigravity*/brain/<conversationId>/.system_generated/logs/transcript.jsonl (falling back to transcript_full.jsonl when a step has truncated_fields) for narration and token usage.

If you hand-wrote your hooks file before this shipped, mossbear doctor says so — it reports an Antigravity logger entry missing its --harness antigravity flag rather than counting it as wired. Re-run mossbear init --platform antigravity after adding the flag, or add it yourself.

Connecting the MCP server. To give Antigravity access to your bundles and inbox over MCP, add mossbear mcp to ~/.gemini/config/mcp_config.json (or .agents/mcp_config.json in a project):

{
"mcpServers": {
"mossbear": {
"command": "mossbear",
"args": ["mcp"]
}
}
}

What differs from Claude Code. Antigravity has no SessionEnd event — Stop fires after every turn, so it can only ever say “here are more actions”. Your sessions are closed by the server’s idle sweep, which means the verdict lands later rather than not at all. When Antigravity runs commands inside its macOS Seatbelt terminal sandbox, ~/.mossbear/runs may be unreadable from inside the sandboxed shell while the host-executed PostToolUse and Stop hooks still read and sync it normally.

OpenCode has no command hooks. It loads plugin modules from .opencode/plugins/, so mossbear init writes one: .opencode/plugins/mossbear.ts. init wires it on its own when the repo has an .opencode/ directory; mossbear init --platform opencode wires it where there is none yet.

The plugin is a shim. It holds no logic of its own, only the commands it runs:

OpenCode eventRunsWhat for
tool.execute.aftermossbear-hook --harness opencodelogs each tool call
session.idlemossbear reportuploads what was logged, after each turn
session.createdmossbear update; mossbear refreshkeeps the CLI and this repo’s Mossbear files current

The commands are bare and resolved through PATH, so the file carries nothing machine-specific and is safe to commit. The plugin passes OpenCode’s own hook arguments to mossbear-hook as they arrive, and the CLI reads them, so a fix to how OpenCode’s tools are recorded reaches you with mossbear update rather than a re-run of init. Anything that fails, including a missing mossbear binary, is swallowed so it never interrupts your session. Subagent sessions are skipped at session.created, because they are part of the session that started them. OpenCode does not wait for a plugin’s event handlers, so the session-start refresh runs alongside your first turn rather than strictly before it.

Mossbear owns this file. mossbear init rewrites it whole, which is how a newer plugin reaches a repo that already has one, so edits outside its mossbear:hooks block do not survive a re-run. If you want your own OpenCode plugin, put it in its own file beside this one. If a file at this path was not written by Mossbear, init leaves it exactly as it is and says so. To stop Mossbear in OpenCode, delete the file.

mossbear doctor reads the plugin’s hook block, so it reports OpenCode as wired or not the same way it does every other agent here.

What you do not get. session.idle fires whenever the agent stops and waits for you, which is after every turn, not at the end of a session. Closing a session there would cut one piece of work into a session per pause, so OpenCode sessions close through the server’s idle sweep and their verdicts land later. Transcript narration is quiet here too: it is derived from a Claude Code transcript’s structure.

This is the row to read before you conclude something is broken.

Cursor’s guide files are discovered and imported. .cursorrules and .cursor/rules/ are both on the list mossbear link scans, alongside AGENTS.md, CLAUDE.md, .agents/, .claude/rules/ and .claude/skills/. So guides go out to Cursor and come back from it exactly as they do anywhere else.

There is no hook wiring for Cursor — it has no lifecycle hooks for Mossbear to register, so init has nothing to write and --platform cursor is refused rather than accepted and ignored. No tool call is ever logged, no session is ever closed, and nothing is ever graded.

What that looks like from the outside is success. Your guides sync. mossbear status prints your guide count and a pending count of zero, because pending actions are the ones logged since the last upload and nothing is logging any. Zero is what a healthy, fully uploaded project prints too. mossbear doctor is the one place the gap is visible: it reports the hooks as not configured. The sessions list stays empty, and no error ever appears to search for.

If you want verdicts from a Cursor project today, run the same repo through an agent in one of the rows above. The guides are the same guides.

Guide delivery and grading are one product. The context layer is a separate one, and it is not tied to any of the rows above: mossbear mcp exposes your bundles and inbox over stdio to anything that speaks the protocol. See context layer.