Skip to content

1.1.0 — restructure agent types: driver registry, plugin opt-in, hermes (beta)#181

Merged
fujibee merged 30 commits into
mainfrom
restructure-agent-types
Jun 22, 2026
Merged

1.1.0 — restructure agent types: driver registry, plugin opt-in, hermes (beta)#181
fujibee merged 30 commits into
mainfrom
restructure-agent-types

Conversation

@fujibee

@fujibee fujibee commented Jun 21, 2026

Copy link
Copy Markdown
Owner

1.1.0 — restructure agent types

The release that makes "a type = a directory" real and purges hardcoded
type names from the shared engine. Adding or overriding an agent runtime is now
data (a manifest) plus optional behavior plugs — no edits across the engine
scripts.

Highlights

  • Delivery as a Template Method. delivery.sh defines the default behavior;
    each type's optional scripts/drivers/types/<name>/_delivery.sh overrides any
    of apply / on_enable / on_disable / status. The gnarly JSON/SQLite hook
    layer is extracted to scripts/lib/hooks-json.sh.
  • Engine purification via manifest keys. New delivery_modes, stop_output,
    and hook_windows_wrap keys move the last per-type case arms (codex both
    guard, opencode/copilot mode rejection, codex Windows hook-wrap, stop output
    protocol) into data. A regression test asserts no per-type branch remains in
    the shared scripts.
  • types/scripts/drivers/types/. Agent types now live under
    scripts/drivers/<axis>/ per the driver spec; the codex runtime is folded in
    alongside its manifest.
  • Axis-generic driver registry + external plugin opt-in. driver-registry.sh
    provides the shared discovery bases (scripts/drivers<install>/plugins
    $AGMSG_PLUGIN_DIRS) and trust policy. External drivers are shell code, so
    they are never loaded until opted into (agmsg plugin trust <axis>/<name>);
    trust is path-pinned. New agmsg plugin list|trust|untrust CLI.
  • Hermes beta agent type. New hermes type (manual-only delivery), shipped
    as beta for community verification. Adapted from feat: add Hermes Agent support #118/Follow-up to #118: support Hermes profiles in spawn #119 — thanks @Fewmanism.
  • Docs. ADR 0002 (driver discovery + plugin opt-in), docs/plugins.md,
    refreshed docs/agent-types.md, README Plugins section + npx-first Quick Start.
  • Fix (upgrade path). install.sh --update now re-points an existing Codex
    monitor shim to the relocated path, so users upgrading from 1.0.x keep working
    monitor mode.

Deferred (follow-ups)

  • resolve-project.sh PID-detection binaries → data (1.1.x; low ROI / sensitive path).
  • --hermes-profile (Follow-up to #118: support Hermes profiles in spawn #119) → a generic spawn-profile mechanism, to keep spawn.sh branch-free.
  • A grok-build type → community contribution (issue to follow).

Testing

Required CI green on ubuntu / macos / windows-tests. The full (experimental)
leg is non-required and times out by design (#125).

lucianlamp and others added 23 commits June 20, 2026 22:26
Discover agent types from types/<name>/type.conf manifests instead of hardcoded
case arms across whoami/join/spawn/delivery, so adding a type is a manifest +
template (cf. the 8-file OpenCode addition #136). Detection (detect=/detect_proc=),
the join whitelist, spawn (direct-CLI cli= and Node-launcher spawn=), and delivery
hooks routing (hooks_file=) all read the registry. Manifests are read-only
key=value DATA, never sourced. External add-on types plug in via a spawn= Node
launcher (universal --name/--team/--project/--initial-input flags) and aliases= (a
type owns another's spawn name), needing no built-in edits. The six built-in types
are converted with zero behavior change; full suite 296 -> 312.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… only

Agent types are selected explicitly: 'spawn codex' is plain codex, 'spawn
codex-app-server' is the add-on — no automatic alias hijacks a built-in's spawn
name. Removes agmsg_type_alias_for, spawn.sh's reverse-alias resolution, the
aliases= manifest key (schema + node-launcher docs), and the alias fixture/test.
The node-launcher (spawn=) plug point for external add-ons stays. Full suite
311/311; built-in behavior unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Group the codex-only scripts (codex-bridge.js, codex-bridge-launcher.sh,
codex-monitor.sh, codex-shim.sh, codex-shim-install.sh, watch-once.sh) under
scripts/codex/ so scripts/ top holds the externally-invoked command surface plus
cross-cutting helpers, not a per-agent subsystem.

Path follow-through: moved scripts resolve SKILL_DIR as ../.. and reference
top-level siblings (delivery.sh, identities.sh, inbox.sh, send.sh, lib/) via ../;
codex-internal siblings stay SCRIPT_DIR-relative. External callers updated
(session-start.sh, delivery.sh), install.sh chmods scripts/codex/, tests and docs
point at the new paths. No behavior change.
…rop hook.sh

- scripts/internal/init-db.sh: DB schema init is a pure internal helper (callers:
  send.sh, install.sh). Not baked into any hook config, so it is safe to move.
- scripts/windows/dispatch.sh: the command dispatcher is used only by the Windows
  launcher (agmsg.ps1); co-locate it. dispatch resolves top-level commands via ..;
  agmsg.ps1 now finds it beside itself (PSScriptRoot).
- remove scripts/hook.sh: a long-deprecated alias for 'delivery.sh set turn|off'
  that only printed a deprecation notice and was never invoked by any runtime/hook.
  Drops tests/test_hook.bats, the hook.sh blocks in test_delivery.bats, and the
  README/design/SKILL mentions.

check-inbox.sh deliberately stays at scripts/ top: delivery.sh bakes its absolute
path into the Stop hook in users' settings, so moving it would break turn-mode
delivery on upgrade until 'delivery.sh set' is re-run (same class as
session-start/session-end).
…_env

setup_test_env ran scripts/init-db.sh (now scripts/internal/init-db.sh), so every
test using it failed at setup. Point it at the new path and chmod scripts/codex/
so the relocated codex scripts stay executable in the test skill dir.
Move the SQLite/JSON read-modify-write helpers (sql_readfile_path,
strip_agmsg_event_file, windows_wrap, add_event_entry_file,
prune_empty_hooks_file) out of delivery.sh into a dedicated lib module.
Pure code move — no behavior change. delivery.sh sources it after
SKILL_NAME is set, matching the existing lib convention.

delivery.sh: 754 -> 588 lines.
delivery.sh is now a template: the default agmsg_delivery_apply_default writes the
JSON event-hooks (claude-code, codex), and a type may override it by shipping
types/<name>/_delivery.sh that defines agmsg_delivery_apply. apply_settings()
sources the plug when present, else calls the default — so adding a type's delivery
behavior is dropping one file, no edits to delivery.sh.

- scripts/lib/delivery-rulefile.sh: shared rule-file behavior (markdown rules
  file). gemini/antigravity delegate to it in a one-line _delivery.sh.
- types/opencode/_delivery.sh, types/copilot/_delivery.sh: bespoke (turn|off only;
  copilot writes JSON) — behavior preserved from the old apply_settings_*.
- removes apply_settings_{gemini,copilot,opencode} and the type dispatch from
  delivery.sh.

test_delivery.bats: 87/87 (behavior unchanged).
…op_output=

The codex|copilot JSON status (continue:true) on empty checks (cooldown / no new
messages) was a hardcoded type list. Read it from the type manifest instead:
stop_output=json emits the JSON status object, otherwise stay silent (claude-code).
codex and copilot set stop_output=json. No behavior change (test_delivery 87/87,
incl. the cooldown-status assertion).
# Conflicts:
#	scripts/codex/codex-bridge.js
#	scripts/delivery.sh
#	scripts/spawn.sh
Apply the delivery.sh Template Method pattern to session-start.sh: it now
defines a default no-op agmsg_session_start and, when types/<type>/_session-start.sh
exists, sources it (in the script's context) and calls the override. The
codex-only bridge block — thread-id resolution, app-server discovery, and the
bridge/request-file launch — moves verbatim into types/codex/_session-start.sh.
Behaviour is unchanged; the codex tests (session-start + bridge) stay green.
… smoke

smoke_windows_powershell.ps1 ran scripts/init-db.sh (now scripts/internal/) so the
Windows-tests CI leg failed with exit 127. Point it at the new path. Also fix the
docs/design.md script-table entry.
Completes the template co-location whose file moves landed in c14d1f3:
the manifest template= key (previously dead) is now the source of truth.

- lib/type-registry.sh: add agmsg_type_template_path, resolving template=
  relative to the type dir (rejects absolute/traversal like resolve_hooks_file)
- type.conf x6: template=cmd.<type>.md -> template=template.md
- install.sh: source the type registry; route every SKILL.md / slash-command
  generation through the resolver instead of hardcoded templates/ paths; drop
  the write-only $SKILL_DIR/templates/ ship (no runtime consumer) — templates
  now travel inside types/ via the existing cp -R, as unsubstituted source data
- test_type_registry.bats: expect template.md; cover the new resolver

No behavior change. Full bats suite (353) green incl. an end-to-end install smoke.
…solve

The PowerShell smoke hand-stages the skill dir by copying scripts/ only,
but join.sh (and other commands) validate the agent type through the type
registry, which resolves types/<name>/type.conf relative to the skill dir.
Without types/, 'join … codex' fails with 'Unknown agent type' (exit 1).

This was latent until the init-db path fix let the smoke reach the join
step; copy types/ alongside scripts/ to mirror what install.sh ships.
Reproduced on macOS: no types/ -> exit 1, types/ present -> exit 0.
do_set no longer branches on codex/claude-code. The per-type onboarding (codex
shim install + node preflight + restart guidance; claude-code's Monitor directive)
and teardown (codex bridge stop; default watcher kill) are now agmsg_delivery_on_enable
/ agmsg_delivery_on_disable hooks in types/<name>/_delivery.sh, called generically
by do_set. delivery.sh is now type-agnostic for the set/off paths.

- types/codex/_delivery.sh: on_enable (shim+guidance), on_disable (stop bridge)
- types/claude-code/_delivery.sh: on_enable (Monitor directive)
- delivery.sh: default no-op on_enable / watcher-kill on_disable; do_set calls hooks

test_delivery.bats 87/87 (behavior unchanged). The codex 'both'-mode guard stays
in do_set (a small validation, not a side effect).
do_status no longer branches on the rule-file type list. agmsg_delivery_status
(default: derive mode from json-hooks + print entry detail) is overridden by
rule-file types to report mode from the rule file's presence. delivery.sh is now
type-agnostic for apply / on_enable / on_disable / status; only the codex 'both'
guard names a type.

- delivery.sh: agmsg_delivery_status_default + dispatch in do_status
- delivery-rulefile.sh: rulefile_status (present=turn, absent=off)
- gemini/antigravity/opencode/copilot _delivery.sh: agmsg_delivery_status delegation

test_delivery.bats 87/87 (behavior unchanged).
B-final shape: scripts/ holds the type-independent engine; types/<name>/
holds everything for that type. Move the six codex runtime files
(codex-bridge.js, codex-bridge-launcher.sh, codex-monitor.sh, codex-shim.sh,
codex-shim-install.sh, watch-once.sh) from scripts/codex/ into types/codex/,
where the manifest, template, and delivery/session-start plugs already live.

Depth is unchanged (both are two levels under the skill root), so SKILL_DIR=
../.. and all codex-to-codex sibling refs are untouched. Only references that
reach UP into the shared engine gain one level: $SCRIPT_DIR/../<x> ->
$SCRIPT_DIR/../../scripts/<x> (lib/*, identities.sh, delivery.sh). codex-bridge.js
computes SKILL_DIR/SCRIPTS_DIR absolutely, so it needs no path change (comments
only). Callers follow the files: _delivery.sh / _session-start.sh, install.sh's
chmod, the test harness (new TYPES var, $TYPES/codex paths), and the docs.

Also fixes a latent bug the earlier scripts/codex move (#23f1b8f) left behind:
codex-bridge-launcher.sh and codex-monitor.sh sourced $SCRIPT_DIR/lib/hash.sh
(a path that never existed under scripts/codex/) — that move fixed node.sh's
'../' but missed hash.sh, so both scripts would fail at the agmsg_sha1 call.
Corrected to ../../scripts/lib/hash.sh alongside the other engine refs.

Full bats suite green except a pre-existing, environment-flaky watch test
(closed-consumer SIGPIPE timing) that fails identically on the unchanged base.
The commandWindows wrapping in hooks-json.sh keyed off a hardcoded
"codex" type name, violating that layer's stated type-agnostic
boundary. Resolve the wrap decision in delivery.sh (the layer that knows
agent types) from a new hook_windows_wrap=yes manifest key and pass a
plain flag down. hooks-json.sh now references no type name.
…fest

Mode acceptance was scattered: a hardcoded codex 'both' guard in
delivery.sh plus per-type monitor/both rejection branches duplicated in
the opencode and copilot plugs. Declare each type's accepted modes once
via the delivery_modes= manifest key and gate them centrally in do_set —
a typo still gets the generic "Unknown mode" error; an unsupported real
mode gets "not supported for <type>". The codex 'both' guard and the
opencode/copilot rejection arms are now redundant and removed (rejection
happens before any file is touched, preserving the don't-wipe-turn
guarantee).

The Windows dispatcher keeps an explicit codex monitor/both guard: the
codex bridge is unsupported on Windows (#182, tests skip_on_windows), and
delivery_modes is a global fact that can't express a platform exception.
The Quick Start opened with the curl one-liner and git clone; npx agmsg
is the lowest-friction way to get the skill installed (it runs the same
setup.sh bootstrapper, no clone). Lead with it and point readers who want
to inspect the code, track main, or pick a custom command name to the
Install section.
Per the driver-interface spec (docs/spec/driver-interface.md §1.1, bundled
drivers live at scripts/drivers/<axis>/), move the agent-type tree from the
repo root into scripts/drivers/types/. Agent types contain executable
runtime (_delivery.sh, codex's bridge/launcher/shim), so they belong under
scripts/, not at the top level.

- git mv types/ -> scripts/drivers/types/
- type-registry in-tree search dir: <root>/types -> <root>/scripts/drivers/types
- codex runtime upward refs reshift for the +2 depth: $SCRIPT_DIR/../..
  (SKILL_DIR) -> ../../../.., and ../../scripts/ -> ../../../; codex-bridge.js
  resolves SKILL_DIR four levels up
- install.sh: the single recursive scripts/ copy now carries the type tree, so
  the separate types/ copy is dropped; codex chmod path follows
- tests: test_helper TYPES var + codex chmod; the scripts/ copy already brings
  the tree, so the separate types/ stage is dropped (bats + powershell smoke)
- docs/comments/user-facing strings updated to the new path

Discovery of EXTERNAL add-on dirs is unchanged here (still the legacy
~/.config/agmsg path); the plugins/AGMSG_PLUGIN_DIRS redesign + opt-in
gating follow in the next commit.
fujibee and others added 5 commits June 21, 2026 16:03
Introduce driver-registry.sh: the axis-generic search bases + trust policy
shared by all driver axes (types now; storage/delivery later). Discovery
order is scripts/drivers (built-in) -> <install_dir>/plugins ->
$AGMSG_PLUGIN_DIRS, with later bases overriding earlier ones among eligible
candidates.

External drivers are shell code run with the user's privileges, so they are
NEVER loaded unless explicitly opted into. A built-in is always trusted;
anything under plugins/ or AGMSG_PLUGIN_DIRS is ignored — with a clear stderr
warning — until 'agmsg plugin trust <axis>/<name>'. Trust is path-pinned (the
db/trusted-plugins allowlist records axis/name -> abs path), so swapping a
directory under a trusted name does not silently activate new code.

- type-registry.sh becomes the types-axis facade over driver-registry; the
  AGMSG_TYPES_ROOT override and the ~/.config/agmsg/types external path are
  removed (root is always resolved from the lib's own location)
- plugin.sh: 'agmsg plugin list|trust <ref>|untrust <ref>' (ref is axis/name
  or an unambiguous bare name); wired into the Windows dispatcher
- docs: ADR 0002 records the discovery + opt-in decision (supersedes ADR 0001's
  deferred-loader note and ~/.agents/agmsg/plugins path); spec + agent-types
  updated
- tests: test_plugin_registry.bats locks ignored-until-trusted, later-wins
  override, path-pinned trust, the warning, and the CLI
The top half still described the pre-1.1.0 layout: types/ at the repo root,
templates/ for command templates, and apply_settings_* per-type code in
delivery.sh. Update to scripts/drivers/types/<name>/, the type-dir-relative
template= file, and the _delivery.sh Template Method plug. Add the
delivery_modes / stop_output / hook_windows_wrap manifest keys to the table and
the codex worked example.
…n dir

Document the external-driver plugin system the way codex-monitor-beta is
documented — a brief README section pointing to a dedicated doc:

- docs/plugins.md: discovery order, the opt-in trust model (path-pinned,
  ignored-until-trusted), the 'agmsg plugin' CLI, and how to author a types
  plugin
- README: a concise Plugins section + AGMSG_PLUGIN_DIRS in the env-var table;
  also refresh the Architecture tree (scripts/drivers/types, plugins/; drop the
  stale templates/) and fix a leftover types/codex path
- plugins/: the default external drop-in dir, shipped with a README (and a
  .gitignore so locally-dropped test plugins/opt-ins stay untracked); install.sh
  now creates <skill>/plugins/ and ships the README
Integrates @Fewmanism's Hermes support (#118) and spawn profile (#119),
adapted to the 1.1.0 driver layout (scripts/drivers/types/<name>/) instead
of the old hardcoded per-type branches and templates/ dir.

- scripts/drivers/types/hermes/{type.conf,template.md,_delivery.sh}: a manual-
  only type (delivery_modes=off — no automatic delivery hook). The _delivery.sh
  plug makes apply/status/teardown no-ops so 'set off' writes nothing and never
  disturbs another type's watcher; cli=hermes + spawnable=yes make 'spawn hermes'
  work through the generic data-driven path.
- delivery.sh: gate the in-session stop directive on the type actually having an
  automatic mode (data-driven via delivery_modes), so a manual-only type emits no
  AGMSG-DIRECTIVE on 'set off'. No per-type branch.
- install.sh: ship the Hermes skill to ~/.hermes/skills/<name>/ and accept
  --agent-type hermes for the shared SKILL.md, both via agmsg_type_template_path.
- tests: hermes delivery (5) + install (5) + join, and the registry invariants
  (now 7 built-ins; spawnable set gains hermes; no-branch guard covers hermes).

Deferred: #119's --hermes-profile spawn flag. It is inherently hermes-specific
and the 1.1.0 layout forbids per-type branches in spawn.sh; it needs a generic
spawn-profile mechanism (manifest key or spawn plug), tracked as a follow-up.
Generic 'spawn hermes <name>' (default Hermes profile, actas via boot prompt)
works today.

Co-authored-by: Fewmanism <lgndscntn@googlemail.com>
The ~/.agents/bin/codex shim bakes in the absolute path to codex-shim.sh at
generation time. install.sh --update copies the relocated script
(scripts/drivers/types/codex/) but did not re-run codex-shim-install.sh, so a
shim generated before the types/ -> scripts/drivers/types/ move kept execing
its old, now-missing path — breaking Codex monitor for users upgrading from
1.0.x. (Found in review by aggie-co1.)

Both install paths now re-run codex-shim-install.sh when an agmsg shim is
already present (status reports 'installed'). install is idempotent and
overwrites only an agmsg shim — a user's own codex binary fails is_agmsg_shim
and is left untouched; when no shim exists the refresh is a no-op, so --update
never opts a user into the shim. Covered by two install.bats cases (re-point on
update; no shim created when none existed).
@fujibee fujibee marked this pull request as ready for review June 22, 2026 02:47
@fujibee fujibee changed the title WIP: 1.1.0 — restructure agent types (data + behavior plugs) 1.1.0 — restructure agent types: driver registry, plugin opt-in, hermes (beta) Jun 22, 2026
fujibee added 2 commits June 21, 2026 19:50
Feature the seven supported agent runtimes (Claude Code, Codex, Gemini,
GitHub Copilot, Antigravity, OpenCode, Hermes) as a white-on-black logo
strip under the intro. Source marks live in docs/logos/; the composited
strip is docs/logos/supported-agents.png.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants