Imported from kanishka-namdeo/AgentCanvas (
src/lib/agent/plugins/AGENTS.md). Install upstream withnpx skills add kanishka-namdeo/AgentCanvas --skill plugins. Copyright stays with the author.
AGENTS.md — src/lib/agent/plugins/
Purpose
The agent plugin subsystem: a registry of 8 ported pi-agent plugins exposing up to 32 additional tools, gated per-user by settings.enabledPlugins (11 tools default-enabled after the 2026-08-30 audit — ask-user 1, todo 5, memory 5; the subagents plugin is now default-OFF: the runner's critique loop is the single critique authority, and subagent_worker was success theater). Plugins add interactive runtime capabilities — blocking questions, todo lists, long-term memory, context compaction, goal tracking, background tasks, MCP servers, sub-agents — without touching the core tool surface in tools.ts.
Ownership
index.ts— plugin registry:ALL_PLUGINSmanifest (pluginId, pluginName, description, category, defaultEnabled, tools) +getEnabledPlugins/getEnabledPluginTools/getEnabledPluginToolNames/getPlugin/getAllPlugins, all gated bysettings.enabledPlugins./api/pluginsserves these manifests.approval-gate.ts— the destructive-op approval gate: pauses the agent on gated tools (pen_clear,pen_delete_shape,figma_delete_page,pen_clear_pattern_memory) until the user Allows/Denies via the approval card →/api/agent/approvals; honorssettings.approvalMode('destructive' default / 'review' / 'off') andalwaysAllowTools.event-bus.ts— module-level per-turnSyncEventsink installed byrunAgentNative;setEventSink/emitEvent/hasSinklet plugin tools fire UI events mid-turn. NON-plugin consumers too (M2-c):tools.ts's round-trip tools (pen_get_computed/pen_get_screenshot) and the VLM critic emitagent:computed_request/agent:screenshot_requestthrough this sink — same mechanism as ask-user-question, answers resolve via/api/agent/client-responses+agent/client-roundtrip.ts.ask-user-question.ts—ask_user_questiontool: emitsagent:ask_user_question, blocks for answers resolved via/api/agent/answers(5-minute timeout); also backs/api/agent/pending.todo.ts— 5todo_*tools maintaining a per-session todo list; each mutation emitsagent:todo_update. BATCH semantics (todo-batch noise fix, 2026-08-28):todo_updateaccepts a BATCH of status transitions (1-20 in ONE call — never one call per transition); WIP=1 auto-advance (marking a step in_progress implicitly completes the previous one, so no separate "completed" call is needed); every mutation returns the FULL list state (notodo_listread-backs); prompt gating nudges the model to use todos only on 5+ step / 10+ call tasks (<1/4 of total calls). Measured: todo share dropped to 0.9% of tool calls (was ~13/31 bookkeeping calls). The single-step schema is still accepted (normalized into a 1-element batch) so old tests + stale transcripts keep working.memory.ts— 5memory_*+scratchpadtools over file-backed long-term memory in~/.pi/agent/memory/(MEMORY.md, SCRATCHPAD.md, daily log).mega-compact.ts— 3compact_*tools: TF-IDF-indexed compaction summaries with deduped recall.goal-list-loop-audit.ts— 5goal_*tools: goal interview + audited task queue for long-running design jobs (in-memory state).background-tasks.ts— 5background_*tools: durable background task execution with status polling via/api/agent/background/[id].mcp-adapter.ts— 5mcp_*tools: MCP server registry/connections configured viasettings.mcpServersand controlled through/api/mcp/[id](placeholder connection — real MCP SDK wiring is a tracked TODO).subagents.ts— 3subagent_*tools (reviewer/oracle/worker profiles) delegating via the provider-aware LLM client. Also exportsgetActiveLLM()— the runner-armed per-turn client that pen tools with sub-agent needs (pen_generate_variants) read; falls back toZAI.create()sandbox credentials when unset.
Local Contracts
- Manifest contract: every plugin registers
{ pluginId, pluginName, description, category, defaultEnabled, tools }. The Settings → Plugins section renders these manifests and merges them with the client-sideenabledPluginstoggle state — user toggles are NOT persisted server-side. - Event-sink pattern: plugin tools never touch the Zustand store or sockets directly; they call
emitEvent()fromevent-bus.tsand the runner fans events out to viewers. - Per-session state lives in module-level Maps keyed by session/toolCall id (questions, todos, goals, background tasks) — no DB. A server restart clears it;
/api/agent/pendingexists so reloads can recover unanswered questions. - Tool gating:
getEnabledPluginTools(settings)is the single choke point — the runner must not import plugin tools any other way. - Plugin tool names must not collide with the core
pen_*/figma_/web_*prefixes.
Work Guidance
- When adding a plugin: add the manifest to
ALL_PLUGINS, implement tools with@sinclair/typeboxschemas matching the core pattern, wire events throughevent-bus.ts, and add an Ownership row here. - When changing the question flow: update
ask-user-question.ts,/api/agent/answers,/api/agent/pending,PluginUI.tsx'sAskUserQuestionDialog, and the canvas store'ssubmitQuestionAnswerstogether — all five are coupled. - When the MCP SDK integration lands: replace the placeholder registry in
mcp-adapter.ts, keep the/api/mcp/[id]+settings.mcpServerscontract, and update this doc +src/app/api/AGENTS.md.
Verification
bun run test— plugin-related unit coverage (tools, agentic workflows).- Manual: Settings → Plugins → toggle a plugin → run a prompt that uses it (e.g. ask the agent to "plan with todos") → TodoOverlay updates live.
- Manual: agent asks a question →
AskUserQuestionDialogappears → answer → run continues; reload mid-question → dialog recovers via/api/agent/pending.
Child DOX Index
No child AGENTS.md files. This folder is flat.