Plugins
Custom Plugin
Build a custom plugin with config, actions, hooks, system text, availability checks, lifecycle, and optional runtime HTTP routes
Custom Plugin
If the thing you want to add is mainly:
- a set of actions
- a set of hooks
- one system text layer
- one lifecycle-owned runtime boundary
- one set of runtime HTTP routes
then a custom plugin is usually the right extension point.
Current public entry points
@downcity/agent exposes:
- plugin types and contracts
- built-in plugin exports
- the local
Agentplugins: [...]assembly entry point
Minimal skeleton
import type { Plugin } from "@downcity/agent";
export const notesPlugin: Plugin = {
name: "notes",
title: "Notes Helper",
description: "Adds note-related actions and prompt guidance.",
actions: {
status: {
execute: async ({ context }) => {
return {
success: true,
data: {
rootPath: context.rootPath,
},
};
},
},
},
};Attach the custom plugin to a local Agent
import { Agent, type Plugin } from "@downcity/agent";
const notesPlugin: Plugin = {
name: "notes",
title: "Notes Helper",
description: "Adds note-related actions and runtime guidance.",
actions: {
status: {
allowWhenDisabled: true,
execute: async ({ context }) => ({
success: true,
data: {
rootPath: context.rootPath,
},
}),
},
},
};
const agent = new Agent({
id: "repo-helper",
path: "/path/to/project",
tools: {},
plugins: [notesPlugin],
});The most important design questions
1. What exactly are you extending
Be explicit about whether you need:
- actions
- hooks
- resolve points
- system text
- lifecycle
- HTTP
Do not default to implementing every field.
2. Should some actions run while disabled
Actions like:
statusinstallconfigure
often need allowWhenDisabled: true.
3. Should runtime state stay inside lifecycle
If the capability must:
- start and stop with the plugin
- keep runtime state in memory
- recover after restart
then model that inside plugin lifecycle instead of hiding it in unrelated hooks.
One practical rule
Your plugin logic should rely on the minimal stable plugin context when possible instead of assuming access to every runtime singleton.