Getting Started

AgentScript is an open agent specification language. Define agents as single .agent files with a declarative, block-based syntax for state, execution flow, instructions, and deterministic control hooks.

Overview

An AgentScript file describes what an agent is — its identity, state variables, available actions, and reasoning instructions. The runtime handles how it executes, meaning the same script can run on increasingly capable runtimes without any changes.

The language was developed for Salesforce Agentforce but is designed to apply to agents in general. The toolchain — parser, linter, compiler, LSP, and editor integrations — is fully open source under Apache 2.0.

What's in the repo

  • Parser — two backends: a hand-written TypeScript parser and a Tree-sitter C/WASM parser
  • Language service — scope resolution, linting (18+ passes), Language Service API
  • Compiler — transforms AST → Salesforce runtime specification with source maps
  • LSP server — Node.js and browser workers for IDE integration
  • VS Code extension — diagnostics, completions, hover, go-to-definition, rename
  • Monaco integration — for browser-based editors
  • UI Playground — React + Vite playground with graph view and CST explorer

The runtime is Salesforce-internal and not open sourced. You can parse, lint, compile, and build tooling around AgentScript, but running agents requires Salesforce's runtime environment.

Installation

Prerequisites

The recommended setup uses mise, which installs the exact toolchain versions pinned in mise.toml:

mise install

Or install manually:

  • Node.js 22 (minimum >=18)
  • pnpm 10 — run corepack enable pnpm once
  • tree-sitter CLI 0.25.x — required to build the parser-tree-sitter package

macOS: brew install tree-sitter installs the C library only, not the CLI. Use mise install (recommended) or brew install tree-sitter-cli.

Clone and build

git clone https://github.com/salesforce/agentscript.git
cd agentscript
pnpm install
pnpm build

Quick Start

Run the UI playground

pnpm ui:dev

Opens the AgentScript playground at http://localhost:27002. It includes a Monaco editor, graph view, CST/AST explorer, and preloaded examples.

Install the SDK

Packages are published to npm under the @sf-agentscript/* scope:

npm install @sf-agentscript/agentforce
# or
pnpm add @sf-agentscript/agentforce
import { parse } from '@sf-agentscript/agentforce';

const doc = parse(`
system:
    instructions: "You are a helpful agent."

start_agent main:
    reasoning:
        instructions: ->
            | Help the user with any questions.
`);

console.log(doc.hasErrors);    // false
console.log(doc.diagnostics);  // []
console.log(doc.emit());       // formatted source

Your First Agent

Create a file named my_agent.agent. Every agent needs at least a start_agent block with a reasoning section:

my_agent.agent
system:
    instructions: "You are a helpful customer support agent."
    messages:
        welcome: "Hello! How can I help you today?"
        error: "Sorry, something went wrong."

config:
    agent_name: "SupportBot"

variables:
    customer_name: mutable string = ""
        description: "The customer's name"
    issue_resolved: mutable boolean = False
        description: "Whether the issue has been resolved"

start_agent support:
    description: "Handles customer support inquiries"

    reasoning:
        instructions: ->
            | Greet the customer and ask how you can help.
            if @variables.customer_name != "":
                | Address them by name: {!@variables.customer_name}
            | Always be concise and professional.
        actions:
            capture_name: @utils.setVariables
                description: "Capture customer name from conversation"
                with customer_name=...
            escalate: @utils.escalate
                description: "Hand off to a human agent"

Key elements explained

  • system — global instructions inherited by all subagents, plus standard messages.
  • config — agent metadata like name and description.
  • variables — typed state that persists across turns. mutable variables can be written; linked variables are read-only runtime values.
  • start_agent — the entry point. Exactly one per script. Functions identically to subagent.
  • reasoning.instructions — a procedure that builds the LLM's prompt. Re-evaluated each turn, so it can reflect current variable state.
  • reasoning.actions — action bindings available to the LLM during reasoning.
  • @utils.setVariables — built-in utility for slot-filling: the LLM extracts values from conversation and sets them.

Using the SDK

The @sf-agentscript/agentforce package is the batteries-included SDK that combines the parser, language service, and compiler:

import { parse, compileSource } from '@sf-agentscript/agentforce';

// Parse and analyze
const doc = parse(source);

if (doc.hasErrors) {
  for (const diag of doc.diagnostics) {
    console.error(`${diag.severity}: ${diag.message} at line ${diag.range.start.line}`);
  }
}

// Get formatted source
const formatted = doc.emit();

// Compile to runtime spec (Agentforce dialect)
const compiled = compileSource(source);
console.log(compiled.spec);   // JSON runtime specification
console.log(compiled.maps);   // source maps

Document mutation

The Document class supports mutation with undo/redo:

import { parse } from '@sf-agentscript/agentforce';

const doc = parse(source);

// Mutate
doc.set(['config', 'agent_name'], 'NewName');

// Undo / redo
doc.undo();
doc.redo();

// Get updated source
console.log(doc.emit());

UI Playground

The browser playground at http://localhost:27002 (run with pnpm ui:dev) includes:

  • Monaco editor — full LSP experience: diagnostics, completions, hover, go-to-definition
  • Graph view — visualize the agent's topic/subagent flow as a node graph
  • CST/AST explorer — inspect the concrete and abstract syntax trees in real time
  • Compiled output — see the JSON runtime specification the compiler produces
  • Multiple dialects — switch between agentscript, agentforce, and agentfabric
  • Preloaded examples — hello world, order tracking, lead qualification, weather assistant

Blocks

Everything in AgentScript is a block. Blocks compose to form an agent. There are two categories:

  • Configuration blocks (config, system, language) — set up the agent's identity and behavior.
  • Execution blocks (start_agent, subagent, topic) — define how the agent runs. These have implied execution — the runtime's ReAct loop is handled behind the scenes.

Blocks are indentation-sensitive, like Python or YAML. A block is a key followed by :, with its children indented below:

config:
    agent_name: "Support Bot"
    description: "An AI assistant for customer support"

Some blocks accept an instance name after the block type:

subagent billing:
    description: "Handles billing inquiries"

start_agent router:
    description: "Routes users to the right subagent"

Determinism vs. Autonomy

AgentScript does not prescribe how much control you take. The language gives you the tools — how you use them is up to you.

More deterministic More autonomous
Use before_reasoning to gate transitions and guard against bad state Write only reasoning.instructions and let the LLM decide everything
Use if/else in instructions to focus the LLM's context Provide broad instructions and a rich action set
Use set in after_reasoning to explicitly drive state Use @utils.setVariables and let the LLM slot-fill
Use run in before_reasoning to fetch data before the LLM reasons Expose actions in reasoning and let the LLM call them

Most real agents sit somewhere in between. The key principle: execution is decoupled from specification. More procedures = more determinism. Fewer procedures = more autonomy.

Dialects

A dialect is a collection of block types, their schemas, and lint rules. Dialects extend the base AgentScript schema with platform-specific blocks and constraints.

DialectDescription
agentscript Base dialect. Core blocks: system, config, variables, actions, start_agent, subagent, reasoning, etc.
agentforce Salesforce Agentforce. Adds modality, security, model_config, related_agent, language. Has its own compiler.
agentfabric AgentFabric platform. Alternative schema, lint rules, and compiler output.

To select a dialect in a script, add a comment in the first 10 lines:

# @dialect: agentforce=2.2

If no dialect comment is present, the LSP/parser uses defaultDialect or the first registered dialect.

💡

Custom dialects can be built by creating a DialectConfig object with a schema and lint passes, then registering it in the LSP server and UI. See Packages → Dialect Layer for details.

Next steps

  • Language Guide — complete reference for all syntax and blocks
  • Examples — real-world agents with annotated code
  • Packages — SDK and toolchain package reference