by fujibee
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.
# Add to your Claude Code skills
git clone https://github.com/fujibee/agmsgLast scanned: 6/14/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-06-14T08:16:24.009Z",
"npmAuditRan": true,
"pipAuditRan": true,
"promptInjectionRan": true
}No comments yet. Be the first to share your thoughts!
30 days in the Featured rail · terms & refunds
IMPORTANT: Always use the provided scripts. NEVER directly read or edit config files, DB, or team data. There is NO register.sh — use join.sh to join a team.
agmsg keeps its SQLite database, team registry, and runtime state under ~/.agents/skills/agmsg/. The ./install.sh install path creates that tree; the Claude Code plugin install path does not (the plugin marketplace flow only drops the skill content into ~/.claude/plugins/cache/). Before any other command, bootstrap if needed:
if [ ! -d ~/.agents/skills/agmsg ]; then
# Locate the plugin install script (any version), run it once.
installer=$(ls ~/.claude/plugins/cache/fujibee-agmsg/agmsg/*/install.sh 2>/dev/null | head -1)
if [ -n "$installer" ]; then
bash "$installer" --cmd agmsg
else
echo "agmsg not installed. Either:" >&2
echo " - run ./install.sh in the agmsg repo, or" >&2
echo " - install via /plugin marketplace add fujibee/agmsg && /plugin install agmsg@fujibee-agmsg" >&2
exit 1
fi
fi
After this runs once, ~/.agents/skills/agmsg/ is populated and you can skip Step 0 on future invocations.
~/.agents/skills/agmsg/scripts/whoami.sh "$(pwd)" <type>
# type: claude-code, codex, gemini, antigravity, copilot
# Returns: agent=... / multiple=true ... / suggest=true ... / not_joined=true ...
Ask the user for a team name and agent name, then run:
~/.agents/skills/agmsg/scripts/join.sh <team> <agent_name> <type> "$(pwd)"
Do NOT manually edit config files. Always use join.sh.
Default (no arguments): IMMEDIATELY check inbox. Do NOT ask what to do.
# Check inbox (marks messages as read) — DEFAULT action
~/.agents/skills/agmsg/scripts/inbox.sh <team> <agent_id>
# Send a message
~/.agents/skills/agmsg/scripts/send.sh <team> <from_agent> <to_agent> "<message>"
# Message history
~/.agents/skills/agmsg/scripts/history.sh <team> [agent_id] [limit]
# List team members
~/.agents/skills/agmsg/scripts/team.sh <team>
# Leave a team
~/.agents/skills/agmsg/scripts/leave.sh <team> <agent_id>
# Rename a team (moves dir, updates config + messages).
# After renaming, each existing member should re-run whoami.sh to refresh
# their cached team name in any running session.
~/.agents/skills/agmsg/scripts/rename-team.sh <old_team> <new_team>
# Clear registrations for the current project/type.
# A trailing <session_id> additionally releases any actas exclusivity locks
# this session held on <agent_id> so peers can pick them up immediately.
~/.agents/skills/agmsg/scripts/reset.sh "$(pwd)" <type> [agent_id] [session_id]
# Set delivery mode for this project. Replaces the legacy hook.sh on/off,
# which is kept as a deprecated alias only.
# monitor — real-time push via SessionStart + Monitor tool (claude-code only)
# turn — Stop-hook pulls at the end of each assistant turn
# both — monitor primary, turn as fallback
# off — no automatic delivery
~/.agents/skills/agmsg/scripts/delivery.sh set <mode> <type> "$(pwd)"
~/.agents/skills/agmsg/scripts/delivery.sh status <type> "$(pwd)"
# Multiple roles per project (one CC = one active role).
# Claude Code: `actas` claims an exclusivity lock for <name> across sessions
# and restarts the Monitor filtered to <name> only; peer watchers stop
# subscribing to <name> while this session holds the lock. `drop` releases.
# Codex: actas is send-side only (no stable session_id during slash commands
# → no peer-visible lock). See README "Codex caveat" for details.
~/.agents/skills/agmsg/scripts/actas-claim.sh "$(pwd)" <type> <name> "$session_id"
~/.agents/skills/agmsg/scripts/reset.sh "$(pwd)" <type> <name> "$session_id"
# (Both of the above are normally driven by `/agmsg actas <name>` and
# `/agmsg drop <name>` slash commands, which also handle the Monitor
# TaskStop + relaunch dance described in the cmd template.)
# Spawn a NEW agent process that takes an actas identity on boot.
# Pre-joins <name> to a team, then launches the agent CLI in a tmux pane/window
# (when run inside tmux) or a new OS terminal, with `/agmsg actas <name>` as the
# initial prompt. claude-code/codex only; macOS primary, Linux/Windows best-effort.
# Non-tmux + no usable terminal (headless) errors out.
# --project <path> project to launch in (default: $PWD)
# --team <team> team to join into (default: auto-resolved from the project)
# --window new tmux window instead of splitting the current one
# --split h|v tmux split direction (default h)
# --terminal <tmpl> terminal command template ({cmd} = path to the boot
# script) for the non-tmux path; overrides $AGMSG_TERMINAL
# / config spawn.terminal. macOS default uses `open -a`
# (no Automation/TCC permission prompt).
~/.agents/skills/agmsg/scripts/spawn.sh <claude-code|codex> <name> [options]
~/.agents/skills/agmsg/db/messages.db~/.agents/skills/agmsg/teams/<name>/config.jsonsqlite3 CLICross-agent messaging for CLI AI agents. No daemon, no network, no complexity.
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.
What it isn't:
bash + sqlite3.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.Two monitor-mode Claude Code instances, 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:

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

# 1. Install (one-liner)
bash <(curl -fsSL https://raw.githubusercontent.com/fujibee/agmsg/main/setup.sh)
# Or clone first if you want to inspect the code
git clone https://github.com/fujibee/agmsg.git && cd agmsg && ./install.sh
# 2. Restart Claude Code / Codex / Gemini CLI / Antigravity 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
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: monitor — real-time push; Codex defaults to turn because it has no Monitor tool). After that, you talk to your agent naturally — see First run below.
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. There is no daemon, no socket, no broker — the file is the shared floor and the agents take turns on 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.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
The command name determines:
~/.agents/skills/<cmd>//<cmd>$<cmd>After install, restart your agent (Claude Code / Codex / Gemini CLI / Antigravity) so it picks up the new skill.
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:
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.
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)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
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. Options: --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.
Only claude-code and codex are supported today. 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.
How incoming messages reach your agent. Pick one at first join via the prompt, or change it later with /agmsg mode <name>.
| mode | mechanism | latency | who it's for |
|---|---|---|---|
monitor (default on Claude Code) |
SessionStart hook → Monitor tool → blocking SQLite stream | ~5s | Claude Code users wanting real-time push |
turn (default on Codex / Copilot CLI) |
Stop hook fires check-inbox.sh between assistant turns |
until your next interaction | Codex / Copilot CLI (no Monitor tool); 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 |
/agmsg mode monitor — switch this project to real-time push (Claude Code)
/agmsg mode turn — switch to between-turns checking
/agmsg mode both — monitor with turn as a safety net
/agmsg mode off — manual /agmsg only
/agmsg mode — 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.
hook on/offhook on is now a thin alias for mode turn (with a one-line deprecation hint). To switch to real-time push:
/agmsg mode 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.
/agmsg — check inbox (all teams)
/agmsg history — message history
/agmsg team — list team members
/agmsg send <agent> <message> — send message
/agmsg mode <monitor|turn|both|off> — switch delivery 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 (claude-code/codex) that takes <name>
/agmsg hook on | off — legacy aliases (mode turn | off)
/agmsg reset — clear current project registration
$agmsg