Plugins

Plugin Call Surfaces

Distinguish City management, Workspace execution, PluginContext, and the plugin_call Tool.

Plugin Call Surfaces

Plugins expose four call surfaces for different callers:

SurfaceCallerPurpose
city.pluginsHost applicationAdd or remove unique instances and invoke host/config actions
city.plugins.scope({ agent_id: agent.id, workspace_id: workspace.id })Host execution codeCall Actions, Availability, or Hooks in one Agent/Workspace scope
context.city.pluginsPlugin codeCall another Plugin Action, pipeline, or effect in the current scope
plugin_callModel in a SessionCall a Plugin Action provided by City

City management surface

city.plugins.add(skill_plugin);
console.log(city.plugins.snapshots());
await city.plugins.remove("skill");

city.plugins.invoke() and invoke_config() call host-management Actions registered during start(); they are not Session execution Actions.

Workspace execution surface

const result = await city.plugins.scope({ agent_id: agent.id, workspace_id: workspace.id }).run_action({
  plugin: "skill",
  action: "lookup",
  payload: { name: "frontend-design" },
});

This surface explicitly binds an Agent and Workspace, allowing City to create the correct PluginContext.

PluginContext

const result = await context.city.plugins.run_action({
  plugin: "skill",
  action: "list",
  payload: {},
});
await context.city.plugins.effect("audit.observe", result.data ?? null);

context.session, context.agent.sessions, and context.workspace are directly callable handles. IDs are reserved for stable identity and serialization.

Model Tool

plugin_call({
  plugin: "skill",
  action: "lookup",
  payload: { name: "frontend-design" },
});

The Tool is always bound to the current Session's Agent/Workspace execution lease and cannot observe another Agent's bindings.