From 05c14b7ac35cf00003c50ec8fb2d509f6716e89d Mon Sep 17 00:00:00 2001 From: m1kekad0 Date: Wed, 19 Aug 2026 20:24:45 +0900 Subject: [PATCH 1/4] feat: add Devin agent type AI-assisted-by: Gemini 3.7 Flash --- README.ja.md | 2 +- README.md | 2 +- docs/agent-types.md | 2 +- install.sh | 4 +- scripts/drivers/types/devin/_delivery.sh | 21 +++ scripts/drivers/types/devin/template.md | 229 +++++++++++++++++++++++ scripts/drivers/types/devin/type.conf | 7 + site/src/i18n/de.js | 3 +- site/src/i18n/en.js | 1 + site/src/i18n/es.js | 5 +- site/src/i18n/fr.js | 1 + site/src/i18n/ja.js | 1 + site/src/i18n/ko.js | 1 + site/src/i18n/pt-BR.js | 5 +- site/src/i18n/zh-CN.js | 1 + site/src/i18n/zh-TW.js | 5 +- site/src/layouts/Home.astro | 1 + tests/test_delivery.bats | 32 ++++ tests/test_type_registry.bats | 20 +- 19 files changed, 321 insertions(+), 22 deletions(-) create mode 100644 scripts/drivers/types/devin/_delivery.sh create mode 100644 scripts/drivers/types/devin/template.md create mode 100644 scripts/drivers/types/devin/type.conf diff --git a/README.ja.md b/README.ja.md index 2bb4e11b9..678ba90cf 100644 --- a/README.ja.md +++ b/README.ja.md @@ -210,7 +210,7 @@ codex: --dangerously-skip-permissions: false # `false`の値はフラグ自体を出力しない ``` -9種類のエージェントタイプのうち8つがspawn可能 — `claude-code`、`codex`、`grok-build`、`cursor`、`gemini`、`antigravity`、`copilot`、`opencode`。`hermes` は不可 — そのCLIには初期プロンプトを事前に仕込んだインタラクティブセッションを開始するモードがない(#279)。macOSが主なターゲットで、LinuxとWindowsはベストエフォート(ターミナルが未対応の場合はissueまたはPRを歓迎)。ヘッドレス環境 — tmuxもなく使えるターミナルもない — はエージェントCLIがインタラクティブなターミナルを必要とするためエラーになる。 +10種類のエージェントタイプのうち8つがspawn可能 — `claude-code`、`codex`、`grok-build`、`cursor`、`gemini`、`antigravity`、`copilot`、`opencode`。`hermes` と `devin` は不可 — 初期プロンプトを事前に仕込んだインタラクティブセッションを開始するモードがない。macOSが主なターゲットで、LinuxとWindowsはベストエフォート(ターミナルが未対応の場合はissueまたはPRを歓迎)。ヘッドレス環境 — tmuxもなく使えるターミナルもない — はエージェントCLIがインタラクティブなターミナルを必要とするためエラーになる。 ### spawnしたエージェントを終了する(`despawn`) diff --git a/README.md b/README.md index b775aedf9..a6ccdfd3a 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ codex: --dangerously-skip-permissions: false # a `false` value suppresses the flag entirely ``` -Eight of the nine agent types are spawnable — `claude-code`, `codex`, `grok-build`, `cursor`, `gemini`, `antigravity`, `copilot`, `opencode`. `hermes` is not: its CLI has no mode that starts an interactive session pre-seeded with an initial prompt (#279). 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. +Eight of the ten agent types are spawnable — `claude-code`, `codex`, `grok-build`, `cursor`, `gemini`, `antigravity`, `copilot`, `opencode`. `hermes` and `devin` are not: their CLIs do not have a known interactive session boot mode pre-seeded with an initial prompt. 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`) diff --git a/docs/agent-types.md b/docs/agent-types.md index ea84c06c7..ef1a17a61 100644 --- a/docs/agent-types.md +++ b/docs/agent-types.md @@ -1,7 +1,7 @@ # Agent types agmsg supports several agent runtimes — claude-code, codex, gemini, antigravity, -copilot, opencode, hermes, cursor — and each is described by a small **manifest** so that the rest +copilot, opencode, hermes, cursor, devin, grok-build — and each is described by a small **manifest** so that the rest of agmsg (detection, the join whitelist, spawn, and delivery routing) discovers it from data instead of hardcoded `case` arms. diff --git a/install.sh b/install.sh index afa0570ff..ccf4507c8 100755 --- a/install.sh +++ b/install.sh @@ -103,7 +103,7 @@ AGENT_TYPE="" # claude-code, codex, gemini, antigravity — passed via --agent- # cursor) that had already drifted from the other two -- re-detecting one of # those three types as "codex" and then, via the template pick, overwriting # the SKILL.md the installer itself had written with the wrong flavor. -AGMSG_SHARED_SKILL_TPL_TYPES="gemini antigravity opencode hermes cursor grok-build" +AGMSG_SHARED_SKILL_TPL_TYPES="gemini antigravity opencode hermes cursor grok-build devin" configure_codex_sandbox() { # --- Configure Codex sandbox (if Codex is installed) --- @@ -219,7 +219,7 @@ while [[ $# -gt 0 ]]; do echo "Options:" echo " --cmd Command & skill folder name (default: agmsg)" echo " Claude Code: /, Codex/Gemini/Antigravity: \$" - echo " --agent-type Agent type: claude-code, codex, gemini, antigravity, opencode, hermes, cursor, grok-build" + echo " --agent-type Agent type: claude-code, codex, gemini, antigravity, opencode, hermes, cursor, grok-build, devin" echo " Selects which template becomes SKILL.md (matches the" echo " arg passed to join.sh / whoami.sh)" echo " --update Update skill scripts only (preserve DB and teams)" diff --git a/scripts/drivers/types/devin/_delivery.sh b/scripts/drivers/types/devin/_delivery.sh new file mode 100644 index 000000000..4cc7d5ebe --- /dev/null +++ b/scripts/drivers/types/devin/_delivery.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# devin delivery plug — manual inbox checks only. +# +# Devin has no agmsg automatic delivery hook: the only valid mode is `off` +# (enforced by delivery_modes=off in the manifest, which the central gate in +# delivery.sh checks). These overrides keep apply / status / teardown from +# touching a hook file or another agent type's watchers. Sourced into +# delivery.sh's context. + +# Nothing to write — manual-only, so no hooks_file is resolved or created. +agmsg_delivery_apply() { :; } + +# No hook file to read; the mode is always off. +agmsg_delivery_status() { echo "mode: off"; } + +# No watcher or bridge of our own. Do NOT fall through to the default teardown +# (which stops this project's watch.sh) — another agent type may hold a live +# watcher on the same project, and a devin `set off` must not disturb it. +agmsg_delivery_on_disable() { + echo "Devin has no agmsg automatic delivery hook; manual inbox checks only." +} diff --git a/scripts/drivers/types/devin/template.md b/scripts/drivers/types/devin/template.md new file mode 100644 index 000000000..aa1a61fa6 --- /dev/null +++ b/scripts/drivers/types/devin/template.md @@ -0,0 +1,229 @@ +--- +name: __SKILL_NAME__ +description: Cross-agent messaging via SQLite. Send messages between Claude Code, Codex, Gemini CLI, Devin, and other agents. No daemon, no network, no dependencies beyond bash and sqlite3. +--- + +Devin skill for agmsg cross-agent messaging. **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.** + +**Shell requirement:** All agmsg scripts are Bash scripts. Always execute them via `bash`, never via PowerShell or cmd directly. If your default shell is not Bash (e.g. PowerShell on Windows), wrap every command with `bash -lc '...'`. Example: `bash -lc '~/.agents/skills/__SKILL_NAME__/scripts/send.sh myteam alice bob "hello"'`. Do NOT construct DB paths manually — the scripts handle path resolution internally. If you need to redirect storage, use `AGMSG_STORAGE_PATH` (the supported override). + +## Identity + +If you already know your AGENT and TEAMS from a previous `/__SKILL_NAME__` use in this session, skip to **Execute** below. + +Otherwise, run: `~/.agents/skills/__SKILL_NAME__/scripts/whoami.sh "$(pwd)" devin` + +Four possible outputs: + +**A) Single identity:** +`agent= teams= type=devin project=` +→ Remember AGENT and TEAMS, then go to **Execute**. + +**B) Multiple identities:** +`multiple=true agents= teams= type=devin project=` +→ Ask the user which agent name to use for this session, then go to **Execute**. + +**C) Not in a team:** +`not_joined=true available_teams=` (or `available_teams=none`) +→ Show the user the available teams from the output, then: + + Before first-time setup, inspect the user's request. If they ask to join, import, or bring in a team that already exists on a server, do not call `join.sh`. Go directly to `remote pull` under Execute. First run `~/.agents/skills/__SKILL_NAME__/scripts/team-list.sh --json --scope all`; if a same-named local team has `binding_state` `none` or `disconnected`, stop and ask the user how to proceed. After pull succeeds, return to Identity setup so the user can register a new local agent in the pulled team. + + > **First-time setup required.** + > Joining a team so this agent can send and receive messages. + > - **Team name**: a group of agents that can message each other (available: ) + > - **Agent name**: this agent's identity within the team + + 1. Ask: "Enter a team name (joins existing or creates new)" + 2. If the team name given already appears in `available_teams`, run `~/.agents/skills/__SKILL_NAME__/scripts/team.sh ` to see the current roster (name, type, project) and note the names already in use. Look for a naming convention already in play (e.g. a shared base name with role and number suffixes (`-`), or names derived from the team name) and, when one exists, propose 2-3 unused names that extend it; otherwise propose 2-3 short, distinctive identity names (not a bare tool-type label like `codex`/`cc`). Either way, names must not collide with the roster. Then ask: "Enter a name for this agent (suggestions: , , — or type your own)". For a brand-new team, skip the roster check and just ask: "Enter a name for this agent". + 3. **You MUST use join.sh** — run: `~/.agents/skills/__SKILL_NAME__/scripts/join.sh devin "$(pwd)"` + 4. Show the result and explain: + + > **Joined!** You can now use `/__SKILL_NAME__` to check and send messages. + > - ask to check inbox — check unread messages + > - ask `send ` — send a message + > - ask `team` — list team members + > - ask `history` — message history + + 5. Devin has no agmsg automatic delivery hook. Set manual delivery explicitly: + `~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh set off devin "$(pwd)"` + + 6. Then check inbox for the newly joined team. + +**D) Suggestions for reuse:** +`suggest=true agents= teams= type=devin project= available_teams=` +→ No exact registration exists for this project, but there are same-type agent names registered elsewhere. + + 1. Show the suggested agent names to the user. + 2. Ask whether to reuse one of those names or choose a new one. + 3. Ask for the team name to join (existing or new). + 4. Run: `~/.agents/skills/__SKILL_NAME__/scripts/join.sh devin "$(pwd)"` + 5. Then continue with the normal post-join flow above. + +## Execute + +**Only use scripts in `~/.agents/skills/__SKILL_NAME__/scripts/` — do not read or modify files under `teams/` or `db` directly.** + +**If no arguments provided (DEFAULT action — always do this when the command is invoked without arguments):** +1. **IMMEDIATELY** run inbox check for each TEAM: `~/.agents/skills/__SKILL_NAME__/scripts/inbox.sh $TEAM $AGENT` +2. Do NOT ask the user what to do — just run the inbox check. +3. If there are messages, read and respond appropriately. To reply: + `~/.agents/skills/__SKILL_NAME__/scripts/send.sh $TEAM $AGENT ""` + +If argument is "history": +1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/history.sh $TEAM $AGENT` + +If argument starts with "team list" (e.g. "team list", "team list --json", "team list --scope project"): +1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/team-list.sh ` +2. This is a distinct command from bare "team" below — check for "team list" FIRST so "list" is never mistaken for a team name. + +If argument is "team": +1. For each TEAM, run: `~/.agents/skills/__SKILL_NAME__/scripts/team.sh $TEAM` + +If argument starts with "send" (e.g. "send misaki check the server"): +1. Parse target agent and message from the arguments +2. Determine which team the target agent belongs to, then run: + `~/.agents/skills/__SKILL_NAME__/scripts/send.sh $TEAM $AGENT ""` + +If argument is "config": +1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/config.sh show` +2. Show the output to the user. + +If argument starts with "config set" (e.g. "config set hook.check_interval 30"): +1. Parse key and value from the arguments. +2. Run: `~/.agents/skills/__SKILL_NAME__/scripts/config.sh set ` + +If argument starts with "actas" followed by an agent name (e.g. "actas alice"): +1. Parse the new role name. If none was given (e.g. bare "actas", or the user asks you to suggest one), run `~/.agents/skills/__SKILL_NAME__/scripts/team.sh ` for each TEAM to see the current roster. Look for a naming convention already in play (e.g. a shared base name with role and number suffixes (`-`), or names derived from the team name) and, when one exists, propose 2-3 unused names that extend it; otherwise propose 2-3 short, distinctive identity names (not a bare tool-type label). Either way, names must not collide with the roster. Ask the user to pick one or type their own before continuing. +2. Run `~/.agents/skills/__SKILL_NAME__/scripts/identities.sh "$(pwd)" devin` to see whether the role is already registered for this (project, type). +3. If the name does not appear in the output, join under the existing team. For a single team, run `~/.agents/skills/__SKILL_NAME__/scripts/join.sh devin "$(pwd)"`. For multiple teams, ask the user which team to join the new role into. +4. Set the session's active FROM to `` for every `send.sh` call until another `actas`. +5. Tell the user: "Now acting as ``. Sends will use `` as the from agent." + +If argument starts with "drop" followed by an agent name (e.g. "drop alice"): +1. Parse the role name. +2. Run `~/.agents/skills/__SKILL_NAME__/scripts/reset.sh "$(pwd)" devin ` to remove that role's registration. +3. If the session's active FROM was ``, clear that state. +4. Tell the user: "Dropped role `` from this project." + +If argument is "mode" (no further args): +1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh status devin "$(pwd)"` +2. Show the output to the user. + +If argument starts with "mode" followed by a mode name (e.g. "mode off"): +1. Parse the mode. Devin supports only `off`. +2. If the requested mode is `off`, run: `~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh set off devin "$(pwd)"` +3. If the requested mode is `monitor`, `both`, or `turn`, do not run a command; tell the user: "Devin has no agmsg automatic delivery hook; only `off` mode is supported." + +If argument is "hook on" (legacy alias): +1. Tell the user: "Devin has no agmsg automatic delivery hook; use manual inbox checks." + +If argument is "hook off" (legacy alias): +1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh set off devin "$(pwd)"` +2. Tell the user: "Delivery mode set to 'off'." + +If argument is "version": +1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/version.sh` +2. Show the output — the installed version (git-describe provenance recorded at install time). + +If argument is "reset": +1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/reset.sh "$(pwd)" devin` +2. Tell the user the result. + +If argument starts with "rename" but not "rename-team": +1. Accept only an explicit user request. Parse either ` `, or ` ` only when this agent belongs to exactly one team. +2. Never invent either name. Before execution, repeat the resolved team, old name, and new name and ask the user to confirm. Wait for confirmation. +3. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/rename.sh ` +4. Show the result. For a connected team, the `member_renamed` journal event propagates the rename to other machines. + +If argument starts with "rename-team": +1. Accept only an explicit user request. Parse ` `. +2. Never invent either team name. Before execution, repeat the old and new team names and ask the user to confirm. Wait for confirmation. +3. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/rename-team.sh ` +4. Show the result. + +If argument starts with "remote connect": +1. Parse the required `--endpoint ` and ``, plus optional `--e2ee`. +2. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/remote.sh connect --endpoint [--e2ee] ` +3. Show the output to the user. Plain sync is the default; pass `--e2ee` only when the user explicitly requests end-to-end encryption. The choice is fixed by the first connect. +4. End by showing this copy-paste command for the other machine, with the actual endpoint and team substituted: `bash ~/.agents/skills/__SKILL_NAME__/scripts/remote.sh pull --endpoint ` + +If argument starts with "remote pull": +1. When the user asks to join or bring in a team that already exists on a server, NEVER use `join.sh`, create a team, or create a same-named local team. Always use remote pull. +2. Before pulling, check for a same-named local team. If one already exists without an active remote connection, stop and ask the user how to proceed; do not overwrite, merge, connect, or rename it on your own. +3. Parse the required `--endpoint ` and ``, plus optional `--team-id `. +4. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/remote.sh pull --endpoint [--team-id ] ` +5. Show the output to the user. + +Machine B needs its own install, not just its own environment variables. +Only `remote.sh`, `remote-sync.sh`, `key.sh` and the two internal helpers read +`AGMSG_SYNC_CONNECTION_DIR`; `send.sh`, `history.sh`, `team.sh` and `inbox.sh` +resolve the team config from the install directory. So a pull driven by +environment variables alone succeeds, and the send that is supposed to confirm +it then reports the team as missing — the failure lands one step after the +cause. See "Use a separate install for testing" in `docs/remote-setup.md`. + +**What e2ee changes, and what it doesn't.** The local store stays plaintext either way — `history`, `inbox`, and `send` read and write exactly the same regardless of a team's encryption setting. Only the SERVER side differs: an e2ee team's server rows carry `cipher: age-v1` and hold sealed ciphertext, so `from`, `to`, and `body` are not readable there; a plain team's rows are not sealed. Keys never pass through the server — moving one to another machine means carrying a handoff bundle by hand (`key handoff` above). + +**Readable local history is therefore not evidence that a team is unencrypted.** To state whether a given team is e2ee, ask the program — `remote status ` below — never infer it from what you can read locally. + +If argument starts with "remote unlock": +1. Parse ``, `--bundle `, and `--confirm-digest `. +2. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/remote.sh unlock --bundle --confirm-digest ` +3. The snapshot digest must be compared over a separate live channel. Never infer or auto-confirm it. The bundle is permanent secret key material; tell the user to transfer and handle it only through their own trusted channel, never by pasting it into agent chat. +4. Show the complete result, including the imported-envelope count and engine PID. +5. The advanced form with repeatable `--snapshot` plus `--identity` or `--identity-stdin` remains available when explicitly requested. + +If argument starts with "remote status": +1. Parse an optional `` and `--json`. +2. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/remote.sh status [] [--json]` +3. Show the output to the user. + +If argument starts with "remote sync start": +1. Parse the required ``. +2. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/remote.sh sync start ` +3. Show the output to the user. + +If argument starts with "remote disconnect": +1. Parse the required ``. +2. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/remote.sh disconnect ` +3. Show the output to the user. + +If argument starts with "remote forget": +1. Parse the required ``. This permanently deletes that team's local roster, history, keys, trust, and sync state, but never changes the server. +2. Do not add `--yes` yourself. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/remote.sh forget ` +3. The command requires the user to confirm in their terminal. If this agent has no interactive terminal, show the deletion summary and tell the user to rerun the displayed command directly; never bypass confirmation for them. + +If argument starts with "key generate" followed by an optional team name: +1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/key.sh generate []` +2. Show the full output to the user, including the mandatory key-backup notice — do not summarize it away. + +If argument starts with "key show": +1. Parse an optional team name and `--reveal-secret`. +2. Run: `~/.agents/skills/__SKILL_NAME__/scripts/key.sh show [] [--reveal-secret]` +3. `--reveal-secret` requires a real interactive terminal and is refused in agent mode — if the user wants to reveal a secret, tell them to run it themselves directly in their own terminal rather than through you. +4. Show the output to the user. + +If argument starts with "key handoff" followed by a team name: +1. Parse optional `--out ` and run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/key.sh handoff [--out ]` +2. The output bundle contains every epoch identity and is itself permanent secret key material. Never read it into agent chat or display its contents. +3. Show the bundle path, latest snapshot digest, and full secrecy warning. + +If argument starts with "key import" followed by a team name: +1. **Do not ask the user to paste the private identity into this chat, and do not run this command yourself.** This identity is a permanent secret. Tell the user to run this directly in their own terminal: + ``` + read -rsp 'Identity: ' IDENTITY; echo + printf '%s' "$IDENTITY" | ~/.agents/skills/__SKILL_NAME__/scripts/key.sh import --identity-stdin + unset IDENTITY + ``` +2. Ask them to paste back only the command's output (never the identity itself) once it's done. +3. **No advanced/automation env-var path is offered for key import** — not even a pre-existing, before-session variable. An identity file is a permanent secret; always use the human-in-own-terminal flow above. + +If argument starts with "key rotate" followed by a team name: +1. Rotation mints a replacement epoch for a team that already has a key and announces it on the roster journal. It requires an existing current key, an identity journal (connect or migrate the team first), and `age`; it refuses with a message naming whichever is missing. +2. Confirm with the user before running it. It changes the team's key state, and every other machine has to receive the new identity out of band. +3. Run: `bash ~/.agents/skills/__SKILL_NAME__/scripts/key.sh rotate ` +4. Show the output: epoch, key_id, and recipient fingerprint. The private key is never written to the journal. Revealing it needs `key show --key-id --reveal-secret`, which is refused in agent mode — tell the user to run that in their own terminal. +5. Messages before the acknowledged rotation boundary remain readable with the old key. + +Device pairing (`key request` / `key approve`) is not implemented — they are not `key.sh` subcommands, so a call prints usage and exits 1. If the user asks for one, tell them so instead of attempting to run it. diff --git a/scripts/drivers/types/devin/type.conf b/scripts/drivers/types/devin/type.conf new file mode 100644 index 000000000..998d7cad5 --- /dev/null +++ b/scripts/drivers/types/devin/type.conf @@ -0,0 +1,7 @@ +# agmsg agent-type manifest — read-only key=value DATA. NEVER sourced. +name=devin +template=template.md +cli=devin +detect_proc=devin devin-* +monitor=no +delivery_modes=off diff --git a/site/src/i18n/de.js b/site/src/i18n/de.js index 1e68d08e5..d5a52dd6d 100644 --- a/site/src/i18n/de.js +++ b/site/src/i18n/de.js @@ -70,7 +70,8 @@ export default { copilot: "GitHub Copilot in der Shell.", cursor: "Cursors Headless-CLI-Agent.", opencode: "Open-Source-Coding-Agent.", - "grok-build": "xAIs Build-/Coding-Agent.", + devin: "Autonomer KI-Software-Ingenieur-CLI.", + "grok-build": "Build/Coding-Agent von xAI.", hermes: "Leichtgewichtiger Relay-Agent.", antigravity: "Agentische Coding-Umgebung.", }, diff --git a/site/src/i18n/en.js b/site/src/i18n/en.js index e1364fe7f..a1e80a8f0 100644 --- a/site/src/i18n/en.js +++ b/site/src/i18n/en.js @@ -70,6 +70,7 @@ export default { copilot: "GitHub Copilot in the shell.", cursor: "Cursor's headless CLI agent.", opencode: "Open-source coding agent.", + devin: "Autonomous AI software engineer CLI.", "grok-build": "xAI's build/coding agent.", hermes: "Lightweight relay agent.", antigravity: "Agentic coding environment.", diff --git a/site/src/i18n/es.js b/site/src/i18n/es.js index 9d3979ffa..f48b6c930 100644 --- a/site/src/i18n/es.js +++ b/site/src/i18n/es.js @@ -69,8 +69,9 @@ export default { gemini: "El agente de codificación CLI de Google.", copilot: "GitHub Copilot en la terminal.", cursor: "El agente CLI de Cursor sin interfaz gráfica.", - opencode: "Agente de codificación de código abierto.", - "grok-build": "El agente de compilación/codificación de xAI.", + opencode: "Agente de código abierto.", + devin: "CLI de ingeniero de software de IA autónomo.", + "grok-build": "Agente de build/código de xAI.", hermes: "Agente de retransmisión ligero.", antigravity: "Entorno de codificación agéntico.", }, diff --git a/site/src/i18n/fr.js b/site/src/i18n/fr.js index 013b2fbe7..8827dcfe0 100644 --- a/site/src/i18n/fr.js +++ b/site/src/i18n/fr.js @@ -70,6 +70,7 @@ export default { copilot: "GitHub Copilot dans le shell.", cursor: "L'agent CLI headless de Cursor.", opencode: "Agent de codage open source.", + devin: "CLI d'ingénieur logiciel IA autonome.", "grok-build": "L'agent de build/codage de xAI.", hermes: "Agent relais léger.", antigravity: "Environnement de codage agentique.", diff --git a/site/src/i18n/ja.js b/site/src/i18n/ja.js index f90ca11bb..cc7385d3c 100644 --- a/site/src/i18n/ja.js +++ b/site/src/i18n/ja.js @@ -68,6 +68,7 @@ export default { copilot: "シェルで使うGitHub Copilot", cursor: "Cursorのヘッドレス版CLIエージェント", opencode: "オープンソースのコーディングエージェント", + devin: "自律型AIソフトウェアエンジニアCLI", "grok-build": "xAIのビルド/コーディングエージェント", hermes: "軽量なリレーエージェント", antigravity: "エージェント型のコーディング環境", diff --git a/site/src/i18n/ko.js b/site/src/i18n/ko.js index cd7e3dd1f..2165ee68d 100644 --- a/site/src/i18n/ko.js +++ b/site/src/i18n/ko.js @@ -68,6 +68,7 @@ export default { copilot: "셸에서 사용하는 GitHub Copilot.", cursor: "Cursor의 헤드리스 CLI 에이전트.", opencode: "오픈소스 코딩 에이전트.", + devin: "자율형 AI 소프트웨어 엔지니어 CLI.", "grok-build": "xAI의 빌드/코딩 에이전트.", hermes: "경량 릴레이 에이전트.", antigravity: "에이전틱 코딩 환경.", diff --git a/site/src/i18n/pt-BR.js b/site/src/i18n/pt-BR.js index 0086608f1..bb1186e1d 100644 --- a/site/src/i18n/pt-BR.js +++ b/site/src/i18n/pt-BR.js @@ -69,8 +69,9 @@ export default { gemini: "Agente de codificação de CLI do Google.", copilot: "GitHub Copilot no terminal.", cursor: "Agente de CLI headless do Cursor.", - opencode: "Agente de codificação open-source.", - "grok-build": "Agente de build/codificação da xAI.", + opencode: "Agente de codificação open source.", + devin: "CLI de engenheiro de software de IA autônomo.", + "grok-build": "Agente de build/código da xAI.", hermes: "Agente de relay leve.", antigravity: "Ambiente de codificação agêntico.", }, diff --git a/site/src/i18n/zh-CN.js b/site/src/i18n/zh-CN.js index 783e04f53..e7c8c125c 100644 --- a/site/src/i18n/zh-CN.js +++ b/site/src/i18n/zh-CN.js @@ -68,6 +68,7 @@ export default { copilot: "在终端中使用的 GitHub Copilot。", cursor: "Cursor 的无头 CLI 智能体。", opencode: "开源编程智能体。", + devin: "自主AI软件工程师CLI。", "grok-build": "xAI 的构建/编程智能体。", hermes: "轻量级中继智能体。", antigravity: "智能体编程环境。", diff --git a/site/src/i18n/zh-TW.js b/site/src/i18n/zh-TW.js index 550f753b6..12ae7e8e6 100644 --- a/site/src/i18n/zh-TW.js +++ b/site/src/i18n/zh-TW.js @@ -69,8 +69,9 @@ export default { gemini: "Google 的 CLI 編碼代理。", copilot: "在終端機中使用的 GitHub Copilot。", cursor: "Cursor 的無頭 CLI 代理。", - opencode: "開源編碼代理。", - "grok-build": "xAI 的建置/編碼代理。", + opencode: "開源程式設計代理。", + devin: "自主AI軟體工程師CLI。", + "grok-build": "xAI 的建置/程式設計代理。", hermes: "輕量級中繼代理。", antigravity: "代理式編碼環境。", }, diff --git a/site/src/layouts/Home.astro b/site/src/layouts/Home.astro index 2ae781075..c1dc160ca 100644 --- a/site/src/layouts/Home.astro +++ b/site/src/layouts/Home.astro @@ -33,6 +33,7 @@ const META = { copilot: { label: "Copilot CLI", logo: "/logos/copilot.svg", blurb: "GitHub Copilot in the shell." }, cursor: { label: "Cursor Agent", logo: null, blurb: "Cursor's headless CLI agent." }, opencode: { label: "OpenCode", logo: "/logos/opencode.svg", blurb: "Open-source coding agent.", mono: true }, + devin: { label: "Devin", logo: null, blurb: "Autonomous AI software engineer CLI." }, "grok-build": { label: "Grok Build", logo: "/logos/grok.svg", blurb: "xAI's build/coding agent.", mono: true }, hermes: { label: "Hermes", logo: "/logos/hermes.png", blurb: "Lightweight relay agent." }, antigravity: { label: "Antigravity", logo: "/logos/antigravity.png", blurb: "Agentic coding environment." }, diff --git a/tests/test_delivery.bats b/tests/test_delivery.bats index d99f562d3..e60866990 100644 --- a/tests/test_delivery.bats +++ b/tests/test_delivery.bats @@ -2658,6 +2658,38 @@ JSON wait 2>/dev/null || true } +# --- devin (manual-only: delivery_modes=off, no automatic hook) --- + +@test "delivery devin: status is manual/off" { + run bash "$SCRIPTS/delivery.sh" status devin "$TEST_PROJECT" + [ "$status" -eq 0 ] + [[ "$output" =~ "mode: off" ]] +} + +@test "delivery devin: rejects automatic modes" { + local mode + for mode in turn monitor both; do + run bash "$SCRIPTS/delivery.sh" set "$mode" devin "$TEST_PROJECT" + [ "$status" -ne 0 ] + [[ "$output" =~ "not supported for devin" ]] + done +} + +@test "delivery devin: rejects unknown mode" { + run bash "$SCRIPTS/delivery.sh" set bogus devin "$TEST_PROJECT" + [ "$status" -ne 0 ] + [[ "$output" =~ "Unknown mode" ]] +} + +@test "delivery devin: accepts off without error" { + run bash "$SCRIPTS/delivery.sh" set off devin "$TEST_PROJECT" + [ "$status" -eq 0 ] + [[ "$output" =~ "Delivery mode set to 'off'" ]] + [[ "$output" =~ "manual inbox checks only" ]] + [[ "$output" != *"AGMSG-DIRECTIVE"* ]] +} + + # --- grok-build (turn|off via a markdown rule file .grok/rules/agmsg.md) --- # Grok passive hooks can't inject (stdout is discarded), so grok delivers via the # rule-file self-poll model (like gemini/opencode): a .grok/rules/agmsg.md that diff --git a/tests/test_type_registry.bats b/tests/test_type_registry.bats index 07799d885..e6cb24304 100644 --- a/tests/test_type_registry.bats +++ b/tests/test_type_registry.bats @@ -29,11 +29,11 @@ write_node_launcher_fixtures() { printf '// stub node launcher fixture\n' > "$nd/nodetype-launcher.mjs" } -@test "type-registry: known_types lists the ten built-ins" { +@test "type-registry: known_types lists the eleven built-ins" { run env -i PATH="$PATH" bash -c \ "source '$SCRIPTS/lib/type-registry.sh'; agmsg_known_types | sort -u | paste -sd, -" [ "$status" -eq 0 ] - [ "$output" = "agmsg-app,antigravity,claude-code,codex,copilot,cursor,gemini,grok-build,hermes,opencode" ] + [ "$output" = "agmsg-app,antigravity,claude-code,codex,copilot,cursor,devin,gemini,grok-build,hermes,opencode" ] } @test "type-registry: is_known_type accepts a built-in and rejects a bogus type" { @@ -92,9 +92,9 @@ write_node_launcher_fixtures() { } @test "agent templates all explain that readable local history is not evidence a team is unencrypted (#682)" { - # scripts/drivers/types/*/template.md is nine independent copies with no + # scripts/drivers/types/*/template.md is ten independent copies with no # shared fragment (#676's exact shape) -- a loop with `[ -f ] || continue` - # alone would silently pass if the glob matched fewer than nine files (a + # alone would silently pass if the glob matched fewer than ten files (a # renamed/missing template), so the count is asserted explicitly rather # than just "every file found had it." local template count=0 @@ -105,9 +105,9 @@ write_node_launcher_fixtures() { || { echo "missing the e2ee-verification paragraph: $template" >&2; return 1; } done # agmsg-app has no template.md (spawnable=no -- it's the desktop app's own - # identity, not a CLI type), so nine is the whole set, not a lower bound a + # identity, not a CLI type), so ten is the whole set, not a lower bound a # silently-skipped file could still satisfy. - [ "$count" -eq 9 ] + [ "$count" -eq 10 ] } @test "the e2ee-verification explanation also appears in both remote-setup docs (#682)" { @@ -156,8 +156,8 @@ write_node_launcher_fixtures() { ! grep -qiE 'rotat(e|ion)[^.]*not available' "$surface" \ || { echo "still calls rotation unavailable: $surface" >&2; return 1; } done - # nine templates (agmsg-app has none) plus SKILL.md. - [ "$count" -eq 10 ] + # ten templates (agmsg-app has none) plus SKILL.md. + [ "$count" -eq 11 ] # Bind the claim to the code. If `rotate` ever stops being a subcommand the # surfaces above become wrong again, and this is the line that says so. @@ -170,8 +170,8 @@ write_node_launcher_fixtures() { grep -Fq 'To mint a replacement epoch instead:' "$BATS_TEST_DIRNAME/../scripts/key.sh" } -@test "type-registry: spawnable set is exactly eight of the ten built-ins (#277, #279)" { - # hermes deliberately stays out (#279): no known CLI mode starts it +@test "type-registry: spawnable set is exactly eight of the eleven built-ins (#277, #279)" { + # hermes and devin deliberately stay out (#279): no known CLI mode starts them # interactive with a seeded initial prompt. agmsg-app also stays out: it's # the desktop app itself (spawnable=no), not a spawnable agent type. run env -i PATH="$PATH" bash -c \ From d79c3544932458ac467b5ea1a1b92dc6fcb60821 Mon Sep 17 00:00:00 2001 From: m1kekad0 Date: Wed, 19 Aug 2026 20:37:55 +0900 Subject: [PATCH 2/4] docs: clarify Devin spawn support status AI-assisted-by: Gemini 3.7 Flash --- README.ja.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.ja.md b/README.ja.md index 678ba90cf..0734fdb25 100644 --- a/README.ja.md +++ b/README.ja.md @@ -210,7 +210,7 @@ codex: --dangerously-skip-permissions: false # `false`の値はフラグ自体を出力しない ``` -10種類のエージェントタイプのうち8つがspawn可能 — `claude-code`、`codex`、`grok-build`、`cursor`、`gemini`、`antigravity`、`copilot`、`opencode`。`hermes` と `devin` は不可 — 初期プロンプトを事前に仕込んだインタラクティブセッションを開始するモードがない。macOSが主なターゲットで、LinuxとWindowsはベストエフォート(ターミナルが未対応の場合はissueまたはPRを歓迎)。ヘッドレス環境 — tmuxもなく使えるターミナルもない — はエージェントCLIがインタラクティブなターミナルを必要とするためエラーになる。 +10種類のエージェントタイプのうち8つがspawn可能 — `claude-code`、`codex`、`grok-build`、`cursor`、`gemini`、`antigravity`、`copilot`、`opencode`。`hermes` は、初期プロンプトを事前に仕込んだインタラクティブセッションを開始する既知のCLIモードがないためspawn不可(#279)。`devin` は、同等のインタラクティブ起動方法がまだ検証されていないため、現時点ではspawnableとして扱っていない。macOSが主なターゲットで、LinuxとWindowsはベストエフォート(ターミナルが未対応の場合はissueまたはPRを歓迎)。ヘッドレス環境 — tmuxもなく使えるターミナルもない — はエージェントCLIがインタラクティブなターミナルを必要とするためエラーになる。 ### spawnしたエージェントを終了する(`despawn`) diff --git a/README.md b/README.md index a6ccdfd3a..09551810a 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ codex: --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` and `devin` are not: their CLIs do not have a known interactive session boot mode pre-seeded with an initial prompt. 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. +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`) From 39c8e573b7946e25bdf7e7aaf3fcb4d6f7f4275d Mon Sep 17 00:00:00 2001 From: m1kekad0 Date: Wed, 19 Aug 2026 20:53:16 +0900 Subject: [PATCH 3/4] chore: narrow Devin agent type diff AI-assisted-by: Gemini 3.7 Flash --- docs/agent-types.md | 2 +- site/src/i18n/de.js | 4 ++-- site/src/i18n/en.js | 2 +- site/src/i18n/es.js | 6 +++--- site/src/i18n/fr.js | 2 +- site/src/i18n/ja.js | 2 +- site/src/i18n/ko.js | 2 +- site/src/i18n/pt-BR.js | 6 +++--- site/src/i18n/zh-CN.js | 2 +- site/src/i18n/zh-TW.js | 6 +++--- tests/test_delivery.bats | 1 - 11 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/agent-types.md b/docs/agent-types.md index ef1a17a61..8a895ff3f 100644 --- a/docs/agent-types.md +++ b/docs/agent-types.md @@ -1,7 +1,7 @@ # Agent types agmsg supports several agent runtimes — claude-code, codex, gemini, antigravity, -copilot, opencode, hermes, cursor, devin, grok-build — and each is described by a small **manifest** so that the rest +copilot, opencode, hermes, cursor, devin — and each is described by a small **manifest** so that the rest of agmsg (detection, the join whitelist, spawn, and delivery routing) discovers it from data instead of hardcoded `case` arms. diff --git a/site/src/i18n/de.js b/site/src/i18n/de.js index d5a52dd6d..bdd93d71c 100644 --- a/site/src/i18n/de.js +++ b/site/src/i18n/de.js @@ -70,10 +70,10 @@ export default { copilot: "GitHub Copilot in der Shell.", cursor: "Cursors Headless-CLI-Agent.", opencode: "Open-Source-Coding-Agent.", - devin: "Autonomer KI-Software-Ingenieur-CLI.", - "grok-build": "Build/Coding-Agent von xAI.", + "grok-build": "xAIs Build-/Coding-Agent.", hermes: "Leichtgewichtiger Relay-Agent.", antigravity: "Agentische Coding-Umgebung.", + devin: "Autonomer KI-Software-Ingenieur-CLI.", }, }, showcase: { diff --git a/site/src/i18n/en.js b/site/src/i18n/en.js index a1e80a8f0..69fd15a35 100644 --- a/site/src/i18n/en.js +++ b/site/src/i18n/en.js @@ -70,10 +70,10 @@ export default { copilot: "GitHub Copilot in the shell.", cursor: "Cursor's headless CLI agent.", opencode: "Open-source coding agent.", - devin: "Autonomous AI software engineer CLI.", "grok-build": "xAI's build/coding agent.", hermes: "Lightweight relay agent.", antigravity: "Agentic coding environment.", + devin: "Autonomous AI software engineer CLI.", }, }, showcase: { diff --git a/site/src/i18n/es.js b/site/src/i18n/es.js index f48b6c930..17ba3914d 100644 --- a/site/src/i18n/es.js +++ b/site/src/i18n/es.js @@ -69,11 +69,11 @@ export default { gemini: "El agente de codificación CLI de Google.", copilot: "GitHub Copilot en la terminal.", cursor: "El agente CLI de Cursor sin interfaz gráfica.", - opencode: "Agente de código abierto.", - devin: "CLI de ingeniero de software de IA autónomo.", - "grok-build": "Agente de build/código de xAI.", + opencode: "Agente de codificación de código abierto.", + "grok-build": "El agente de compilación/codificación de xAI.", hermes: "Agente de retransmisión ligero.", antigravity: "Entorno de codificación agéntico.", + devin: "CLI de ingeniero de software de IA autónomo.", }, }, showcase: { diff --git a/site/src/i18n/fr.js b/site/src/i18n/fr.js index 8827dcfe0..577e80cbd 100644 --- a/site/src/i18n/fr.js +++ b/site/src/i18n/fr.js @@ -70,10 +70,10 @@ export default { copilot: "GitHub Copilot dans le shell.", cursor: "L'agent CLI headless de Cursor.", opencode: "Agent de codage open source.", - devin: "CLI d'ingénieur logiciel IA autonome.", "grok-build": "L'agent de build/codage de xAI.", hermes: "Agent relais léger.", antigravity: "Environnement de codage agentique.", + devin: "CLI d'ingénieur logiciel IA autonome.", }, }, showcase: { diff --git a/site/src/i18n/ja.js b/site/src/i18n/ja.js index cc7385d3c..a7757fa3b 100644 --- a/site/src/i18n/ja.js +++ b/site/src/i18n/ja.js @@ -68,10 +68,10 @@ export default { copilot: "シェルで使うGitHub Copilot", cursor: "Cursorのヘッドレス版CLIエージェント", opencode: "オープンソースのコーディングエージェント", - devin: "自律型AIソフトウェアエンジニアCLI", "grok-build": "xAIのビルド/コーディングエージェント", hermes: "軽量なリレーエージェント", antigravity: "エージェント型のコーディング環境", + devin: "自律型AIソフトウェアエンジニアCLI", }, }, showcase: { diff --git a/site/src/i18n/ko.js b/site/src/i18n/ko.js index 2165ee68d..0bafb5ea2 100644 --- a/site/src/i18n/ko.js +++ b/site/src/i18n/ko.js @@ -68,10 +68,10 @@ export default { copilot: "셸에서 사용하는 GitHub Copilot.", cursor: "Cursor의 헤드리스 CLI 에이전트.", opencode: "오픈소스 코딩 에이전트.", - devin: "자율형 AI 소프트웨어 엔지니어 CLI.", "grok-build": "xAI의 빌드/코딩 에이전트.", hermes: "경량 릴레이 에이전트.", antigravity: "에이전틱 코딩 환경.", + devin: "자율형 AI 소프트웨어 엔지니어 CLI.", }, }, showcase: { diff --git a/site/src/i18n/pt-BR.js b/site/src/i18n/pt-BR.js index bb1186e1d..17dd4ee26 100644 --- a/site/src/i18n/pt-BR.js +++ b/site/src/i18n/pt-BR.js @@ -69,11 +69,11 @@ export default { gemini: "Agente de codificação de CLI do Google.", copilot: "GitHub Copilot no terminal.", cursor: "Agente de CLI headless do Cursor.", - opencode: "Agente de codificação open source.", - devin: "CLI de engenheiro de software de IA autônomo.", - "grok-build": "Agente de build/código da xAI.", + opencode: "Agente de codificação open-source.", + "grok-build": "Agente de build/codificação da xAI.", hermes: "Agente de relay leve.", antigravity: "Ambiente de codificação agêntico.", + devin: "CLI de engenheiro de software de IA autônomo.", }, }, showcase: { diff --git a/site/src/i18n/zh-CN.js b/site/src/i18n/zh-CN.js index e7c8c125c..cf3a35c1a 100644 --- a/site/src/i18n/zh-CN.js +++ b/site/src/i18n/zh-CN.js @@ -68,10 +68,10 @@ export default { copilot: "在终端中使用的 GitHub Copilot。", cursor: "Cursor 的无头 CLI 智能体。", opencode: "开源编程智能体。", - devin: "自主AI软件工程师CLI。", "grok-build": "xAI 的构建/编程智能体。", hermes: "轻量级中继智能体。", antigravity: "智能体编程环境。", + devin: "自主AI软件工程师CLI。", }, }, showcase: { diff --git a/site/src/i18n/zh-TW.js b/site/src/i18n/zh-TW.js index 12ae7e8e6..b5d62acad 100644 --- a/site/src/i18n/zh-TW.js +++ b/site/src/i18n/zh-TW.js @@ -69,11 +69,11 @@ export default { gemini: "Google 的 CLI 編碼代理。", copilot: "在終端機中使用的 GitHub Copilot。", cursor: "Cursor 的無頭 CLI 代理。", - opencode: "開源程式設計代理。", - devin: "自主AI軟體工程師CLI。", - "grok-build": "xAI 的建置/程式設計代理。", + opencode: "開源編碼代理。", + "grok-build": "xAI 的建置/編碼代理。", hermes: "輕量級中繼代理。", antigravity: "代理式編碼環境。", + devin: "自主AI軟體工程師CLI。", }, }, showcase: { diff --git a/tests/test_delivery.bats b/tests/test_delivery.bats index e60866990..a4ef91ea0 100644 --- a/tests/test_delivery.bats +++ b/tests/test_delivery.bats @@ -2689,7 +2689,6 @@ JSON [[ "$output" != *"AGMSG-DIRECTIVE"* ]] } - # --- grok-build (turn|off via a markdown rule file .grok/rules/agmsg.md) --- # Grok passive hooks can't inject (stdout is discarded), so grok delivers via the # rule-file self-poll model (like gemini/opencode): a .grok/rules/agmsg.md that From 0dc0e4ccb8c63b905689134027c6c0ea6451f304 Mon Sep 17 00:00:00 2001 From: m1kekad0 Date: Wed, 19 Aug 2026 23:14:09 +0900 Subject: [PATCH 4/4] test: make Devin assertions enforceable AI-assisted-by: Gemini 3.7 Flash --- tests/test_delivery.bats | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_delivery.bats b/tests/test_delivery.bats index a4ef91ea0..6bfffe4a7 100644 --- a/tests/test_delivery.bats +++ b/tests/test_delivery.bats @@ -2684,9 +2684,9 @@ JSON @test "delivery devin: accepts off without error" { run bash "$SCRIPTS/delivery.sh" set off devin "$TEST_PROJECT" [ "$status" -eq 0 ] - [[ "$output" =~ "Delivery mode set to 'off'" ]] - [[ "$output" =~ "manual inbox checks only" ]] - [[ "$output" != *"AGMSG-DIRECTIVE"* ]] + grep -qF "Delivery mode set to 'off'" <<<"$output" + grep -qF "manual inbox checks only" <<<"$output" + refute grep -qF "AGMSG-DIRECTIVE" <<<"$output" } # --- grok-build (turn|off via a markdown rule file .grok/rules/agmsg.md) ---