macos用
  • TypeScript 78.2%
  • Shell 21.8%
Find a file
answer.kazuya 6437f07d35 fix: ツール名をアンダースコア区切りに変更(ドット入りだと一部モデルで400)
OpenAI系のツール/関数呼び出しはツール名を ^[a-zA-Z0-9_-]+$ でしか受け付けず、
daemon.status のようなドット入り名だとリクエスト全体が拒否される。他プロバイダ
経由では素通りしていたが、Responses APIを使うモデル(gpt-5.6-luna等)で顕在化した。
2026-08-03 14:40:37 +09:00
dist fix: ツール名をアンダースコア区切りに変更(ドット入りだと一部モデルで400) 2026-08-03 14:40:37 +09:00
scripts Add macOS (launchd) support and fix daemon reliability bugs 2026-07-27 22:44:42 +09:00
src fix: ツール名をアンダースコア区切りに変更(ドット入りだと一部モデルで400) 2026-08-03 14:40:37 +09:00
.gitignore chore: add .gitignore, remove node_modules from tracking 2026-07-14 03:06:45 +00:00
package-lock.json fix: READMEのInstall手順を実際に動く内容に修正、パッケージ名をfieldcrmブランドから独立 2026-07-14 11:02:25 +00:00
package.json fix: READMEのInstall手順を実際に動く内容に修正、パッケージ名をfieldcrmブランドから独立 2026-07-14 11:02:25 +00:00
README.md fix: ツール名をアンダースコア区切りに変更(ドット入りだと一部モデルで400) 2026-08-03 14:40:37 +09:00
tsconfig.json chore: add .gitignore, remove node_modules from tracking 2026-07-14 03:06:45 +00:00

agmsg-daemon-plugin

OpenCode plugin that sets up a systemd auto-reply daemon for agmsg agents (cross-agent messaging via SQLite). One line in opencode.json → daemon running.


What this solves

You run multiple opencode agents (deepseek, mimo, etc.) that listen for inbound agmsg messages. Each needs a polling daemon that:

  1. Watches the agmsg SQLite inbox every 5 seconds
  2. Injects unread messages into a fresh opencode run turn
  3. Marks messages read and sends auto-ack

Without this plugin, you'd hand-write systemd unit files with correct paths, environment variables, and override.conf for every agent and every machine.


Typical use cases

Claude Code → opencode sub-agent

Claude sends a research task via agmsg → opencode daemon picks it up, runs the task, replies with results. No need to keep a terminal session open.

Multi-agent swarm

deepseek + mimo + other opencode agents running in parallel, each with its own daemon, all on the same agmsg team.

CI / ephemeral machines

Spin up a new dev machine → git clone agmsg && git clone this plugin → daemon running in 10 seconds.

Headless agents

Agents that run autonomously even when no one is logged into a terminal session.


Prerequisites

This plugin only automates the systemd wiring for agents that already exist in agmsg. It does not create agmsg teams or agents — that step must be done first, manually, with agmsg itself.

  • Linux with systemd (systemctl --user must work)
  • agmsg installed at ~/.agents/skills/agmsg/
  • The target agent has already joined a team as codex type — run join.sh yourself first (see Example workflow below). Without this, the plugin finds nothing and does nothing.
  • opencode CLI in PATH

Install

This package is not published to npm (no registry account needed / nothing to authenticate). Install it as a local file-based opencode plugin instead — clone the repo and point opencode.json at the built dist/index.js with a file:// URL. dist/ is already committed pre-built, so no build step is required.

git clone https://git.answer.mydns.jp/kaz/agmsg-daemon.git
cd agmsg-daemon/agmsg-daemon-plugin
// opencode.json (global: ~/.config/opencode/opencode.json,
// or project: .opencode/opencode.json)
{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["file:///absolute/path/to/agmsg-daemon-plugin/dist/index.js"]
}

Use an absolute path. Restart opencode. On load, the plugin scans ~/.agents/skills/agmsg/teams/*/config.json for agents registered as codex type (agents already joined via join.sh — see Prerequisites above), generates systemd units, and starts them.


Options

These options live entirely in opencode.json — they configure the daemon's own opencode run subprocess for the target agent (e.g. deepseek, mimo), and have nothing to do with Claude Code or the model Claude Code itself is running as.

{
  "plugin": [
    ["file:///absolute/path/to/agmsg-daemon-plugin/dist/index.js", {
      "models": {
        "deepseek": "opencode-go/deepseek-v4-flash",
        "mimo": "opencode-go/mimo-v2.5"
      },
      "agmsgDir": "/path/to/agmsg",
      "storagePath": "/path/to/agmsg/db",
      "disableAutoSetup": false
    }]
  ]
}
Key Type Description
models Record<string, string> Per-agent model to pass as -m to opencode run
agmsgDir string agmsg installation directory (default: ~/.agents/skills/agmsg)
storagePath string Directory containing messages.db (default: <agmsgDir>/db)
disableAutoSetup boolean Skip auto-setup on plugin load; use daemon_setup manually

Custom tools

Tool names use underscores, not dots — OpenAI-style function/tool calling only accepts ^[a-zA-Z0-9_-]+$ for tool names, and a dotted name gets the whole request rejected with a 400 on models that go through the stricter Responses API (found 2026-08-03 via gpt-5.6-luna on opencode-go).

Tool Description
daemon_status Show status of all daemons (or specific agent with agent arg)
daemon_start Start daemon for a specific agent
daemon_stop Stop daemon for a specific agent
daemon_restart Restart daemon for a specific agent
daemon_remove Remove systemd unit for a specific agent
daemon_setup (Re)run setup for all agents or a specific one

Example workflow

1. Join agmsg team

bash ~/.agents/skills/agmsg/scripts/join.sh lab1 deepseek codex /home/user/project

2. Add plugin & restart

{ "plugin": ["file:///absolute/path/to/agmsg-daemon-plugin/dist/index.js"] }

Plugin auto-detects codex-type agents, generates systemd units, and starts them.

3. Verify

daemon_status
→ deepseek@lab1: RUNNING pid=247808
  mimo@lab1: RUNNING pid=247807

4. Done

When an agmsg message arrives for deepseek@lab1, the daemon picks it up, runs opencode run, marks it read, and sends auto-ack.


What gets created

  • ~/.config/systemd/user/agmsg-daemon-{agent}.service — systemd unit
  • ~/.config/systemd/user/agmsg-daemon-{agent}.service.d/override.conf — PROJECT_DIR, AGMSG_STORAGE_PATH
  • <agmsgDir>/scripts/agmsg-daemon.sh — self-contained daemon script
  • ~/.config/opencode/agmsg-daemon/setup-state.json — tracks which project setup ran for

Uninstall

daemon_remove deepseek
daemon_remove mimo

Remove the file://...agmsg-daemon-plugin/dist/index.js entry from opencode.json's plugin array.


How it works

opencode restart
  └─ plugin loads
       └─ scans teams/*/config.json for codex agents
            └─ for each agent:
                 ├─ generate systemd unit
                 ├─ copy daemon.sh to agmsg/scripts/
                 └─ systemctl --user enable --now

daemon.sh (5s loop)
  ├─ SELECT COUNT(*) FROM messages WHERE read_at IS NULL
  ├─ if unread > 0: opencode run "process these"
  └─ mark read + INSERT auto-ack

The daemon is fully self-contained: it resolves the SQLite path directly (no dependency on agmsg's storage.sh or send.sh), and uses inline SQL INSERT for auto-ack.


License

MIT