Skip to content

Add built-in plugin system for namespaced target-scoped integrations#28

Open
burczu wants to merge 8 commits into
callstackincubator:masterfrom
burczu:feat/plugin-system
Open

Add built-in plugin system for namespaced target-scoped integrations#28
burczu wants to merge 8 commits into
callstackincubator:masterfrom
burczu:feat/plugin-system

Conversation

@burczu
Copy link
Copy Markdown

@burczu burczu commented May 20, 2026

Summary

Closes #26.

This PR adds a built-in plugin system that lets target-scoped integrations (e.g. Rozenite) be added without leaking runtime-specific behavior into the core daemon, dispatcher, CLI, or protocol types.

  • Protocol — one generic plugin-command IPC envelope added to IpcCommand; the union never needs to widen for a new plugin
  • AgentPlugin interface (src/plugin.ts) — plugins declare a unique id, static commands, a supportsTarget() predicate, a state machine (idle / ready / unsupported-target / waiting-for-runtime / error), and optional daemon/target lifecycle hooks
  • PluginOrchestrator (src/plugin-orchestrator.ts) — validates unique plugin/command ids at construction, wraps RuntimeSession into a narrow AgentPluginTargetSession, fans out lifecycle events, and dispatches plugin-command IPC with state enforcement before calling execute()
  • AgentRuntimeBridge → plugin — migrated to src/plugins/runtime-bridge/index.ts implementing AgentPlugin; uses an injected CoreCommandRelay instead of holding the dispatcher directly; checks supportsTarget in lifecycle hooks (RN-only)
  • Daemon — intercepts plugin-command before the dispatcher; sequences orchestrator lifecycle alongside core attachments via existing callbacks; calls orchestrator.start/stop around daemon lifetime
  • CLIcreateProgram gains a plugins: AgentPluginRegistration[] parameter; BUILT_IN_PLUGINS assembled in cli/index.ts; bridge registerCliCommands is a no-op placeholder for future subcommands

Backward compatibility

All existing commands, flags, outputs, and daemon behavior are unchanged. The plugin-command IPC type is additive. The runtime bridge behavior is identical — it now runs through the plugin seam transparently.

Risks

  • The CoreCommandRelay is a closure over this.commandDispatcher constructed before the dispatcher is assigned. This is safe because the relay is only called at runtime, never during construction — same pattern as the original bridge.
  • onTargetDisconnected is declared in the interface but not yet wired. No existing behavior changes.
  • beforeClearTarget fires orchestrator cleanup as fire-and-forget (void). Plugin onTargetCleared implementations that do meaningful async work should be aware of this for the shutdown path.

Manual testing

Requires a React Native app with @agent-cdp/sdk installed (e.g. the playground app in this repo).

# build
pnpm build

# start daemon
pnpm run agent-cdp start

# confirm daemon is running and bridge plugin is active
pnpm run agent-cdp status

# select a React Native target
pnpm run agent-cdp target list
pnpm run agent-cdp target select <rn-target-id>

# trigger an in-app SDK measurement (via playground or your own app)
# verify it routes correctly — e.g. sample memory from the app
pnpm run agent-cdp memory usage list

# confirm unknown plugin-command returns a clean error
echo '{"type":"plugin-command","pluginId":"nope","command":"cmd"}' | nc -U ~/.agent-cdp/daemon.sock

# stop daemon
pnpm run agent-cdp stop

Expected: all existing workflows unchanged; unknown plugin command returns {"ok":false,"error":"Unknown plugin 'nope'"}.

burczu added 7 commits May 20, 2026 09:47
- Extend IpcCommand union with generic plugin-command envelope
- Approve esbuild, simple-git-hooks, unrs-resolver build scripts in pnpm-workspace.yaml
- Add .idea to .gitignore
Add plugin.ts with the full TypeScript interface for the built-in plugin
system: AgentPluginState, AgentPluginTargetSession, AgentPluginCommandContext,
AgentPluginTargetContext, AgentPluginDetachContext, AgentPluginCommand,
and AgentPlugin with daemon/target lifecycle hooks.
Orchestrator validates unique plugin/command ids at construction, wraps
RuntimeSession into AgentPluginTargetSession, sequences lifecycle hooks
across all plugins, and dispatches plugin-command IPC with state
enforcement before calling execute(). 19 tests covering all paths.
Replace the standalone AgentRuntimeBridge class with AgentRuntimeBridgePlugin
implementing the AgentPlugin interface. The plugin checks supportsTarget in
lifecycle hooks, manages its own state (idle/ready/unsupported-target), and
routes SDK measurement commands through an injected CoreCommandRelay instead
of holding a direct dispatcher reference. Old bridge file removed in Phase 5.
Replace hardwired AgentRuntimeBridge with PluginOrchestrator backed by
AgentRuntimeBridgePlugin. Daemon intercepts plugin-command IPC before the
dispatcher, sequences orchestrator lifecycle hooks alongside core
attachments, and calls orchestrator.start/stop around the daemon lifetime.
Delete the now-unused bridge/runtime-bridge.ts.
Define AgentPluginRegistration in cli/program.ts and extend createProgram
with a plugins parameter that calls registerCliCommands for each plugin
after core commands. Assemble BUILT_IN_PLUGINS in cli/index.ts with the
runtime-bridge registration. Bridge registerCliCommands is a no-op for now.
Add a Built-in plugin system section to README with an overview of the
protocol envelope, AgentPlugin interface, PluginOrchestrator, CLI
registration, and a 4-step guide for adding a new plugin. Update AGENTS.md
command family lookup with plugin system files and add guidance on plugin
routing and the plugin authoring workflow.
Comment thread AGENTS.md Outdated
Comment thread packages/agent-cdp/README.md Outdated
- Fix stray 'oh ' prefix on AGENTS.md heading
- Extract built-in plugin system docs to docs/PLUGINS.md
- Replace verbose README section with a one-line reference
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.

Add built-in plugin system for namespaced target-scoped integrations

2 participants