* Fix istall/update scripts * test: capture pre-refactor install snapshot for regression Adds take-snapshot.sh script and the resulting snapshot/ directory, capturing the exact vault state produced by launchme.sh before the framework-agnosticity refactor begins. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Summary: Refactor agents/skills/hooks/mcp in agentic-platform-agnostic templates. refactor: rename source CLAUDE.md → DISPATCHER.md (framework-neutral) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> refactor: convert agent frontmatter from tools: to neutral capabilities: Replace Claude Code-specific `tools:` frontmatter with framework-agnostic `mode: subagent` and `capabilities: [...]` in all 8 agent files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> refactor: add neutral hook trigger manifests (.hook.yaml) refactor: hooks read neutral JSON schema (args.* instead of tool_input.*) refactor: convert .mcp.json to neutral mcp/servers.yaml Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Implement agentic-platform adapters skeleton. build: add adapters/lib.sh skeleton with vocabulary constants test: bash test runner for adapter helpers Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(adapters): parse_frontmatter helper with tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(adapters): parse_capabilities helper with tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(adapters): should_include helper with tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(adapters): parse_hook_yaml helper with tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(adapters): agent_body helper with tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(adapters): enumerate_agents and enumerate_hooks helpers Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Implement agentic-platform adapter for Claude Code. build(adapters): claude-code adapter skeleton with capability/event tables build(claude-code): adapter_translate_dispatcher with test build(claude-code): adapter_translate_references with test build(claude-code): adapter_translate_skills with tests build(claude-code): adapter_translate_agents with capability→tools mapping build(claude-code): hook wrapper template (CC native → neutral schema) build(claude-code): adapter_translate_hooks with wrapper generation build(claude-code): adapter_translate_mcp with hand-rolled YAML parser build(claude-code): adapter_finalize and complete adapter_build wiring build: scripts/build.sh dispatches to per-framework adapter Also fix adapter_translate_hooks and adapter_translate_agents to use while-read loops (avoiding word-splitting on paths with spaces) and guard grep calls with || true to survive set -eo pipefail when hooks have no match-tool field. Remove scripts/build.sh from .gitignore. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Refactor install/update scripts to support agentic-platform agnosticity. refactor(lib.sh): generalize install_claude_md → install_dispatcher New signature takes the full destination path instead of just the vault dir, allowing callers to install CLAUDE.md, AGENTS.md, or any dispatcher file to an explicit location. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat(launchme): support --framework flag, build dist/ before install Add --framework and --target arg parsing. Run build.sh before installing to populate dist/<framework>/. All install_* calls now read from dist/<framework>/ instead of the raw source dirs. MCP is now handled automatically by the adapter (no interactive prompt). Replaced install_claude_md with install_dispatcher. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat(updateme): support --framework flag, build dist/ before update Add --framework and --target arg parsing. Run build.sh before installing to populate dist/<framework>/. All install_* calls now read from dist/<framework>/ instead of raw source dirs. Replaced install_claude_md with install_dispatcher. Also fix set -e compatibility in lib.sh: add || true to all conditional [[ ... ]] && info "..." logging lines so they don't abort the script when VERBOSE_COPY=0. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: regression runner diffs dist/claude-code against pre-refactor snapshot - Add tests/regression/run.sh that builds dist/claude-code and compares against snapshot, excluding runtime-only artifacts (.mbifc-manifest, .mcp.json, .claude-plugin/plugin.json) - Fix adapters/lib.sh agent_body: preserve '---' section dividers in body (awk now only skips '---' while still inside frontmatter, fm < 2) - Fix adapters/claude-code/adapter.sh: change 'read' capability to expand to only 'Read', appending 'Glob, Grep' at end of tools list to match snapshot ordering - Update snapshot to reflect intentional refactor changes: hook JSON schema (.args.* instead of .tool_input.*), wrapper scripts, settings.json with wrapper paths, and consistent tool ordering for postman/sorter Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Implement opencode adapter. Co-Authored-By: win0na <winnie@winneon.moe> feat(lib.sh): add install_plugins helper for opencode JS plugins build(adapters): opencode adapter skeleton with capability/event tables build(opencode): adapter_translate_dispatcher (DISPATCHER.md → AGENTS.md) build(opencode): adapter_translate_references and adapter_translate_skills Implements Task 4 and Task 5: - adapter_translate_references: Copies reference markdown files to .opencode/references/ - adapter_translate_skills: Copies skill SKILL.md files to .opencode/skills/<name>/ with exclude filtering Both functions respect framework filtering via should_include(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(opencode): adapter_translate_agents with capability→permission mapping Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(opencode): bash-executor template for spawning hook scripts build(opencode): plugin-stub template for mbifc-hooks.js build(opencode): adapter_translate_hooks with JS plugin generation Implements _oc_hook_registry_json and adapter_translate_hooks in the opencode adapter. Copies hook scripts to .opencode/hooks/, generates a single .opencode/plugins/mbifc-hooks.js by inlining bash-executor.js and synthesising a hook registry from *.hook.yaml files. Uses python3 for template substitution to safely handle multi-line JS content. Adds 3 unit tests (copies scripts, registry entries, noop when no hooks dir). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(opencode): adapter_translate_mcp with local/remote handling build(opencode): adapter_finalize and complete adapter_build wiring Add adapter_finalize placeholder and wire adapter_translate_mcp into adapter_build; add end-to-end integration test (14/14 pass). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat(launchme): branch on --framework for opencode install layout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat(updateme): branch on --framework for opencode install layout Mirror the same case "$FRAMEWORK" block from launchme.sh: framework-specific DIST_COMPONENTS_DIR, VAULT_COMPONENTS_DIR, DISPATCHER_SRC/DST, MCP_SRC/DST, HAS_PLUGINS; conditional install_plugins; conditional install_settings; framework-aware vault-setup check; framework-neutral summary messages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix adapters to follow the same template. fix: restore adapter_build() contract, revert function renames Both adapters now export adapter_build() and adapter_translate_*() as the uniform public contract. scripts/build.sh sources one adapter and calls adapter_build uniformly. Private helpers (_oc_*) and vocabulary tables (cc_capability_to_tools, oc_capability_to_permission, etc.) retain their prefixes. CC regression and OC unit tests all pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> fix(tests): restore test_oc_ prefix on adapter_build end-to-end test * Fix agent format in opencode adapter * refactor: rename --framework to --platform across all scripts and tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Modify generic name for model tiers Co-Authored-By: win0na <winnie@winneon.moe> refactor: neutral model vocabulary (low/mid/high) in source agents feat(claude-code): cc_model_to_native() maps low/mid/high to haiku/sonnet/opus Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat(opencode): update oc_model_to_provider() for low/mid/high vocabulary Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add gemini-cli adapter Co-Authored-By: win0na <winnie@winneon.moe> build(gemini-cli): adapter skeleton with capability/event/model tables build(gemini-cli): adapter_translate_dispatcher (DISPATCHER.md → GEMINI.md) build(gemini-cli): adapter_translate_references and adapter_translate_skills Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(gemini-cli): adapter_translate_agents with capability→tools mapping Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(gemini-cli): adapter_translate_hooks with wrapper scripts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> feat(install): add gemini-cli platform to launchme.sh and updateme.sh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Implement preserving config merge for opencode. Co-Authored-By: win0na <winnie@winneon.moe> feat(opencode): config-merge.sh with formatting-preserving JSON merge Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> build(opencode): source config-merge.sh from adapter Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat(install): use oc_config_merge for opencode.json instead of overwrite Source config-merge.sh from install scripts for opencode platform so user keys in opencode.json are preserved on reinstall and update. Fix in-place merge by writing to a temp file before moving to output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add mcp files to gitignore. * Fix claude-specific references in agents, skills and references * Fix: remove claude-specific reference from hooks. build: add platform_dir and dispatcher_name to all hook wrapper/plugin templates feat(hooks): platform-aware path checks using platform_dir and dispatcher_name from JSON input test: update regression snapshot for platform-aware hook wrappers and scripts * Added interactive platform choice in launchme, and platform auto-detection in updateme. * Fix: remove claude-specific references from documentation * Update documentation to reflect the new platform-agnostic architecture * fix: address Copilot review feedback on PR #32 - tests/run.sh: check source return code, report failures - tests/regression/run.sh: use mktemp + trap cleanup instead of fixed /tmp paths - tests/regression/run.sh: include .mcp.json in regression comparison - tests/regression/take-snapshot.sh: use --platform flag instead of stale scripted input - adapters/opencode/templates/plugin-stub.js.tmpl: include stdout in hook block error message * fix: address Copilot review round 2 - config-merge.sh: reword comment to only promise indentation preservation (not full formatting) - take-snapshot.sh: copy required artifacts explicitly, optional ones with existence check - adapters/lib.sh: document parse_hook_yaml single-trigger limitation * fix: address Copilot review round 3 - adapters/opencode/adapter.sh: replace python3 template substitution with pure bash (while-read loop with case matching), removing python3 dependency - adapters/lib.sh: should_include now falls back to plain YAML key read for files without frontmatter delimiters (fixes hook .yaml exclude: support) * fix: address Copilot review round 4 - scripts/launchme.sh: fix double-dot in FW_DIR_NAME display (basename already includes the dot, e.g. ".claude") - scripts/launchme.sh: replace undefined MCP_ANSWER with check on MCP_DST existence for summary banner --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
8.7 KiB
Executable File
Agent Orchestration Protocol
This document defines how agents coordinate through the dispatcher (DISPATCHER.md). Agents do NOT communicate directly with each other — the dispatcher handles all routing and chaining.
Overview
The dispatcher is a reactive multi-router with skill-first routing:
- User sends a message → dispatcher checks the skill routing table first
- Skill match found? → invoke the skill via the Skill tool and respond to user
- No skill match? → dispatcher picks the best agent by priority
- Agent executes → returns output to the dispatcher
- Dispatcher reads the output → decides if another agent should be chained
- Repeat until done or max depth reached
Agents help the dispatcher by including suggestions in their output when they detect work for other agents.
Skill-First Routing
Skills are checked before agents. They handle complex, multi-step workflows that were extracted from agents for better performance.
How it works
- The dispatcher maintains a skill routing table (defined in
DISPATCHER.md) with trigger phrases in multiple languages. - If a user message matches a skill trigger, the skill is invoked via the Skill tool (not the Agent tool). The dispatcher does NOT also invoke the source agent.
- Skills run in the main conversation context, preserving multi-turn state. This is different from agents, which run as subprocesses.
- If no skill matches, the dispatcher falls through to the agent routing table.
Skill-to-agent chaining
Skills can still produce output that triggers agent chaining:
- A skill may include
### Suggested next agentin its output (e.g.,/onboardingmay suggest Connector to link newly created notes). - The dispatcher reads this output and applies the same chaining rules as for agents (check registry, check call chain, max depth 3).
- Skills count as step 1 in the call chain when they produce agent suggestions.
List of skills
See .platform/references/agents.md (Skills section) for the full table of skills, their source agents, and purposes.
How Agents Signal the Dispatcher
When an agent detects work that another agent should handle, it includes a section at the end of its output:
### Suggested next agent
- **Agent**: {name from agents-registry.md}
- **Reason**: {what needs to be done and why}
- **Context**: {relevant details the next agent would need — note titles, folder paths, specific issues}
Multiple suggestions are allowed — list them all. The dispatcher prioritizes and decides which (if any) to invoke.
Examples
### Suggested next agent
- **Agent**: architect
- **Reason**: No area exists for "Personal Finance" — 3 notes were placed in Inbox as fallback
- **Context**: Notes: "Monthly Budget March.md", "Savings Goals.md", "Expense Tracking.md". Suggest creating 02-Areas/Personal Finance/ with sub-folders and MOC.
### Suggested next agent
- **Agent**: connector
- **Reason**: 5 recently filed notes about "Machine Learning" have no cross-links
- **Context**: Notes in 03-Resources/Technology/ML/. They reference shared concepts (gradient descent, neural networks) but have zero wikilinks between them.
### Suggested next agent
- **Agent**: architect
- **Reason**: MOC for Machine Learning is missing
- **Context**: There are now 8 notes under this topic but no MOC in MOC/ folder.
Suggesting a New Agent
When an agent detects that the user needs functionality that no existing agent provides, it can suggest creating a new custom agent:
### Suggested new agent
- **Need**: {what capability is missing}
- **Reason**: {why no existing agent can handle this}
- **Suggested role**: {brief description of what the new agent would do}
The dispatcher reads this and may invoke the Architect to start the custom agent creation flow. This is NOT automatic. The dispatcher should confirm with the user first:
"The [agent] noticed you might benefit from a custom agent for [need]. Would you like me to create one?"
Dispatcher Decision Logic
After each agent returns, the dispatcher:
- Reads the output — looks for
### Suggested next agentsections - Consults
agents-registry.md— validates the suggested agent exists and isactive - Checks the call chain — is this agent already in the chain? Is max depth reached?
- Checks for
### Suggested new agent-- if present, asks the user if they want the Architect to create a custom agent - Decides: invoke next agent OR return results to user
The dispatcher can also chain agents without an explicit suggestion if the output clearly matches another agent's capabilities (e.g., notes created → Sorter might be needed).
Call Chain Tracking
Every user request has a call chain — the ordered list of agents invoked so far.
Rules
- Start: chain is empty
[] - After each agent returns: append its name to the chain (the chain always lists agents already invoked, in order)
- Pass the chain: when invoking the next agent, tell it the chain and its position —
"Call chain so far: [scribe, architect]. You are step 3 of max 3." - No duplicates: never invoke the same agent twice in one chain
- No circular patterns: if Agent A suggests Agent B and B is already in the chain, skip
- Max depth: 3: no more than 3 agents per user request
- On overflow: return results to user with a note about what was deferred
What Happens at Max Depth
If the dispatcher would need a 4th agent, it:
- Returns the current results to the user
- Includes a summary of what was deferred: "The Connector also detected 5 orphan notes that need linking — you can say 'connect the notes' to handle that."
Custom Agent Lifecycle
Custom agents are created by the Architect and stored in .platform/agents/. They participate fully in the orchestration system:
- Creation: the Architect creates the agent file, adds a row to
agents-registry.md, and updatesagents.md - Discovery: the platform auto-discovers the agent from its frontmatter in
.platform/agents/ - Routing: the dispatcher checks
agents-registry.mdfor custom agents when no core agent matches - Chaining: custom agents can suggest (and be suggested by) any other agent, following the same protocol
- Maintenance: the Librarian audits custom agents during vault health checks. For every row in agents-registry.md with status=active, the corresponding file must exist in
.platform/agents/ - Deletion: only the Architect can remove a custom agent (with user confirmation). The agent file is deleted, and the registry row is set to
disabled
What Agents Should NOT Do
- ❌ Do NOT reference
Meta/agent-messages.md— the shared message board is deprecated - ❌ Do NOT edit other agents' prompt/config files (e.g.,
.platform/agents/*.md) — normal vault notes/MOC edits are still allowed per your responsibilities; all coordination goes through the dispatcher - ❌ Do NOT block waiting for another agent — finish your task and suggest next steps in your output
- ❌ Do NOT call other agents — only the dispatcher invokes agents
Migration from Legacy System
If a vault still has the old Meta/agent-messages.md file:
- The Librarian will rename it to
Meta/agent-messages-DEPRECATED.mdduring maintenance - Agents should ignore this file entirely — all coordination now flows through the dispatcher
Agent State (Post-it Protocol)
Every agent has a personal post-it file at Meta/states/{agent-name}.md. This provides continuity between executions.
Rules
- One file per agent — named after the agent (e.g.,
Meta/states/scribe.md) - Always written — every agent writes its post-it at the end of every execution, no exceptions
- Overwrites previous — each execution replaces the previous post-it (it is not a log)
- Max 30 lines — agents must keep the body under 30 lines to prevent bloat
- Read at start — agents read their post-it at the start of execution for context
- Private — the dispatcher does not read or write agent post-its. Only the owning agent touches its own file
- Multi-step flows — agents that run multi-step conversations (e.g., Architect onboarding) use the post-it to track their current phase and collected answers, so they can resume on re-invocation
Format
---
agent: {agent-name}
last-run: "YYYY-MM-DDTHH:MM:SS"
---
## Post-it
[Agent's notes — max 30 lines]
Reference Files
- Agent registry:
.platform/references/agents-registry.md— the single source of truth for all agents - Agent directory:
.platform/references/agents.md— detailed descriptions of each agent's responsibilities