Skip to content
Back to skills

Voltagent

ASecurity

VoltAgent is an open-source TypeScript framework for building AI agents with typed tools, persistent memory, supervisor/sub-agent teams, MCP tools, guardrails and suspendable workflows, served over a local HTTP API. Use when someone asks to "build an AI agent in TypeScript", "add tools and memory to an agent", "set up a supervisor with sub-agents", "pause a workflow for human approval", "connect an agent to an MCP server", or mentions VoltAgent, @voltagent/core or create-voltagent-app.

  • 155 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 4, 2026
ai-agentstypescriptpythongobashsqlnoderailstestinggitapi

Works with

  • terminal
  • api
  • mcp

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add TerminalSkills/skills --skill voltagent --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Voltagent?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Voltagent
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-voltagent/badge)](https://www.skillsdirectory.com/skills/terminalskills-voltagent)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: voltagent
description: >-
  VoltAgent is an open-source TypeScript framework for building AI agents with
  typed tools, persistent memory, supervisor/sub-agent teams, MCP tools,
  guardrails and suspendable workflows, served over a local HTTP API. Use when
  someone asks to "build an AI agent in TypeScript", "add tools and memory to
  an agent", "set up a supervisor with sub-agents", "pause a workflow for human
  approval", "connect an agent to an MCP server", or mentions VoltAgent,
  @voltagent/core or create-voltagent-app.
license: Apache-2.0
compatibility: "Node.js 20.19+; @voltagent/core 2.x (peer: ai 6.x, zod 3.25+ or 4.x); an API key for the chosen LLM provider, or a local Ollama"
metadata:
  author: terminal-skills
  version: "1.0.0"
  category: development
  tags: ["ai-agents", "typescript", "multi-agent", "llm-workflows", "mcp"]
  repository: https://github.com/VoltAgent/voltagent
---
# VoltAgent — TypeScript Framework for AI Agents and Workflows

## Overview

VoltAgent (`@voltagent/core`) lets a Node.js project define agents in code: a model, instructions, Zod-typed tools, a memory adapter, optional sub-agents and guardrails. A `VoltAgent` instance registers agents and workflows and, with `@voltagent/server-hono`, serves them over a REST API on port 3141 with Swagger UI at `/ui`. Workflows are declarative step chains that can suspend for a human decision and resume later. The companion VoltOps Console (console.voltagent.dev, cloud or self-hosted) connects to the local server for traces, chat testing and workflow runs; the framework itself is MIT-licensed and works without it.

## Instructions

### Installation

Scaffold a project (asks for provider, package manager and server; writes `.env`):

```bash
npm create voltagent-app@latest order-desk
cd order-desk
npm run dev
```

The generated project has `src/index.ts`, `src/tools/`, `src/workflows/`, and scripts `dev` (`tsx watch --env-file=.env ./src`), `build` (tsdown), `start` (`node dist/index.js`) and `typecheck`. `--example <name>` starts from a folder of the repo's `examples/` directory, e.g. `npm create voltagent-app@latest -- --example with-research-assistant`.

Adding VoltAgent to an existing project instead:

```bash
npm install @voltagent/core @voltagent/server-hono @voltagent/libsql @voltagent/logger zod
```

Put the provider key in `.env`: `OPENAI_API_KEY` (platform.openai.com/api-keys), `ANTHROPIC_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY`, `GROQ_API_KEY` or `MISTRAL_API_KEY`.

### Define an agent with a tool and memory

Models can be given as `"provider/model"` strings (resolved by VoltAgent's built-in provider registry) or as AI SDK model objects.

```typescript
import { VoltAgent, Agent, Memory, createTool } from "@voltagent/core";
import { LibSQLMemoryAdapter } from "@voltagent/libsql";
import { honoServer } from "@voltagent/server-hono";
import { z } from "zod";

const lookupOrder = createTool({
  name: "lookupOrder",
  description: "Look up an order by ID and return its status and carrier",
  parameters: z.object({ orderId: z.string().describe("Order ID such as ORD-48213") }),
  execute: async ({ orderId }) => {
    const res = await fetch(`${process.env.ORDERS_API_URL}/orders/${orderId}`);
    return res.json();
  },
});

const memory = new Memory({
  storage: new LibSQLMemoryAdapter({ url: "file:./.voltagent/memory.db" }),
});

const support = new Agent({
  name: "order-support",
  instructions: "Answer order questions. Always call lookupOrder before answering.",
  model: "openai/gpt-4o-mini",
  tools: [lookupOrder],
  memory,
});

new VoltAgent({ agents: { support }, server: honoServer({ hostname: "127.0.0.1" }) });
```

Without `memory`, an agent keeps history in process memory only; `memory: false` disables it. `LibSQLMemoryAdapter` also accepts a Turso `url` plus `authToken`.

### Call an agent from code or over HTTP

```typescript
import { Output } from "ai";

const reply = await support.generateText("Where is order ORD-48213?", {
  memory: { userId: "cust-5521", conversationId: "ticket-9912" },
});
console.log(reply.text);

const stream = await support.streamText("Summarize my last three orders", {
  memory: { userId: "cust-5521", conversationId: "ticket-9912" },
});
for await (const chunk of stream.textStream) process.stdout.write(chunk);

const triage = await support.generateText("Classify: my parcel arrived damaged", {
  output: Output.object({ schema: z.object({ category: z.enum(["delivery", "damage", "billing"]) }) }),
});
console.log(triage.output.category);
```

Top-level `userId`/`conversationId` options still work but are deprecated in core 2.11; use the `memory` envelope. Structured output is `generateText`/`streamText` with an `output` setting; `generateObject`/`streamObject` are deprecated. The same calls are exposed by the server:

```bash
curl -s -X POST http://localhost:3141/agents/order-support/text \
  -H "Content-Type: application/json" \
  -d '{"input":"Where is order ORD-48213?","options":{"memory":{"userId":"cust-5521","conversationId":"ticket-9912"}}}'
```

Other routes: `GET /agents`, `POST /agents/:id/stream`, `POST /agents/:id/object`, `GET /workflows`.

### Supervisor and sub-agents

Passing agents in `subAgents` gives the supervisor an automatic `delegate_task` tool; it picks which specialist gets each part of the task.

```typescript
const billing = new Agent({
  name: "billing",
  instructions: "Handle invoices, refunds and payment failures.",
  model: "openai/gpt-4o-mini",
});

const lead = new Agent({
  name: "support-lead",
  instructions: "Route each question to order-support or billing, then write one reply.",
  model: "anthropic/claude-sonnet-4-5",
  subAgents: [support, billing],
  supervisorConfig: { customGuidelines: ["Never promise a refund amount"] },
});
```

### MCP tools

```typescript
import { MCPConfiguration } from "@voltagent/core";

const mcp = new MCPConfiguration({
  servers: {
    filesystem: {
      type: "stdio",
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-filesystem", "./policies"],
    },
  },
});
const policyTools = await mcp.getTools(); // names are prefixed: filesystem_read_file, ...
```

Pass `policyTools` into an agent's `tools`. Remote servers use `type: "http"` (or `"sse"`, `"streamable-http"`) with a `url`. Call `mcp.disconnect()` on shutdown.

### Guardrails

```typescript
import { createInputGuardrail, createInputLengthGuardrail } from "@voltagent/core";

const noCardNumbers = createInputGuardrail({
  name: "block-card-numbers",
  handler: async ({ inputText }) =>
    /\b\d{16}\b/.test(inputText ?? "")
      ? { pass: false, action: "block", message: "Please do not paste card numbers." }
      : { pass: true },
});
// new Agent({ ..., inputGuardrails: [createInputLengthGuardrail({ maxCharacters: 2000 }), noCardNumbers] })
```

A blocked input makes `generateText` throw with code `GUARDRAIL_INPUT_BLOCKED`. `outputGuardrails` work the same way on responses; ready-made ones include `createPIIInputGuardrail`, `createEmailRedactorGuardrail` and `createSensitiveNumberGuardrail`.

### Workflows with human approval

```typescript
import { createWorkflowChain } from "@voltagent/core";
import { z } from "zod";

export const refundApproval = createWorkflowChain({
  id: "refund-approval",
  name: "Refund Approval",
  purpose: "Auto-approve small refunds, pause large ones for a reviewer",
  input: z.object({ orderId: z.string(), amount: z.number() }),
  result: z.object({ status: z.enum(["approved", "rejected"]), approvedBy: z.string() }),
})
  .andThen({
    id: "check-amount",
    resumeSchema: z.object({ approved: z.boolean(), reviewer: z.string() }),
    execute: async ({ data, suspend, resumeData }) => {
      if (resumeData) return { ...data, approved: resumeData.approved, approvedBy: resumeData.reviewer };
      if (data.amount > 200) await suspend("Refund over $200 needs review", { orderId: data.orderId });
      return { ...data, approved: true, approvedBy: "auto" };
    },
  })
  .andThen({
    id: "finalize",
    execute: async ({ data }) => ({
      status: data.approved ? ("approved" as const) : ("rejected" as const),
      approvedBy: data.approvedBy,
    }),
  });
```

Register it with `new VoltAgent({ workflows: { refundApproval } })` to run it from the Console or REST. Other step builders: `andAgent` (call an agent inside a step), `andAll` and `andRace` (parallel), `andWhen` and `andBranch` (conditions), `andForEach`, `andSleep`, `andTap`.

## Examples

### Example 1: Order-status agent the frontend can call

**Request:** "Build me a TypeScript agent that answers 'where is my order' questions using our orders API and remembers each customer's ticket."

1. `npm create voltagent-app@latest order-desk`, pick OpenAI, then replace `src/index.ts` with the agent from "Define an agent with a tool and memory" and set `ORDERS_API_URL=https://orders.internal.shopnorth.io` in `.env`.
2. `npm run dev` prints `VOLTAGENT SERVER STARTED SUCCESSFULLY`, `HTTP Server: http://localhost:3141` and `Swagger UI: http://localhost:3141/ui`.
3. The frontend posts to `/agents/order-support/text`. The response looks like:

```json
{"success":true,"data":{"text":"Order ORD-48213 shipped via UPS, arriving 2026-10-03.","finishReason":"stop","toolCalls":[{"toolName":"lookupOrder","input":{"orderId":"ORD-48213"}}]}}
```

Follow-up messages with the same `conversationId` reuse the history stored in `.voltagent/memory.db`.

### Example 2: Refund workflow that waits for a manager

**Request:** "Refunds under $200 should go through automatically; bigger ones must wait until Maria approves them in our admin panel."

With the `refundApproval` workflow registered and the server running:

```bash
curl -s -X POST http://localhost:3141/workflows/refund-approval/execute \
  -H "Content-Type: application/json" \
  -d '{"input":{"orderId":"ORD-48377","amount":640}}'
```

```json
{"success":true,"data":{"executionId":"40be49cb-17d4-49ea-ae6b-5f278a92e993","status":"suspended","result":null}}
```

The admin panel stores the `executionId`; when Maria decides, it resumes:

```bash
curl -s -X POST http://localhost:3141/workflows/refund-approval/executions/40be49cb-17d4-49ea-ae6b-5f278a92e993/resume \
  -H "Content-Type: application/json" \
  -d '{"resumeData":{"approved":true,"reviewer":"maria.lopez"}}'
```

```json
{"success":true,"data":{"status":"completed","result":{"status":"approved","approvedBy":"maria.lopez"}}}
```

In code the same flow is `const wf = refundApproval.toWorkflow()`, register `wf` with `new VoltAgent({ workflows: { refundApproval: wf } })`, then `const run = await wf.run(input)` and `await run.resume({ approved: true, reviewer: "maria.lopez" })`. A $45 refund returns `status: "completed"` immediately with `approvedBy: "auto"`.

## Guidelines

- Pin one major version across the `@voltagent/*` packages. Core 2.x needs `ai` 6.x; the npm `latest` tag of `ai` and `@ai-sdk/openai` has moved to the next major, so if you pass AI SDK model objects install the `ai-v6` tagged versions (`npm install ai@ai-v6 @ai-sdk/openai@ai-v6`) or use `"provider/model"` strings, which need no extra provider package.
- Resuming from code needs the workflow registered on a `VoltAgent` instance and run through the same object: `const wf = chain.toWorkflow()`, register `wf`, call `wf.run()`. Resuming a chain that was never registered fails with "Workflow not found"; running the chain while `VoltAgent` holds its own copy fails with "Workflow state not found". Over REST this is handled for you.
- Suspension data is stored in the workflow's memory. Pass a persistent `Memory` (for example the LibSQL one above) as `memory` in `createWorkflowChain({...})` so approvals that wait for days survive a restart.
- Without auth every endpoint is open, including `POST /tools/:name/execute` (runs a tool directly) and `/api/memory/*` (reads stored conversations), and `honoServer()` listens on `0.0.0.0`, not localhost. For local-only use pass `honoServer({ hostname: "127.0.0.1" })`. Before exposing it, add `authNext: { provider: jwtAuth({ secret: process.env.JWT_SECRET! }) }` (`jwtAuth` is exported by `@voltagent/server-hono`) and run with `NODE_ENV=production`: in any other environment a request with the header `x-voltagent-dev: true` or `?dev=true` skips authNext.
- Tools run with your process's permissions. Validate inputs in `execute`, keep write actions narrow, and use `needsApproval` on tools that change data.
- Keep keys in `.env` (git-ignored). VoltOps keys (`VOLTAGENT_PUBLIC_KEY`, `VOLTAGENT_SECRET_KEY`, from console.voltagent.dev) are only needed to send traces to VoltOps.
- `maxSteps` caps tool-call loops per request; set it on agents whose tools can fail repeatedly.
- The official docs MCP server (`npx -y @voltagent/docs-mcp`) gives a coding agent current VoltAgent docs; use it when the API in this skill looks out of date. The repo README still shows the old name `@voltagent/mcp-docs-server`, which is not on npm.
- Not the right tool for Python stacks (use LangGraph, CrewAI or PydanticAI), for a single prompt-and-response call (the AI SDK alone is lighter), or when you need a visual no-code builder.

Files in this skill

  • SKILL.md12.9 KB
  • _scores.json1.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…