PluginsExamples
NotesPlugin Scenario
Use a small but real NotesPlugin scenario to show how actions, config, and system text can work together
NotesPlugin Scenario
Scenario
You want to add a project-notes capability to one agent:
- inspect current notes config
- save notes-folder behavior
- inject a little system guidance about how notes should be used
That is much closer to a plugin than a service.
Why this looks like a plugin
Because what you want is:
- explicit actions
- one system augmentation block
- one project-scoped config block
not a long-lived background worker.
Example
import { Agent, type Plugin } from "@downcity/agent";
export const notesPlugin: Plugin = {
name: "notes",
title: "Project Notes",
description: "Save and describe a project notes folder.",
config: {
plugin: "notes",
scope: "project",
defaultValue: {
injectPrompt: true,
folder: ".notes",
},
},
system(context) {
return `Project notes folder: ${context.rootPath}/.notes`;
},
actions: {
status: {
allowWhenDisabled: true,
execute: async ({ context }) => {
return {
success: true,
data: {
rootPath: context.rootPath,
},
};
},
},
},
};
const agent = new Agent({
id: "repo-helper",
path: "/path/to/project",
tools: {},
plugins: [notesPlugin],
});
const status = await agent.plugins.runAction({
plugin: "notes",
action: "status",
});What this scenario is good for
- a plugin can already be useful with only
config + actions + system - it does not need a worker or long-lived runtime state to be a valid plugin
How this lands in the local SDK
This pattern now runs directly inside a local Agent.
The most useful details are:
statusdeclaresallowWhenDisabled: true, so it can still support self-check style calls even if the plugin was explicitly disabledagent.plugins.runAction(...)is the most direct explicit entry point- if you also implement
system(), the local SDK session prompt path injects it when this plugin is registered on the Agent