VirtuousAI
Primitives

Agents

Define, execute, and manage AI agents with composable tool access

Agents

Agents are first-class AI primitives defined as markdown documents with YAML frontmatter. They encapsulate instructions, tool access, and composition rules into reusable, versioned specs that can be executed on demand or delegated to by other agents.

Concept

An agent combines:

  • Instructions — Natural language directives (markdown body)
  • Configuration — Model, tools, and permissions (YAML frontmatter)
  • Composition — Which other agents it can delegate to

Examples:

AgentModeToolsUse Case
data-analystprimarygenerate_query, explain_schema, create_flashboardInteractive data analysis
sql-expertsubagentgenerate_query, explain_schemaSQL query specialist
research-botprimaryweb_search, fetch_page, call_agentWeb research with delegation

AgentSpec Format

Agent specs are markdown documents with YAML frontmatter. The frontmatter configures the agent's behavior; the body provides natural language instructions.

---
name: Data Analyst
slug: data-analyst
mode: primary
model: orchestrator
tools:
  - generate_query
  - explain_schema
  - create_flashboard
sub_agents:
  - sql-expert
permissions:
  max_cost_per_run: 5.00
---

# Goal

You are a data analyst specializing in e-commerce metrics.
Analyze connected data sources and build visual dashboards.

## Guidelines

- Always explain your reasoning before running queries
- Use gold-layer tables when available for performance
- Create flashboards for multi-metric analyses

Frontmatter Fields

FieldTypeRequiredDescription
namestringYesDisplay name
slugstringYesURL-safe identifier, unique per org
mode"primary" | "subagent"YesWhether agent appears in picker or only as delegate target
modelstringNoModel override (default: org setting)
toolsstring[]YesAllowed tool slugs (see Tool Access)
sub_agentsstring[]NoAgent slugs this agent can delegate to via call_agent
permissionsobjectNoFine-grained permission overrides
descriptionstringNoShort description shown in agent picker

Permissions

FieldTypeDescription
allowed_connectionsstring[]Restrict which connections the agent can access
allowed_actionsstring[]Restrict which action kinds are permitted
max_cost_per_runnumberMaximum cost budget per execution

Agent Modes

Agents operate in one of two modes:

ModeAppears in PickerCan Use call_agentCan Be CalledUse Case
primaryYesYesYesUser-facing entry points
subagentNoNoYesDomain specialists called by primary agents

Subagents cannot use call_agent. This prevents infinite delegation loops. Only primary agents can delegate.

Agent Run Lifecycle

Each execution creates an AgentRun that tracks status through a defined lifecycle:

StatusDescriptionCan Transition To
PENDINGCreated, awaiting executionRUNNING, CANCELLED
RUNNINGActively executing toolsAWAITING_APPROVAL, COMPLETED, FAILED, CANCELLED
AWAITING_APPROVALWrite tool needs human approvalRUNNING (approved), CANCELLED (rejected)
COMPLETEDFinished successfully— (terminal)
FAILEDEncountered an error— (terminal)
CANCELLEDManually cancelled or rejected— (terminal)

Execution Model

Agent execution uses Server-Sent Events (SSE) for real-time streaming. Each tool invocation is tracked as a step, and write operations create approval gates.

SSE Event Types

EventDescription
run_startedExecution began
step_startedTool invocation starting
step_completedTool invocation finished
approval_requiredWrite tool needs human approval
narrationAgent's reasoning/commentary
run_completedExecution finished successfully
run_failedExecution encountered an error

DAG Building

During execution, every tool call is recorded as a step in a directed acyclic graph (DAG). This DAG captures the execution order and dependencies, enabling crystallization — converting the run into a deterministic automation.

Tool Access

Agents can use any combination of the following tools. Grant only what's needed for the agent's domain.

ToolCategoryRiskDescription
generate_queryDataReadGenerate and execute SQL queries against connected schemas
explain_schemaDataReadExplain table structures and column meanings
web_searchResearchReadSearch the web via Tavily API
fetch_pageResearchReadExtract readable content from URLs
call_agentDelegationReadInvoke another agent by slug
create_flashboardOutputWriteBuild a persistent dashboard from data
http_requestIntegrationWriteMake arbitrary HTTP requests to external APIs

Tool Risk Levels

Read tools execute without approval. Write tools create an approval gate, pausing execution until a human approves or rejects.

Composition and Delegation

The call_agent tool enables agents to delegate tasks to other agents by slug. This is the core composition primitive.

How It Works

  1. Primary agent encounters a task outside its expertise
  2. Calls call_agent(agent="sql-expert", question="Optimize this query...")
  3. Subagent executes with its own tools and instructions
  4. Result is returned to the calling agent
  5. Calling agent continues with the subagent's response

Rules

RuleDescription
Explicit sub_agentsAn agent can only call agents listed in its sub_agents field
Depth guardMaximum delegation depth prevents infinite recursion
No self-callsAn agent cannot call itself
Subagent restrictionSubagents cannot use call_agent — only primary agents can delegate

Composition Example

# Primary agent: operations-bot
sub_agents:
  - data-analyst
  - report-builder

# When operations-bot needs data analysis, it calls:
# call_agent(agent="data-analyst", question="...")
# The data-analyst runs with its own tools, returns results

Performance and Evaluation

Agent specs track execution statistics:

MetricDescription
Total runsNumber of times the agent has been executed
Success ratePercentage of runs that completed successfully
Average durationMean execution time across runs
Crystallization countHow many runs have been crystallized into automations
Feedback statsThumbs up/down from users

Access stats via GET /api/v1/agents/specs/{spec_id}/stats.

Creating Agent Specs

curl -X POST https://vai-dev.virtuousai.com/api/v1/agents/specs \
  -H "Authorization: Bearer $VAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "---\nname: Data Analyst\nslug: data-analyst\nmode: primary\ntools:\n  - generate_query\n  - explain_schema\n---\n\n# Goal\n\nAnalyze connected data sources and answer questions about business metrics."
  }'

The API accepts the full agent spec as a markdown string. The YAML frontmatter is parsed for configuration, and the markdown body becomes the agent's instructions.

---
name: Data Analyst
slug: data-analyst
mode: primary
tools:
  - generate_query
  - explain_schema
---

# Goal

Analyze connected data sources and answer questions
about business metrics.

Crystallization

Successful agent runs can be crystallized into deterministic automations. The DAG built during execution is extracted and converted into an automation workflow that can be replayed without AI involvement.

curl -X POST https://vai-dev.virtuousai.com/api/v1/agents/runs/{run_id}/crystallize \
  -H "Authorization: Bearer $VAI_API_KEY"

See Crystallization for details.

Best Practices

  1. Keep instructions focused — One agent, one domain. A data analyst should not also handle email campaigns
  2. Use subagent mode for specialists — If an agent is only called by other agents, make it a subagent
  3. Grant minimum necessary tools — Don't give http_request to an agent that only needs generate_query
  4. List sub_agents explicitly — Avoid open-ended delegation; enumerate which agents can be called
  5. Test with approval flow — Review tool calls before enabling autonomous execution
  6. Write clear instructions — The markdown body is the agent's primary guidance; be specific about behavior

OpenAPI Reference

For detailed endpoint schemas, request/response formats, and authentication:

On this page