Can PrimeAgent Be Extended with Custom Modules? A Complete Guide to the Plugin Architecture
Yes, PrimeAgent is designed as a modular, plugin-friendly platform with four official extension points—AI providers, coding-agent skills, TUI components, and configuration hooks—that let developers add functionality without modifying core source code.
PrimeAgent separates its core services (AI provider handling, coding-agent orchestration, and terminal UI rendering) from extension points discovered at startup through glob patterns. This architecture, implemented in the PrimeIntellect-ai/prime-agent repository, enables dynamic loading of custom modules from the plugins/ directory without requiring a full rebuild.
AI Providers: Adding Custom LLM Backends
The AI provider system in packages/ai/src/providers/register-builtins.ts uses a lazy-loading registration pattern. You implement a standard interface and register your provider by name.
Provider Interface Requirements
Your provider must export two streaming functions:
stream(model, messages, opts)— full streaming with metadatastreamSimple(model, messages, opts)— simplified text-only streaming
Both return AssistantMessageEventStream objects defined in packages/ai/src/types.
Implementation Example
// packages/ai/src/providers/my-custom-provider.ts
import {
AssistantMessageEventStream,
StreamOptions,
} from "../types";
export interface MyProviderOptions extends StreamOptions {
temperature?: number;
}
export async function stream(
model: string,
messages: any[],
opts: MyProviderOptions,
): Promise<AssistantMessageEventStream> {
// Translate your LLM's response format to AssistantMessageEventStream
return new ReadableStream({
start(controller) {
// Stream events matching the expected shape
}
});
}
export async function streamSimple(
model: string,
messages: any[],
opts: MyProviderOptions
): Promise<ReadableStream<string>> {
// Simplified text-only output
}
Registration
Lazy-load your provider in the registry to avoid initialization overhead:
// packages/ai/src/providers/register-builtins.ts
import { registerBuiltinProvider } from "./registry";
registerBuiltinProvider("my-custom-api", async () =>
import("./my-custom-provider")
);
When a user specifies api: "my-custom-api" in their configuration, PrimeAgent dynamically imports and instantiates your provider.
Coding-Agent Skills: Adding Custom Commands
Skills extend PrimeAgent's command vocabulary. The package manager in packages/coding-agent/src/package-manager.ts scans plugins/*/skills at startup and auto-discovers modules matching the skill interface.
Skill Structure
Each skill requires:
SKILL.md— documentation for the LLM and usersskill.ts— TypeScript module exporting aSkillobject
Complete Skill Example
// plugins/pdf-to-markdown/skills/pdf-to-markdown/skill.ts
import { Skill } from "coding-agent";
export const skill: Skill = {
name: "pdf-to-markdown",
description: "Convert a PDF file to Markdown text",
async run({ args, context }) {
const [pdfPath] = args;
if (!pdfPath) {
throw new Error("Usage: pdf-to-markdown <path>");
}
// Your conversion logic here
const markdown = await convertPdf(pdfPath);
return { output: markdown };
},
};
<!-- plugins/pdf-to-markdown/skills/pdf-to-markdown/SKILL.md -->
# pdf-to-markdown
Converts a PDF document to Markdown.
## Usage
pdf-to-markdown
## Examples
Convert a research paper:
pdf-to-markdown ./paper.pdf
Upon restart, PrimeAgent recognizes /run pdf-to-markdown ./doc.pdf as a valid command in both CLI and TUI modes.
TUI Components: Extending the Terminal Interface
PrimeAgent's terminal UI, built on Blessed, exposes extension points in packages/tui/src/index.ts for custom widgets and key bindings.
Widget Implementation
// packages/tui/src/custom-status.ts
import { Box } from "blessed";
export function createStatusWidget(): Box {
const widget = new Box({
top: "100%-1",
left: 0,
width: "100%",
height: 1,
style: { bg: "gray", fg: "white" },
tags: true,
content: "{center}Custom Provider: Ready{/center}",
});
// Expose update method for external callers
(widget as any).setStatus = (text: string) => {
widget.setContent(`{center}${text}{/center}`);
widget.screen.render();
};
return widget;
}
Integration Point
// packages/tui/src/index.ts
import { createStatusWidget } from "./custom-status";
import { DEFAULT_EDITOR_KEYBINDINGS } from "./keys";
export function init(screen: blessed.Widgets.Screen) {
const status = createStatusWidget();
screen.append(status);
// Add custom key binding
DEFAULT_EDITOR_KEYBINDINGS["C-x"] = () => {
status.setStatus("Action triggered!");
};
// ... existing initialization
}
The widget integrates immediately because screen.append() registers it with Blessed's rendering loop.
Configuration Hooks: Runtime Behavior Modification
PrimeAgent's configuration system supports extension through environment variables and JSON configuration, resolved in two key files:
| File | Purpose | Extension Method |
|---|---|---|
packages/ai/src/env-api-keys.ts |
API key resolution | Add new provider API key patterns |
packages/coding-agent/src/core/model-resolver.ts |
Default model mapping | Register defaults for custom providers |
Both files use dynamic property access, so new environment variables or config keys become automatically available throughout the system without type definition changes.
Key Architectural Files for PrimeAgent Extension
Understanding these files clarifies how the plugin system operates:
-
packages/ai/src/providers/register-builtins.ts— Central AI provider registry with lazy-loading infrastructure -
packages/coding-agent/src/package-manager.ts— Skill discovery engine; implementsplugins/*/skillsglob scanning -
packages/tui/src/index.ts— TUI initialization hub; mounting point for custom components -
packages/ai/src/env-api-keys.ts— Environment-based configuration resolver -
packages/coding-agent/src/core/model-resolver.ts— Model-to-provider mapping defaults
Summary
PrimeAgent's extension architecture enables custom module integration through four mechanisms:
- AI providers — Implement
stream/streamSimpleinterfaces and register inregister-builtins.tsfor lazy-loaded LLM support - Skills — Create
plugins/<name>/skills/<skill>/directories withskill.tsandSKILL.mdfor auto-discovered commands - TUI widgets — Export Blessed components from
packages/tui/src/and append to the screen instance - Configuration — Extend
env-api-keys.tsormodel-resolver.tsfor runtime behavior customization
All extension points use dynamic import() and glob-based discovery, enabling drop-in functionality without recompiling the core project.
Frequently Asked Questions
Does PrimeAgent require rebuilding to add custom modules?
No. The package manager and provider registry use dynamic import() statements with glob patterns (plugins/*/skills). Place your code in the correct directory structure and restart PrimeAgent—the new functionality loads automatically without a build step.
What interface must a custom AI provider implement?
Your provider must export stream(model, messages, opts) and streamSimple(model, messages, opts) functions returning AssistantMessageEventStream or ReadableStream<string> respectively, as defined in packages/ai/src/types. Register via registerBuiltinProvider() in register-builtins.ts.
Can skills access the full PrimeAgent context?
Yes. The Skill.run method receives a context object containing args (parsed arguments), fs (sandboxed filesystem access), and llm (query interface to the active provider). Check packages/coding-agent/src/types.ts for the complete SkillContext interface.
How do I debug a skill that isn't loading?
Verify three things: (1) your file path matches plugins/*/skills/<name>/skill.ts, (2) the file exports skill as a named export matching the Skill interface, and (3) SKILL.md exists in the same directory. The package manager logs discovery results when DEBUG=prime-agent is set in your environment.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →