Plugins
A Podcode plugin is a single JavaScript module that the server imports at boot. It hands back a set of hook functions, and from then on it sits inside the agent loop — adding tools, adjusting model parameters, and watching every tool call go by.
There is no build step, no manifest, and no SDK to install. A plugin is one file with one default export.
export default {
id: "hello",
server({ bus, cwd, version }, { config }) {
return {
"chat.params": (params) => ({ ...params, temperature: 0.2 }),
}
},
}Register the path in your global config, restart the server, and every model call in every session now runs at temperature 0.2.
What a plugin can do
Four hooks are defined and wired today. Implement any subset — a plugin that only wants one of them returns only that key.
| Hook | Runs | Purpose |
|---|---|---|
tool | Once, at load | Register custom tools into the agent's tool set |
chat.params | Before every model call | Adjust temperature, topP, topK, output cap, provider options |
tool.execute.before | Before every tool runs | Inspect or rewrite the arguments |
tool.execute.after | After every tool runs | Inspect or rewrite the result |
Hook names are exact strings. A typo is not an error — the key is simply never called. See the hook reference for payload shapes and ordering.
Where a plugin runs
Plugins are imported into the server process. There is no sandbox and no permission prompt at load time: the module executes with the full privileges of the server the moment it is imported — filesystem, network, environment, everything.
That is why registration lives in the operator-owned global config (~/.config/podcode/config.json) and never in a project's .podcode/config.json. A cloned repository cannot register a plugin, cannot supply plugin config, and cannot flip the auto-discovery switch. Those keys are stripped from the project layer before it merges.
Two more boundaries are worth knowing before you write anything:
- Server-wide, not per-workspace. Plugins load once at boot using the server's own working directory. Every workspace and every session shares the same loaded set.
- Fail-soft, always. A plugin that fails to import is skipped and logged. A plugin whose
server()throws is skipped. A hook that throws or stalls has its contribution dropped and the turn continues. Nothing a plugin does can take the server down — which also means nothing a plugin does can reliably stop a turn.
Where to go next
- Quickstart — a working plugin in about five minutes.
- Plugin anatomy — the module contract, in detail.
- Hook reference — every payload, the pipeline, the timeouts.
- Custom tools — giving the agent a new capability.
- Configuration — registration, per-plugin config, the trust boundary.
- Examples — complete plugins you can copy.
- Troubleshooting — what silence usually means.