Preface

You can spin up a TypeScript Agent project with create-voltagent or npm create voltagent-app@latest, but when you actually start writing business logic, your coding assistant will keep asking the same set of questions: Should I use Agent or Workflow? How should I structure the src/ directory? Should memory be attached to the entry point or a single object? Which server should I choose between Node.js processes and Cloudflare Workers? How do I connect observability data to VoltOps?

All these questions have answers in the official documentation, but they are scattered across the Agent, Workflow, Memory, Server, and Observability chapters. Every time the model improvises, the project will gradually grow into a structure that “works but doesn’t align with the framework’s conventions”.

voltagent-best-practices collects these conventions into a single Agent Skill. It originates from the official VoltAgent-maintained VoltAgent/skills repository, with the main content in skills/voltagent-best-practices/SKILL.md, licensed under MIT. The same SKILL.md is written in the universal Agent Skills format, and can be loaded by tools that support Skills such as Cursor, Codex CLI, and Claude Code.

Unlike “running a single scaffold command”, this document carries framework-level architectural knowledge: when to use Agent vs Workflow, how to organize your directory structure, how to choose memory and server options. It does not replace voltagent.dev/docs, but instead helps your coding assistant align with official conventions before writing code.

What This Is

One-sentence positioning: A quick reference manual for VoltAgent architecture patterns and conventions, covering tradeoffs between Agent and Workflow, project layout, default memory settings, server providers, and observability integration.

Official frontmatter:
- name: voltagent-best-practices
- description: VoltAgent architectural patterns and conventions. Covers agents vs workflows, project layout, memory, servers, and observability.
- author: VoltAgent
- version: 1.0.0
- license: MIT
- repository: https://github.com/VoltAgent/skills

VoltAgent is an open-source TypeScript Agent engineering platform: the runtime is in @voltagent/core (Agent, Tool, Memory, Workflow, etc.), and the observability and operations side is VoltOps. The VoltAgent class itself is the application entry point, responsible for registering Agents/Workflows together, applying global default values, and starting HTTP or serverless providers as needed. The official documentation entry point is voltagent.dev/docs.

There are three supporting Skills in the same repository; do not mix up their responsibilities:
- create-voltagent: Create a project from scratch (CLI or manual scaffold)
- voltagent-core-reference: Reference for VoltAgent class options and lifecycle
- voltagent-docs-bundle: Access embedded documentation matching your current @voltagent/core version

The scope of voltagent-best-practices is “after you have decided to use VoltAgent, write your project structure according to official conventions”. You should still run create-voltagent first when creating a new repository.

officialskills.sh summarizes it the same way as SKILL.md: putting all conventions in one place means you no longer have to dig through the VoltAgent monorepo every time you start a new project to find the correct imports, memory patterns, or server options.

Core Features and Highlights

The Skill text is not long, and is divided into quick reference sections. Below is the official SKILL.md content, with details cross-checked against the VoltAgent documentation to supplement priorities and package names.

First, Distinguish Between Agent and Workflow

The judgment criteria given by the Skill are only two lines, but they are enough as default rules:

Use When
Agent Open-ended tasks that require tool selection and adaptive reasoning
Workflow Multi-step pipelines with explicit control flow that need to suspend/resume

The official Workflow documentation describes Workflows as step chains strung together with methods like .andThen(), .andAgent(), and .andWhen(); the HTTP API also has corresponding suspend/resume endpoints: POST /workflows/:id/executions/:executionId/suspend and .../resume. The reimbursement approval example in the scaffold follows this pattern: suspend the workflow when the amount exceeds a threshold, and wait for someone to resume it with resumeData.

Conversely, for tasks where the next step depends on model judgment, such as customer service Q&A and research assistants with tools, the Skill requires using Agent. The official API Overview also separates Agent endpoints (/agents/:id/text, streaming, object) from Workflow endpoints, and the two are not the same execution model.

A practical inference: Use Workflow when the step order is known in advance and may require waiting for people or external events; use Agent when the path requires the model to select tools on the spot. The two can be combined—call an Agent within a Workflow step—but you must first choose the correct entry type.

The directory structure given by the Skill is:

src/
|-- index.ts
|-- agents/
|-- tools/
`-- workflows/

The create-voltagent scaffold generates src/index.ts, src/tools/, and src/workflows/ by default, and Agents are often written directly in the entry file. voltagent-best-practices additionally requires placing Agents in src/agents/. The two do not conflict: the CLI provides a minimal runnable structure, and this Skill provides a way to split your project as it scales.

The entry file is responsible for new VoltAgent({ agents, workflows, server }). Specific Agents, Tools, and Workflows are placed in their respective directories to avoid cluttering everything into index.ts.

Memory: Use Shared Defaults, Split Only When Needed

The Skill only has two rules for memory:
- Use memory as the shared default for Agents and Workflows
- Use agentMemory or workflowMemory when their default values need to differ

The official VoltAgent Instance and Memory Overview clarify the priority more completely:
- For Agents: instance-level memory > entry-level agentMemory > entry-level memory > built-in memory
- For Workflows: instance-level memory > entry-level workflowMemory > entry-level memory > built-in memory

Omitting memory will not turn off memory; it will fall back to the above defaults (or built-in in-memory storage). To completely disable memory on a specific Agent, the official写法 is to explicitly set memory: false.

There is also a easy-to-confuse distinction: the memory on a Workflow stores execution history (input/output of each step, status, latency), which is not the same as conversation memory on an Agent. The official Workflow documentation explicitly calls out this difference. The Skill lets you configure default storage once at the entry point; you can choose adapters like InMemory, LibSQL, Postgres, or Managed Memory from the Memory documentation, and this Skill does not cover each adapter in detail.

Server: Use Hono/Elysia for Node.js, Serverless for Fetch Runtimes

The Skill’s server options:
- Node.js HTTP: @voltagent/server-hono
- Node.js alternative: @voltagent/server-elysia
- Fetch runtimes like Cloudflare, Netlify: use the serverless provider

The official API Overview lists Hono as the recommended implementation, with Elysia as another high-performance alternative; both can be attached with new VoltAgent({ server: honoServer() }) or elysiaServer(). The default port in the documentation and Quick Start is 3141, and the Swagger UI is available at /ui.

For serverless, the official deployment documentation gives the specific package @voltagent/serverless-hono, with the entry写法 serverless: serverlessHono(), and then export toCloudflareWorker() or Netlify handler. The Skill only mentions “serverless provider”, so refer to the package names in the deployment documentation when writing code.

Observability: Connect to VoltOps with Environment Variables

The Skill has two rules:
- Use VoltOpsClient or createVoltAgentObservability for tracing
- If VOLTAGENT_PUBLIC_KEY and VOLTAGENT_SECRET_KEY are set, VoltAgent will automatically configure VoltOps

This matches the official Observability Setup: after adding both keys to environment variables, you do not need to write additional observability code for basic use. The keys can be obtained from the project settings at console.voltagent.dev, in the format pk_xxxx and sk_live_xxxx. If you need a service name or sampling rate, use createVoltAgentObservability({ serviceName, voltOpsSync: { sampling: ... } }); if you need to explicitly pass the client to VoltAgent, use voltOpsClient: new VoltOpsClient({ publicKey, secretKey }).

Embedded Recipes and a Repository-Specific Gotcha

The Skill points to shorter practice recipes in the embedded documentation of the VoltAgent monorepo:

packages/core/docs/recipes/

The retrieval command is:

rg -n "keyword" packages/core/docs/recipes -g"*.md"

These paths are relative to the voltagent/voltagent repository (and @voltagent/core/docs after installation), not the VoltAgent/skills repository itself. When you need to look up embedded documentation matching your current core version, the voltagent-docs-bundle in the same repository is more suitable.

The final Footguns note: Do not use JSON.stringify inside the VoltAgent package, instead use safeStringify from @voltagent/internal. This is a convention for modifying framework source code and submitting PRs to VoltAgent (the official repository’s coding guideline also states this), and it does not require business projects to replace all serialization code. JSON.stringify can easily throw errors on Agent objects or tool results with circular references, so the framework internally uses safeStringify instead.

Installation and Activation

This Skill is included in the VoltAgent/skills repository. The official README and Docs for AI Assistants both use npx skills add as the standard method; this command will install all Skills in the repository, not just voltagent-best-practices.

Official Recommendation (Agents Supporting add-skill)

npx skills add VoltAgent/skills

If you only want to install this single Skill on officialskills.sh or skills.sh, the command is:

npx skills add https://github.com/VoltAgent/skills --skill voltagent-best-practices

The official documentation separates Local Skills and MCP documentation services: Skills are suitable for assistants that can read local files; if you want to search for documentation, examples, and changelogs on demand in Cursor / VS Code, you can use @voltagent/docs-mcp. This is not the Skill itself, but it is part of the same toolchain for “getting AI to write VoltAgent code according to official conventions”.

Manual Clone

git clone https://github.com/VoltAgent/skills.git

Then place skills/voltagent-best-practices/ into the Skill directory scanned by your tools. SKILL.md is in the universal format. According to Cursor’s documentation, project-level Skills are automatically discovered from .agents/skills/ and .cursor/skills/; user-level paths correspond to ~/.agents/skills/ and ~/.cursor/skills/. Compatible directories also include .claude/skills/, .codex/skills/, and their corresponding user-level paths. When placing manually, the directory should look like:

.cursor/skills/voltagent-best-practices/SKILL.md

Or:

.agents/skills/voltagent-best-practices/SKILL.md

For Claude Code, project-level paths are .claude/skills/voltagent-best-practices/SKILL.md, and user-level paths are ~/.claude/skills/voltagent-best-practices/SKILL.md. Codex CLI scans $CODEX_HOME/skills (default ~/.codex/skills) and project-level .codex/skills/.

After activation, you can manually call it by searching for voltagent-best-practices by typing / in the chat. When a user says “organize the project according to VoltAgent conventions”, “should I use Agent or Workflow for this”, or “how to connect VoltOps”, the agent should automatically select this Skill based on its description.

Typical Usage Examples

The code below is from the official SKILL.md and matches the写法 in VoltAgent Instance and Workflow Overview.

Let the Assistant Make Architectural Choices According to Conventions

After installing the Skill, you can directly pass the judgment criteria to it:

Please design this VoltAgent service according to voltagent-best-practices:
The user uploads a long document, extracts text first, generates a summary, then writes to the database.
The steps are fixed, and may require human review in between. Decide whether to use Agent or Workflow,
and provide file划分 according to the recommended src/ layout.

According to the Skill’s table, this should be implemented as a Workflow (multi-step, explicit control flow, possible suspend/resume), not a single large Agent that “thinks” through all three steps. In terms of files, you should have a src/workflows/ directory instead of writing the pipeline in src/agents/.

Another type of prompt is more suitable for Agent:

Please add an assistant according to voltagent-best-practices: after the user asks a question, the model decides
whether to check the weather, search the knowledge base, or answer directly. Place it in the recommended directory, and use openai/gpt-4o-mini for the model.

Basic Agent

The minimal Agent from the Skill:

import { Agent } from "@voltagent/core";

const agent = new Agent({
  name: "assistant",
  instructions: "You are helpful.",
  model: "openai/gpt-4o-mini",
});

The model string format is provider/model. The Skill gives examples of openai/gpt-4o-mini and anthropic/claude-3-5-sonnet. The official documentation states that when using this string format, you do not need to separately import the provider SDK, just add the corresponding API key to the environment variables. Both the documentation and repository README also have Vercel AI SDK写法 like openai("gpt-4o-mini"), and both appear in official materials; this Skill uses the string format.

Basic Workflow

The minimal Workflow from the Skill uses createWorkflowChain + Zod to declare input and output, then connects a step with .andThen():

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

const workflow = createWorkflowChain({
  id: "example",
  input: z.object({ text: z.string() }),
  result: z.object({ summary: z.string() }),
}).andThen({
  id: "summarize",
  execute: async ({ data }) => ({ summary: data.text }),
});

This is only a structural example: execute directly places text into summary to demonstrate the chain API, not a real summarization model. When you need the model to participate in a step, the official Workflow documentation uses .andAgent(), or directly calls agent.generateText() / streamText() within .andThen().

Entry Point: Register Agents, Workflows, and Server Together

import { VoltAgent } from "@voltagent/core";
import { honoServer } from "@voltagent/server-hono";

new VoltAgent({
  agents: { agent },
  workflows: { workflow },
  server: honoServer(),
});

This is the bootstrap snippet from the Skill. The official Instance documentation also allows passing agentMemory / workflowMemory, voltOpsClient, observability, and logger at the same location. When switching to Elysia, change the import to elysiaServer from @voltagent/server-elysia; when deploying to Cloudflare / Netlify, stop using server: honoServer() and switch to serverless: serverlessHono().

How to Configure Memory Defaults in the Entry Point

The split写法 from the official Instance documentation corresponds to the Skill’s agentMemory / workflowMemory:
```typescript
import { Memory, VoltAgent } from “@voltagent/core”;
import { LibSQLMemoryAdapter } from “@voltagent/libsql