Skip to content

Repository files navigation

Roboport

Agents as Code

A minimal framework for building agents.

Composable primitives with sane defaults. Bring your own models, tools, skills; or just use the built-ins.

  • Minimal: one dependency (Zod), small core
  • High level: no tool approvals, no steering
  • Modular: swap out built-in components or implement custom ones
  • Batteries included — harness presets, a built-in skill bundle, and MCP client support

Docs

Install

bun add roboport zod

Example

import { Agent } from 'roboport';
import { claudeCode } from 'roboport/harness';
import { Anthropic } from 'roboport/models';
import { prReview } from 'roboport/skills';
import { github } from 'roboport/triggers';

const agent = new Agent({
  model: new Anthropic('claude-opus-4-8', { thinking: 'medium' }),
  system: claudeCode.system,
  tools: claudeCode.tools,
  skills: [prReview],
});

const gh = github({ secret: process.env.GITHUB_WEBHOOK_SECRET });
agent.on(
  gh.pullRequest({ actions: ['opened', 'synchronize'] }),
  async (event) => {
    await using session = agent.session();
    await session.send(
      `Review PR #${event.number} in ${event.repository.full_name}. ` +
        `Post the verdict and any line-level findings to GitHub.`,
    );
  },
);

await agent.start();

Sessions

agent.session() returns a Session you can stream from and reuse across turns.

await using session = agent.session();

// Stream events as they arrive
for await (const event of session.send('Summarise the branch.')) {
  if (event.type === 'text-delta') process.stdout.write(event.text);
  if (event.type === 'tool-call') console.log(`→ ${event.toolName}`);
  if (event.type === 'tool-result') console.log(`← ${event.toolName}`);
}

// Or await the turn for the post-turn message history
const messages = await session.send('Now write a PR description.');

Resume a prior conversation by passing its message history:

const resumed = agent.session({ messages: savedMessages });
await resumed.send('Continue from here.');

Sessions hold MCP connections for their lifetime, so close them when done (or use await using).

Learn more

Skills

import { Skill } from 'roboport';
import { prReview, docsUpdate } from 'roboport/skills';

const releaseNotes = new Skill({
  name: 'release-notes',
  description: 'Draft release notes from merged PRs.',
  content: '# Release notes\n\n...',
});

const agent = new Agent({
  // …
  skills: [docsUpdate, releaseNotes],
});

Skills are lazy-loaded by the model.

Learn more

MCP

import { Grafana, Linear } from 'roboport/mcp';

const agent = new Agent({
  // …
  mcp: [
    new Grafana({
      url: process.env.GRAFANA_URL,
      serviceAccountToken: process.env.GRAFANA_TOKEN,
    }),
    new Linear({ apiKey: process.env.LINEAR_API_KEY }),
  ],
});

MCP tools are deferred by default and surfaced via ToolSearch.

Learn more

Triggers

A trigger is an event source. The handler decides whether to start the agent.

import { cron, github } from 'roboport/triggers';

// Time-based, fires in-process
agent.on(cron({ schedule: { every: 'day', at: { hour: 9 } } }), async () => {
  await using session = agent.session();
  await session.send('Post the daily standup summary.');
});

// Webhook-based
const gh = github({ secret: process.env.GITHUB_WEBHOOK_SECRET });
agent.on(gh.pullRequest({ actions: ['opened'] }), async (event) => {
  await using session = agent.session();
  await session.send(`Review PR #${event.number}.`);
});

await agent.start();

A webhook trigger needs a URL to receive events. Bind the receiver's handle to a route:

app.post('/webhooks/github', (c) => gh.handle(c.req.raw));

Learn more

Channels

A channel is a two-way connection between a chat transport and an agent: inbound messages run a turn, the reply is relayed back. serve wires it up — one long-lived conversation per chat, serialized, with a "typing" indicator and in-memory history by default (swap in fileStore to persist).

import { serve, telegramChannel } from 'roboport/channels';

// Long-polling by default
const bot = serve(agent, telegramChannel({ token: process.env.TELEGRAM_TOKEN }));

Learn more

Status

Early. Experimental. APIs will change.

About

Agents as Code

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages