Downcity
Local Agent

tools, services, and plugins

How to inject tools, explicit service instances, and plugin definitions into a local Agent

tools, services, and plugins

tools

A local Agent can receive a tool collection directly:

const agent = new Agent({
  id: "repo-helper",
  path: "/path/to/project",
  tools: {
    my_tool: myTool,
  },
});

Those tools become available during session execution.

If your app needs a long-lived default tool set, agent-level injection is usually the cleanest choice.

services

If you want the local Agent to own services, pass explicit instances:

import { Agent, ChatService } from "@downcity/agent";

const agent = new Agent({
  id: "repo-helper",
  path: "/path/to/project",
  tools: {},
  services: [
    new ChatService({
      telegram: {
        botToken: process.env.TELEGRAM_BOT_TOKEN!,
      },
    }),
  ],
});

When explicit services are useful

  • you want the SDK process itself to start chat channels
  • you want service lifecycle to be controlled by your application code

You can think of this as: the caller explicitly decides which services are permanent capabilities of this local agent.

If those services implement system(context), the local SDK injects their system text into the session prompt.

plugins

If you want the local Agent to own plugins, pass explicit plugin definitions:

import { Agent, skillPlugin, webPlugin } from "@downcity/agent";

const agent = new Agent({
  id: "repo-helper",
  path: "/path/to/project",
  tools: {},
  plugins: [skillPlugin, webPlugin],
});

const plugins = agent.plugins.list();

Those plugins are registered into the current Agent's own registry.

That means:

  • plugin actions can be called through agent.plugins.runAction(...)
  • context.plugins inside services and plugin hooks points to the same registry
  • duplicate plugin names throw immediately
  • the SDK does not register every built-in plugin by default

The local SDK currently wires the plugin registry, AgentContext.plugins, and the registered plugins' system(context) text into the session prompt.

It does not automatically mount plugin.http.runtime onto the SDK HTTP server started by agent.start({ http: { ... } }).

Important boundary

The SDK services field is the set of instances you hand to Agent yourself. It is not a mirror of some automatic project-runtime registry.

The SDK plugins field is also the set of definitions you hand to Agent yourself. It is not a mirror of the global plugin manager.

So do not think of SDK mode as "import everything from the project automatically." It is intentionally explicit assembly.

If you want the next layer of detail:

  • which services exist today
  • where ChatService fits
  • how to build a custom service
  • how plugins attach to a local Agent

continue with: