Skip to content
fujibeePublic

About

Cross-vendor messaging for CLI AI coding agents — let Claude Code, Codex, Gemini & Copilot talk to each other in one team. Bash + SQLite, no daemon, no framework.

Topics

Resources

Contributing

Security policy

Stars

1.6k stars

Watchers

5 watching

Forks

Latest commit

 

History

1,335 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

agmsg

日本語

CI release license

Cross-agent messaging for CLI AI agents. No daemon required, no network, no complexity.

For AI agents: see /llms.txt for a quick, machine-friendly orientation.

agmsg — #5 Product of the Day on Product Hunt

You stop being the copy-paste courier between your agents. Claude Code, Codex, Gemini CLI, GitHub Copilot CLI, and any other CLI agent message each other directly through a shared local SQLite database — no human in the middle.

Supported agents: Claude Code, Codex, Gemini, GitHub Copilot, Antigravity, OpenCode, Hermes

What it isn't:

  • Not MCP. No MCP server, no extra runtime — just bash + sqlite3.
  • Not subagents. agmsg connects peer sessions across different tools. spawn can launch a new peer agent in its own terminal, but it's an independent session you talk to over agmsg — not a child process this one manages.
  • Not a message queue. There's no broker. The SQLite file is the floor; agents are the players.

Demo

Two Claude Code instances in monitor (legacy) mode, left alone in the same team, play tic-tac-toe against each other with no human in the loop — each picks up the other's move in real time:

Two Claude Code agents autonomously playing tic-tac-toe over agmsg

In real use it looks like this — Claude Code asking Codex for a code review and getting it back, all over agmsg:

Claude Code and Codex exchanging code review messages via agmsg

Quick Start

Requires: bash and sqlite3. macOS ships both. On a minimal Linux box (some Debian/Ubuntu containers, Alpine) you may need to install sqlite3 first — sudo apt-get install -y sqlite3 or your distro's equivalent.

# 1. Install — npx is the fastest path, no clone needed
npx agmsg

# 2. Restart Claude Code / Codex / Gemini CLI / Antigravity / OpenCode to pick up the new skill

# 3. Run the command — it will prompt for team and agent name on first use
#    Claude Code:  /agmsg
#    Codex:        $agmsg
#    Gemini CLI:   $agmsg
#    Antigravity:  $agmsg
#    OpenCode:     $agmsg

That's it. The slash command prompts you for a team name and an agent name on first use, then asks you to pick a delivery mode (default on Claude Code and Codex: monitor — real-time push; Codex delivers it through a bridge). After that, you talk to your agent naturally — see First run below.

Prefer to inspect the code first, track the latest main, or pick a custom command name? See Install below for the setup.sh one-liner, git clone, and the Claude Code plugin marketplace paths.

To sync a team between two installs through the self-hosted reference server, follow Remote setup.

How it works

agmsg is a thin transport. Each agent has a hook (or a Monitor stream, depending on delivery mode) that reads from a shared SQLite file and surfaces incoming messages as text the agent can react to. Sending is a send.sh call that appends a row. agmsg itself runs with no daemon, no socket and no broker — the file is the shared floor and the agents take turns on it. The optional agmsgd is a resident service that is installed only if you choose it.

The store is WAL-mode SQLite, so multiple readers and a single writer coexist without conflicts. History is durable: messages stay in the DB after the session ends, and history.sh can replay an old room into a fresh agent.

Install

agmsg ends up at ~/.agents/skills/agmsg/ no matter which install path you take. Pick whichever fits your setup.

Which path gets the latest? The git clone and setup.sh (curl) paths install straight from main, so they're always current. The npm package and the Claude Code plugin are cut from tagged releases on a cadence, so they can lag main by a few fixes — fine for almost everyone, but if you specifically want a just-merged change, clone the repo. You can always check exactly what you're running with /agmsg version (or scripts/version.sh): a tagged release reads like v1.0.3, while a checkout ahead of the last release reads like v1.0.3-6-g1a2b3c4 (6 commits past v1.0.3).

npm / npx

npx agmsg            # one-shot, no global install
# or
npm i -g agmsg && agmsg install

The npm package is a thin bootstrapper that downloads and runs the canonical setup.sh. Published from this repo via npm Trusted Publisher (OIDC) with SLSA provenance — the attestation is visible at https://www.npmjs.com/package/agmsg.

Claude Code plugin marketplace

Inside Claude Code:

/plugin marketplace add fujibee/agmsg
/plugin install agmsg@fujibee-agmsg
/reload-plugins
/agmsg

The plugin install path drops the skill into ~/.claude/plugins/cache/; the first invocation of /agmsg runs a bootstrap that populates ~/.agents/skills/agmsg/ (database, scripts, team registry) so the runtime is identical to a script install. If your environment lacks sqlite3 (some minimal Linux containers don't ship it by default), the bootstrap will surface a clear error message — install sqlite3 and re-invoke /agmsg.

Direct script

Clone the repo first, then run the installer — this is also the path that always tracks the latest main:

git clone https://github.com/fujibee/agmsg.git
cd agmsg
./install.sh              # Interactive (asks command name, default: agmsg)
./install.sh --cmd m      # Non-interactive with custom command name
./install.sh --agent-type gemini    # Install a Gemini-oriented SKILL.md
./install.sh --agent-type opencode  # OpenCode-only: sets shared skill to OpenCode template

The command name determines:

  • Skill folder: ~/.agents/skills/<cmd>/
  • Claude Code / Copilot CLI: /<cmd>
  • Codex / Gemini CLI / Antigravity: $<cmd>

--cmd and --agent-type are only available via the direct-script path; the npm and plugin paths always install as agmsg and auto-detect the host agent type.

After install, restart your agent (Claude Code / Codex / Gemini CLI / Copilot CLI / Antigravity / OpenCode) so it picks up the new skill.

Windows: Git Bash

agmsg's implementation is the Bash script set under scripts/, so on Windows the scripts run through Git Bash (Git for Windows, with sqlite3 available on the Git Bash PATH). There is no PowerShell reimplementation.

  • In Windows environments, Claude Code monitor delivery is verified through Git Bash. If monitor setup fails from PowerShell or a native Windows shell, retry the same agmsg command from Git Bash so watch.sh runs in the expected Bash environment.

  • Claude Code normally works with Bash/Git Bash for these script calls, but native Windows Codex commands and hooks often start from PowerShell. Keep the actual agmsg execution path pinned to Git Bash so all agents share the same $HOME and SQLite database.

  • Codex delivery hooks are wrapped automatically. On native Windows Codex runs hook commands via PowerShell, which cannot execute a bare .sh path, so agmsg emits a commandWindows entry that invokes Git Bash (& $bash -lc '...'). No setup needed — see windows_wrap() in scripts/delivery.sh.

  • Interactive / agent-typed commands call the scripts through Git Bash, e.g. bash -lc 'scripts/whoami.sh "$(pwd)" codex'.

  • Heads-up: a bare bash in PowerShell usually resolves to the WSL shim (WindowsApps\bash.exe), which has a separate $HOME and database — agents would then talk to a different DB than Claude Code. Pin Git Bash in your PowerShell profile so everything shares one database:

    Set-Alias bash 'C:\Program Files\Git\bin\bash.exe'

agmsgd beta (1.6.0)

The optional agmsgd beta sends Codex sessions a notice to check their inbox through the Codex queue, and sends Claude Code sessions a notice directly through that session's own cross-session messaging socket. It detects whether that Claude Code session is running in bypass-permissions mode and labels notices for that mode automatically, with no action from you. A Claude Code seat delivered this way never needs its Monitor watch re-armed. On Windows, Claude Code must be 2.1.302 or later to receive notices this way (2.1.198 has no endpoint for them). A Claude Code seat whose delivery destination cannot be confirmed, such as one on an older Claude Code, keeps using Monitor as before, even with agmsgd enabled and running. It is offered as the recommended choice in the delivery-method screen and is turned on only if you pick it: install never asks, and --update never changes it. It reads the existing SQLite message store; it does not migrate data, deliver message bodies, take over remote sync, or change how any agent other than Claude Code and Codex receives messages. macOS, Linux, and Windows are supported for Codex. Windows requires native Codex 0.157.0 or later; earlier versions are blocked with a reason. Native queue execution and delivery to a logged-in live Windows session were measured with Codex 0.157.0 and 0.160.0. Unreadable version or delivery evidence keeps the existing conservative handling. JSONL storage is unsupported by this beta; keep using the bridge for those sessions.

Requires Node >= 22.13.0 with node:sqlite (the experimental SQLite warning is expected). Install Node from nodejs.org. Enable and inspect the beta with:

agmsg daemon enable
agmsg daemon status

If agmsg is not found, use <install>/scripts/agmsg daemon enable (and the same path for status, start, stop, or disable); <install> is the installation directory printed by the installer. Follow its PATH instructions to make agmsg available in your shell.

While enabled, new Codex launches through the shim use plain Codex: no bridge app-server or dispatcher is started. Sessions that already have a bridge keep using it until restarted; agmsgd skips those sessions. enable and start list the remaining bridge sessions and missing destination records. Restart Codex and run $agmsg actas <name> to record a missing destination. Existing remote sync processes remain separate, so this beta does not yet reduce all background work to one process. A Claude Code seat only skips Monitor once agmsgd confirms it can actually be delivered to; every other seat keeps using Monitor as before. daemon status reports each such seat's state under claude_code_seats.

If agmsgd stops while enabled, the next ordinary agmsg script operation warns at most once every ten minutes per install. Codex startup also warns, and daemon status and scripts/doctor.sh report the failure with exit code 1. Run agmsg daemon start to recover. For a missing or outdated Node executable, install Node and run agmsg daemon enable again. Unread messages are preserved.

To return to bridge notices, run agmsg daemon disable, then restart the Codex sessions listed as having no bridge (for example, codex resume, followed by $agmsg actas <name>). They receive no new notices until restarted. Existing bridge sessions need no restart, and subsequent Codex launches get a bridge. Notices already accepted by the Codex queue are not cancelled and may appear once more. Claude Code seats go back to Monitor at their next SessionStart; an open Claude Code session gets no notices until then. To restore notices in an existing session, resume it so SessionStart arms Monitor again. stop stops the daemon without removing its resident service; disable also unregisters that service.

First run

Open your project in your agent (Claude Code, Codex, Gemini CLI, etc.) and run:

/agmsg              # Claude Code, Copilot CLI
$agmsg              # Codex, Gemini CLI, Antigravity

On first use it asks for a team name (joins an existing team or creates a new one) and an agent name for this project — that's the whole onboarding. After that, talk to your agent naturally:

  • "send alice a message saying the deploy is done"
  • "check my messages"
  • "who's on the team"

The agent picks the right subcommand and runs it for you. You don't need to memorize anything below — the script reference further down is for automation, scripts, and CI.

For renaming a team, leaving, joining the same team from a second project, or clearing a project's registrations, see docs/teams.md.

Multiple roles per project (actas / drop)

Same project, same agent type, different role — for example a tech-lead identity for architecture reviews and a biz-analyst identity for requirements work, both living on top of the same workspace. Toolset and assets are shared; only the role differs.

/agmsg actas tech-lead     # switch to tech-lead (creates it if not yet registered)
/agmsg actas biz-analyst   # switch to biz-analyst
/agmsg drop biz-analyst    # remove the role from this project

actas <name> is exclusive across sessions: it switches both sending and receiving to <name>, claims a lock that stops peer sessions from subscribing to the same name, and refuses if another session already holds it. drop releases the lock. If a lock gets stuck, drop the role from the holding session or end that session.

See docs/actas.md for the full mechanics — exclusivity model, recovery, liveness / PID recycling, Codex caveat.

Spawn a new agent (spawn)

Where actas switches this session to a different role, spawn brings up a separate agent process that takes a role on boot — handy for fanning out collaborators.

/agmsg spawn codex reviewer            # new codex agent, joins and becomes "reviewer"
/agmsg spawn claude-code alice --window  # new claude-code agent in a fresh tmux window
/agmsg spawn codex reviewer --boot-prompt "review the diff on this branch"  # joins AND starts the task

spawn <type> <name> pre-joins <name>, then launches the target CLI with the actas slash command (/<your-command> actas <name>, matching your install command name) as its initial prompt. If the current session is inside tmux, it opens in a new pane (or --window for a new window, --split h|v for the direction); otherwise it opens a new OS terminal window.

Pass --boot-prompt <text> to hand the new agent an initial task: the boot prompt becomes the actas slash command followed (newline-separated) by your text, so the agent claims its identity and acts on the task in the same first turn. This is the reliable way to give a one-shot goal to a codex peer: a Codex session that is not on monitor (legacy) or agmsgd delivery only looks at its inbox on its next turn, so it never notices a message you send after it goes idle.

By default spawn blocks until the new agent is actually listening — its watcher attaches and touches a readiness sentinel — then prints status=ready, so you can send work the moment spawn returns without losing it to the agent's cold start. Use --no-wait for fire-and-forget, or --ready-timeout <secs> to bound the wait (default 90; on timeout it prints status=timeout and exits 3 so a caller can re-spawn). Codex skips the wait: it has no spawn-time readiness handshake (this is separate from how it receives messages).

Options: --boot-prompt <text> (initial task; see above), --project <path> (default: current project), --team <team> (auto-resolved when the project has a single team), and --terminal <tmpl> / $AGMSG_TERMINAL / config spawn.terminal to override the terminal command on the non-tmux path (a {cmd} placeholder is replaced with the path to the generated boot script). On macOS the default opens whichever terminal you're currently in (iTerm or Terminal, via $TERM_PROGRAM) using open -a — a plain app launch, so it does not trigger the Automation/AppleScript permission prompts that scripting the terminal directly would.

To always pass a given agent type extra CLI flags on spawn (e.g. a default permission mode or sandbox policy), set them in a YAML spawn options file — one section per type, a flat --flag: value map underneath. Path: $AGMSG_SPAWN_OPTIONS_FILE, else ~/.agmsg/config/spawn_options.yaml; a missing file or section is a no-op.

claude-code:
  --permission-mode: acceptEdits
  --dangerously-skip-permissions: true   # a `true` value emits the flag with no argument

codex:
  --sandbox: workspace-write
  --dangerously-skip-permissions: false  # a `false` value suppresses the flag entirely

Eight of the ten agent types are spawnable — claude-code, codex, grok-build, cursor, gemini, antigravity, copilot, opencode. hermes is not spawnable because its CLI has no known mode that starts an interactive session pre-seeded with an initial prompt (#279). devin is currently not marked spawnable because an equivalent interactive boot mode has not yet been verified. macOS is the primary target; Linux and Windows are best-effort (please open an issue/PR if your terminal isn't handled). Headless environments — no tmux and no usable terminal — error out, since the agent CLIs need an interactive terminal.

Tear down a spawned agent (despawn)

despawn is the inverse of spawn — it cleanly tears down a member you brought up.

/agmsg despawn reviewer          # graceful: the member drops its role and closes its own pane
/agmsg despawn alice --force     # force: tear it down from here when its watcher can't respond

By default despawn <name> is graceful: it sends a ctrl:despawn control message to <name>, whose watcher drops its own role (releasing the actas lock and registration) and closes its own tmux pane — ending the agent. It blocks until the role is released, up to --timeout <secs> (default 30), then prints status=ok. If the member's watcher never responds it prints status=timeout and exits 3 — retry with --force.

--force skips the message and tears the member down from the placement recorded at spawn time: it kills the member's tmux pane/window and drops its registration. Use it when the member's watcher can't respond — a dead watcher, or a codex member (it never holds an actas lock and runs no Claude Code watcher, so graceful has nothing to confirm). A member started by hand (no spawn placement record) can't be --forced; despawn says so and leaves it for you to close.

Despawn only acts on the named member — the session running despawn is never torn down, and a broad-subscription watcher ignores a ctrl:despawn aimed at another role.

Bring a role back with its context (session resume)

A role remembers the session that last embodied it: sessions are named <team>-<agent>, and spawn resumes a role's previous session by default — so re-spawning after a despawn, crash, or restart comes back in the prior conversation, not blank (--fresh forces new). With tmux-resurrect, one ~/.tmux.conf line re-seats every role pane into its session after a tmux-server restart.

See docs/session-resurrect.md for the tmux-resurrect setup, how it resolves each pane, what does and doesn't come back automatically, and the manual fallback.

Delivery modes

How incoming messages reach your agent. Pick one at first join via the prompt, or change it later with /agmsg delivery <name> (/agmsg mode still works as an alias; from a shell: agmsg delivery <name>). On Claude Code and Codex the prompt offers agmsgd first, as the recommended choice, and lists the monitor as monitor (legacy) (the mode value is still monitor). Installing or updating never turns agmsgd on by itself, and an update changes nothing about the mode you already use.

mode mechanism latency who it's for
agmsgd (recommended on Claude Code and Codex; choose it at the prompt or with /agmsg delivery agmsgd) a background service delivers a notice straight into the session, no Monitor task needed a few seconds anyone on Claude Code or Codex who can run the service: it registers one that starts at login, and agmsg daemon disable stops and removes it
monitor (legacy) (value monitor; default on Claude Code; on OpenCode with the opencode-sentinel plugin) SessionStart hook → Monitor tool → blocking SQLite stream ~5s Claude Code users wanting real-time push
turn (default on Codex / Copilot CLI / OpenCode without the plugin) Stop hook fires check-inbox.sh between assistant turns until your next interaction Codex / Copilot CLI / OpenCode users not running monitor; Claude Code users on a quieter loop
both monitor primary, turn as per-session safety net ~5s; falls back to turn-end on watcher failure belt-and-suspenders
off no automatic delivery manual /agmsg only minimalists

agmsgd is not offered where agmsg daemon enable would refuse (Node older than 22.13, a JSONL message storage, no systemd user services on Linux, Codex older than 0.157 on Windows); the prompt says why in one line and lists the other modes. When agmsgd is already on, the prompt does not ask which to use: it says so and asks only whether to keep it or switch to monitor (legacy). Choosing agmsgd runs agmsg daemon enable and leaves the project on monitor as the fallback for a session whose destination is not confirmed yet. Choosing monitor (legacy) (or turn, both, off) is a real opt-out for that project: agmsgd stops delivering to its seats (agmsg daemon status shows them as chosen), and agmsgd itself stays on for the install's other projects (agmsg daemon disable turns it off for all of them). A project that never chose is unchanged.

Picking a mode

/agmsg delivery agmsgd     — direct delivery by the background service (Claude Code, Codex)
/agmsg delivery monitor    — switch this project to real-time push (Claude Code)
/agmsg delivery turn       — switch to between-turns checking
/agmsg delivery both       — monitor with turn as a safety net
/agmsg delivery off        — manual /agmsg only
/agmsg delivery            — show current mode

Settings are per-project. Each <project>/.claude/settings.local.json gets exactly the hooks the chosen mode needs — repeated set calls are idempotent.

Monitor priming: in monitor mode, the receiving agent doesn't react to its first inbound message until it has taken at least one turn this session. If you've just started a fresh session and a teammate has already sent something, nudge the agent with any short message ("hi") to prime it — subsequent messages stream in real time.

Claude Code monitor verification

delivery.sh status claude-code <project> showing mode: monitor means the project is configured for monitor delivery. It does not prove that Claude Code has started the runtime Monitor task in the current session.

For real-time delivery, verify the Claude Code runtime state:

  1. ToolSearch select:Monitor finds Claude Code's generic Monitor tool.
  2. The session starts Monitor(agmsg inbox stream) with the watch.sh ... claude-code command from the AGMSG-DIRECTIVE (or, after actas <name>, Monitor(agmsg inbox stream (acting as <name>))).
  3. The transcript contains a Monitor event: "agmsg inbox stream" (or "agmsg inbox stream (acting as <name>)") notification when messages arrive.

These are failure states, even if delivery.sh status says mode: monitor:

  • watch.sh is running only as a Bash/background/nohup shell process, not through the Monitor tool.
  • Tool search finds Azure Monitor, an MCP monitor, or any other monitor-branded tool instead of Claude Code's generic Monitor tool.
  • ToolSearch select:Monitor cannot find a generic Monitor tool.

TaskList may list this task, but not every environment does (the desktop app's Code tab runs the Monitor and delivers its events without listing it), so a task missing from TaskList is not a failure: judge by the Monitor call starting and its events arriving. The background-task footer is not a reliable check either. If the Monitor tool is unavailable, use turn delivery or manual /agmsg inbox checks as a fallback. Those modes still deliver queued messages, but they are not real-time monitor delivery.

Migrating from legacy hook on/off

hook on is now a thin alias for mode turn (with a one-line deprecation hint). To switch to real-time push:

/agmsg delivery monitor

The command updates db/config.yaml, rewrites the project's hook entries, and prints an AGMSG-DIRECTIVE that activates monitor in the current session — no agent restart needed.

Usage

Claude Code

/agmsg                                  — check inbox (all teams)
/agmsg history                          — message history
/agmsg team                             — list team members
/agmsg send <agent> <message>           — send message
/agmsg delivery <agmsgd|monitor|turn|both|off>     — switch delivery (alias: /agmsg mode)
/agmsg mode                             — show current mode
/agmsg actas <name>                     — switch to another role in this project (create if needed)
/agmsg drop <name>                      — remove a role from this project
/agmsg spawn <type> <name>              — launch a new agent that takes <name> (supported types: see "Spawn a new agent")
/agmsg despawn <name> [--force]         — tear down a member you spawned (graceful, or --force)
/agmsg hook on | off                    — legacy aliases (mode turn | off)
/agmsg version                          — show the installed version (git-describe provenance)
/agmsg reset                            — clear current project registration

Codex

$agmsg                          — or /skills → agmsg

Codex supports mode monitor through an app-server bridge, plus mode turn and mode off.

⚠️ Monitor mode changes how Codex starts — enable it knowing that. Codex has no Claude Code Monitor tool, so monitor (legacy) mode (mode monitor) prints a shell function that makes codex route through agmsg's monitor shim in your interactive shell. In monitor-mode projects the shim routes interactive launches through a bridge that turns incoming agmsg messages into turns on the current Codex thread; codex exec and non-monitor projects pass straight through to the real Codex. It depends on Codex app-server behavior and has a known limitation (orphans on TUI close — #149).

If you prefer a global PATH shim, run ~/.agents/skills/<cmd>/scripts/drivers/types/codex/codex-shim-install.sh install and put ~/.agents/bin before the real Codex binary on PATH. You can also launch with ~/.agents/skills/<cmd>/scripts/drivers/types/codex/codex-monitor.sh. Codex sandboxing must allow writes to the skill's db/, teams/, and run/ dirs — install.sh configures those writable_roots when ~/.codex/config.toml exists. Setup notes and internals: docs/codex-monitor-beta.md.

GitHub Copilot CLI

/agmsg                          — invokes the agmsg skill

The Copilot installer drops a SKILL.md at ~/.copilot/skills/agmsg/ so /agmsg is auto-discovered. Per-project hooks live at <project>/.github/hooks/agmsg.json. Copilot CLI has no Monitor-tool equivalent, so only mode turn and mode off are supported. Asking for monitor or both is rejected with an error.

OpenCode

$agmsg

Install with ./install.sh (when ~/.config/opencode/ exists, the OpenCode-typed skill is placed automatically alongside the default Codex-typed shared skill). Use --agent-type opencode only for OpenCode-only environments where Codex is not installed. OpenCode supports mode monitor (via the external opencode-sentinel plugin; without it the rule instructs a fallback to turn mode, which the agent follows rather than agmsg enforcing it), mode turn, and mode off. spawn opencode is available via opencode --prompt (TUI mode, which stays resident after the boot prompt's turn). both is not supported.

This makes OpenCode useful as a local coding agent, including configurations backed by local providers such as Ollama.

See docs/opencode.md for full setup instructions.

Shell (any agent)

~/.agents/skills/<cmd>/scripts/send.sh <team> <from> <to> "<message>" [--force]
~/.agents/skills/<cmd>/scripts/inbox.sh <team> <agent_id>
~/.agents/skills/<cmd>/scripts/history.sh <team> [agent_id] [limit]
~/.agents/skills/<cmd>/scripts/team.sh <team> [--json] [--delete] [--force] [--purge-messages] [--yes]
~/.agents/skills/<cmd>/scripts/placement-collisions.sh
~/.agents/skills/<cmd>/scripts/whoami.sh <project_path> <type>
~/.agents/skills/<cmd>/scripts/delivery.sh set <mode> <type> <project_path>
~/.agents/skills/<cmd>/scripts/delivery.sh status [<type> <project_path>]
~/.agents/skills/<cmd>/scripts/reset.sh <project_path> <type> [agent_id]

team.sh combines the roster with terminal placement, activity, delivery mode, and identity consistency. Verified identity is collapsed to identity=ok; mismatches and values that could not be observed are expanded with their evidence. --json emits every field for every registration. team.sh is read-only with respect to other seats: it reports an inconsistent or unresponsive seat but never repairs it from outside (the former --fix, --fix-pane-names and --rename-sessions flags were removed in #1152). A seat repairs its own identity cells by running fix from itself; one that cannot is despawned and restarted, or taken over by a person. Pane liveness will join this view when the pane-state contract lands; until then the unavailable column is omitted rather than filled with unknown.

--delete removes a team once every member has left (leave.sh each remaining one first) and the team is not actively synced (binding_state=active in team-list.sh --json refuses; disconnected proceeds with an extra warning) — its config, roster, identity history, and per-agent runtime state (actas locks, role-session records, spawn/placement records), but not its message history. --force (combined with --delete) removes every remaining member first, the same effect as running leave.sh for each, then deletes the team as --delete alone does — a team the desktop app created always has its app-user as a member, so it could never be deleted from the app without this; a --force confirmation names the members it will remove. --purge-messages deletes only a team's rows from the sqlite message store (jsonl is not supported yet) and can be used standalone or together with --delete; other teams' data is untouched. Both prompt for confirmation, in the same style as uninstall.sh's, unless --yes is given.

placement-collisions.sh is a separate, read-only installation-wide report. It never repairs or removes a record; keeping this fleet observation outside team.sh prevents an operator-level scan from becoming part of a seat's repair path. Today it reports only the record-only layer: two DIFFERENT seats' records resolved to the same canonical (kind, instance, pane) locator, entirely from records on disk — no terminal is ever asked anything. A ref with no instance component to resolve (every herdr ref today; a legacy bare tmux %N/@N) is not joined by raw string equality; it is listed under unscoped_records instead, since record-only evidence cannot tell such refs apart across terminal instances. Orca refs are not in that bucket: terminal_id_split always resolves the constant local instance for a validated handle (Orca has exactly one local runtime today), so an orca ref reaches the real instance+pane comparison instead of unscoped_records. collisions: none means the walk completed and found nothing; collisions: none_observed paired with coverage: partial means something along the way (a team config, a placement record, an empty ref) could not be read, so the empty answer is not a proven one; collisions: not_attempted means there was no teams/ directory to walk at all. An actual-location layer — matching a seat's own record against where a live census actually observes it — is designed but not yet wired here; see the script's header.

Terminal identity has a different number of observable names on each backend. Herdr exposes three independent values: the visible pane label, its internal agent key, and the CLI session name. tmux exposes two: the @agmsg_agent pane option is the internal key, while the CLI owns pane_title, so there is no independent pane-label field after the CLI starts. team.sh reports that tmux field as n/a rather than treating an unavailable concept as a mismatch. Orca exposes exactly one: terminal_name writes the tab title, and team.sh reads it back as pane_label (the durable value lives in the tab itself, not in any one pane within it — a tab can hold more than one pane, split). There is no separate @agmsg_agent-style key, so agent_key reports n/a unconditionally, the same way tmux's pane_label does for the field it lacks. cli_session is not: it follows the AGENT type's own session_name_source, same as on every driver — a title-sourced type (Claude Code) gets n/a too, since orca's own observation has no independent title field either; a screen-sourced type (Codex, whose session name comes from a Thread name: line) is read straight off the pane's screen, independent of orca's own observe extension, and reports unknown:name_not_visible when that line isn't found there.

send.sh takes four positional arguments — <team> <from> <to> "<message>" — plus an optional trailing --force. Quote the message so the shell sees it as one argument; an unquoted message with spaces will be misparsed. Both from and to must already be registered in <team>; an unregistered name errors out (listing the currently registered names) instead of silently storing an undeliverable message. Pass --force to bypass this check for an intentional pre-registration send.

FAQ / Design notes

Is this MCP? Do I need an MCP server?

No. agmsg is standalone — bash + sqlite3, no server, no network, and no daemon unless you choose the optional agmsgd. The two stacks are orthogonal: you can run agmsg alongside any MCP setup you already have.

Concurrent writes to the same channel — do they conflict?

The store is SQLite in WAL mode. Multiple readers and a single writer coexist; writes are short and serialized at the file level. In practice, two agents sending into the same team don't collide.

Does SQLite guarantee turn order? Is there a lock or token?

SQLite guarantees the ordering of the log itself — every row has a monotonic id and timestamp. Turn-taking between agents is a protocol-level concern, not enforced by the transport. The floor is intentionally dumb; the protocol lives in your prompts.

Two Claude Code instances grab the same task — claim/lock?

Not in v1. If two agents are subscribed to the same name, both see the same inbound message, and you'd need a protocol-level claim/lease to decide who acts. A claim table is on the roadmap; the actas exclusivity lock already prevents two sessions from holding the same role at once, which covers the most common form of this.

Runaway loops — where does the stop condition live?

At the protocol/prompt level, not the transport. Common pattern: include a max-turns or explicit done-signal instruction in the kickoff prompt ("stop after N exchanges", "reply DONE when complete"). agmsg won't cut a conversation off for you.

What's carried on a handoff — context, diffs, or just text?

Plain text. Messages are short — a sentence, a request, a path. Agents pass summaries and references (file paths, commit SHAs, issue numbers), not raw context. Transport is the message; semantic packing is up to the prompt.

What if the output exceeds the receiver's context window?

Use the summary + file-reference pattern: write the artifact to disk, send a one-line pointer. The DB stores messages, not files.

Does it hold up with more than 2 agents?

Yes. Teams are N-agent. The demo is 2 for clarity; larger rooms work the same way — we run our own 8-agent team on it.

Does context persist across sessions?

Yes. Messages live in SQLite and survive sessions. history.sh <team> replays the room.

Can I re-seed a fresh agent from an old room?

The message store is effectively a replay log. There's no one-shot "rehydrate from room X" command yet, but history.sh gives you the transcript and you can prompt a new agent with it. Treat persistence as the unlock that makes that possible.

How do you pronounce it?

"AG message" (ay-jee message), or spelled out as A-G-M-S-G. Either is fine.

Update

npx agmsg@latest install --update      # add --cmd <name> if you have more than one install

From a clone:

cd agmsg
git pull
./install.sh --update

DB and team configs are preserved. Only scripts and assets are updated.

Upgrading from 1.5.x

--update does not enable agmsgd. If you have never run agmsg daemon enable, nothing changes: agmsgd stays off, and messaging keeps working exactly as it did on 1.5.x. If agmsgd is currently on, an update restarts it on the new version automatically; if agmsg daemon status still shows it stopped afterward, run agmsg daemon start. If you had turned it off yourself (agmsg daemon disable), it stays off through the update, as intended.

No running Codex session needs to be restarted just because you ran --update. Restarting a Codex session is only needed to pick up agmsgd itself — either turning it on for the first time (see "agmsgd beta" above) or dropping back to the bridge after agmsg daemon disable.

Uninstall

An uninstall.sh copy ships inside every install, so this works whether you installed via git clone, npx agmsg, or the curl one-liner:

~/.agents/skills/agmsg/uninstall.sh              # This install only (confirms each step)
~/.agents/skills/agmsg/uninstall.sh --yes        # This install only, no confirmation
~/.agents/skills/agmsg/uninstall.sh --keep-data  # Remove skill but keep DB and teams
~/.agents/skills/agmsg/uninstall.sh --all        # Every agmsg install on this machine

With no --all, it removes exactly one install — the one it's running from. Cleans up: skill files, slash commands, hooks, AGENTS.md sections, and team configs.

If you have a git clone checkout handy, ./uninstall.sh from the repo root works the same way when there's exactly one install on the machine. With more than one, it refuses rather than guess which one you mean — run the uninstall.sh inside the one you want, or pass --all to remove every install on the machine (with one combined confirmation unless --yes is also given, plus a separate one for whether to remove each install's DB and teams too).

Configuration

Environment variables

Variable Default Purpose
AGMSG_STORAGE_PATH <skill>/db Directory holding the SQLite message store (messages.db). Override to relocate the store — handy for tests, sandboxes, or running isolated instances.
AGMSG_PLUGIN_DIRS (unset) :-separated extra directories to search for external drivers, in addition to <skill>/plugins. Each holds <axis>/<name>/ subdirs. Drivers found here are still ignored until opted into with agmsg plugin trust. See docs/plugins.md.

The message store path resolves as AGMSG_STORAGE_PATH (env) > built-in default. (A config-file layer is planned to slot in between the two as part of the storage-driver work; the intended order is env > config > default.) The override is scoped to the SQLite store only — team configs under teams/ are unaffected.

# Run against an isolated store
AGMSG_STORAGE_PATH=/tmp/agmsg-sandbox ./scripts/send.sh myteam alice bob "hi"

Sandbox compatibility (Claude Code)

Claude Code's sandbox restricts filesystem writes to the project directory. In monitor mode, watch.sh runs inside the sandbox and needs to write pidfiles and SQLite WAL files under ~/.agents/skills/agmsg/. If you have sandboxing enabled, add an allowlist entry to your settings:

~/.claude/settings.json (user-level — applies to all projects):

{
  "sandbox": {
    "filesystem": {
      "allowWrite": [
        "~/.agents/skills/agmsg/"
      ]
    }
  }
}

The allowlist does not enable sandboxing by itself. Use /sandbox in Claude Code to choose a sandbox mode, or add "enabled": true alongside "filesystem" under "sandbox" to configure it in settings. The allowlist has no effect until sandboxing is enabled.

This can also go in project-level .claude/settings.local.json if you prefer per-project scope. The allowlist merges across all settings scopes and takes effect immediately — no restart needed.

If you installed agmsg under a custom command name (e.g. m), adjust the path accordingly (~/.agents/skills/m/).

Sandbox compatibility (Codex)

Codex may run shell commands in a workspace-write sandbox. agmsg stores its SQLite database and team metadata under ~/.agents/skills/<cmd>/ by default, which is outside most project workspaces. If the sandbox cannot write there, commands that append or update state can fail with errors such as sqlite3.OperationalError: unable to open database file.

This affects operations such as:

  • sending messages (send.sh writes to db/messages.db)
  • marking inbox rows as read (inbox.sh updates read_at)
  • joining, resetting, switching roles, or changing delivery mode (teams/ and config/state files may be updated)

If you use Codex with filesystem sandboxing enabled, allow writes to the agmsg skill storage directory in your Codex config.

Example ~/.codex/config.toml:

sandbox_mode = "workspace-write"

[sandbox_workspace_write]
writable_roots = [
  "~/.agents/skills/agmsg/db",
  "~/.agents/skills/agmsg/teams",
  "~/.agents/skills/agmsg/run",
]

If you installed agmsg under a custom command name, adjust the path accordingly:

[sandbox_workspace_write]
writable_roots = [
  "~/.agents/skills/m/db",
  "~/.agents/skills/m/teams",
  "~/.agents/skills/m/run",
]

You can also allow the whole skill directory if your Codex setup supports that:

[sandbox_workspace_write]
writable_roots = [
  "~/.agents/skills/agmsg",
]

Codex supports mode monitor (legacy) through the app-server bridge, plus mode turn and mode off; it just has no Claude Code Monitor tool. The sandbox allowlist is required for writes performed by manual $agmsg commands, turn-end inbox checks and the bridge.

Some Codex runtimes or automations may inject a managed permission profile for a single run. In that case, the run-specific writable roots must also include the agmsg storage paths; the user-level config alone may not be enough.

Tests

bats tests/    # requires bats-core: brew install bats-core

Architecture

~/.agents/skills/<cmd>/           # Folder name = command name
├── SKILL.md                      # Skill definition (read by CC & Codex)
├── agents/
│   └── openai.yaml               # Codex metadata
├── scripts/                      # Bash scripts (the type-agnostic engine)
│   ├── lib/                      # Sourced helper libraries
│   └── drivers/types/<name>/     # Built-in agent-type drivers (manifest + runtime)
├── plugins/<axis>/<name>/        # External drivers you opt into (agmsg plugin trust)
├── db/messages.db                # SQLite WAL-mode message store
├── run/                          # Runtime state: pidfiles, actas locks, agmsgd install record
└── teams/                        # Team configs (self-contained)
    └── <team>/
        └── config.json
  • Storage: Single SQLite file with WAL mode
  • Concurrency: Multiple readers + 1 writer, no conflicts
  • Dependencies: bash, sqlite3 (no Python required)
  • Auto detection: Stop hook checks inbox after each response (60s cooldown, configurable via delivery.turn.check_interval)
  • No daemon required: direct filesystem access (the optional agmsgd is a resident service you choose)
  • No network: Everything local

Plugins

agmsg's pluggable units are drivers grouped by axis (types for agent runtimes; storage and delivery to follow). Built-ins ship under scripts/drivers/; you can drop your own under <skill>/plugins/<axis>/<name>/ (or point AGMSG_PLUGIN_DIRS at a directory) to extend agmsg without forking.

Because a driver is shell code that runs with your privileges, external drivers are never loaded until you opt in — an unexpected drop-in is ignored (with a warning) until you run agmsg plugin trust <axis>/<name>. List what's discovered and its trust state with agmsg plugin list.

Full discovery order, the trust model, and authoring guidance: docs/plugins.md (design rationale in ADR 0002).

Building on agmsg

Writing something outside agmsg's own scripts that reads or drives agmsg — a GUI app, a bot, a derivative project (agmsg-shogi, agmsg-go, agmsg-mcp, …)? Read data via scripts/api.sh (JSON out, no need to touch messages.db or teams/*/config.json directly — those are internal and free to change), and write through the existing scripts (send.sh, join.sh, …) rather than the database. Full guidance: docs/building-on-agmsg.md.

Community

  • Product Hunt: #5 Product of the Day, 2026-06-09 launch — 219 upvotes, 39 comments
  • Community projects (also on the showcase): agkanban — multi-agent kanban board that pairs with agmsg; agmsg-office — replays message logs as characters speaking on a stage; agmsg-viewer — message history in a chat interface in the browser; agmsg-bubblelog — replays a team's log locally as a messenger-style thread; agmsg-tui — Rust/ratatui terminal client, friendly to SSH, mosh, and tmux
  • External contributors: @MiuraKatsu (Gemini support + whoami auto-detect), @roundrop (Copilot CLI support), @TOMONOSUKEJP (native Windows / Git Bash), @kenshin-yamada (watcher scoping fix), @utenadev (OpenCode contribution), @lucianlamp (native Windows PowerShell helpers), @tatsuya6502 (sandboxed Bash tool support), @Masashi-Ono0611 (project-path validation, watchdog and watcher fixes), @chemica-tan (Windows codex bridge: project compare and port parsing), @otsune (Git Bash quoting from PowerShell), @tsukimiya (OpenCode: resident spawn and monitor delivery)

Project site (agmsg.cc)

agmsg.cc is an Astro project under site/.

  • Source of truth: site/ (Astro + Tailwind). The built output is not committed — CI builds it.
  • Local preview:
    cd site
    npm install
    npm run dev        # http://localhost:4321, live reload
    # or, to serve the production build:
    npm run build && npm run preview
  • Publish: pushing to main with changes under site/ runs .github/workflows/pages.yml, which builds the site and deploys it to GitHub Pages. The custom domain is set by site/public/CNAME.
  • The agent-types gallery is generated at build time from scripts/drivers/types/*/type.conf, so adding an agent type surfaces it on the site automatically.

docs/ is developer documentation (markdown, ADRs, spec) read on GitHub — it is not the published site.

Contributing

See Design & Architecture for developer documentation — identity model, data storage, hook system, and script responsibilities.

If agmsg saves you copy-paste round-trips, a GitHub star helps other people find it.

License

MIT

About

Cross-vendor messaging for CLI AI coding agents — let Claude Code, Codex, Gemini & Copilot talk to each other in one team. Bash + SQLite, no daemon, no framework.

Topics

Resources

Contributing

Security policy

Stars

1.6k stars

Watchers

5 watching

Forks

Releases

Packages

Contributors

Languages