AgentPulse Script
A rendered, navigable view of Agentforce Agent Script (.agent) files, toggled the same way
as Markdown preview, plus a dedicated Tests panel. Works in both Cursor and VS Code — Cursor
is a VS Code fork, so one unpacked extension serves both.
Part of the AgentPulse family of developer tools (alongside the agentpulse CLI); this
extension is the Agent Script previewer + test harness and ships independently.
Install
Open the Extensions view, search AgentPulse Script, and click Install:
Cursor is a VS Code fork, so the same package serves both editors.
Prefer a file? Cmd+Shift+P → Extensions: Install from VSIX..., pick the .vsix, then
Cmd+Shift+P → Developer: Reload Window.
Prerequisites & setup
There are two tiers, and the extension shows exactly where you stand in its Setup & Status view
(the pulse icon in the Activity Bar, or click AgentPulse Script in the status bar):
- Preview — no setup. Rendering
.agent files needs nothing but the extension. It works on any
machine, in any workspace.
- Tests panel — a few prerequisites (all checked live in the Setup & Status view):
- Node 18+ and the Salesforce CLI (
sf) on your PATH.
- An authenticated org:
sf org login web. Either make it your default (sf config set target-org <alias>) or set agentScript.suite.org to its alias/username. (Nothing is
hard-coded — with the setting empty the suite uses your default org.)
- A coding CLI — Claude Code by default; for anything else set
agentScript.ai.* (see
Choosing a coding CLI).
- The workspace must ship the suite
scripts/ and the .agent file must live under
aiAuthoringBundles/<bundle>/. If the scripts aren't present, the Tests panel is unavailable and
the previewer still works.
Use
Open any .agent file, then either:
- click the preview icon in the editor title bar,
- press
Cmd+K V to toggle the preview beside the file, or
- press
Cmd+Shift+V to toggle it in the current column.
Running the command again closes the preview, so the icon acts as a toggle.
The preview follows the file as you type — no save required — and keeps your scroll position
and expanded sections across re-renders. Clicking any line in the preview jumps the editor to
that line.
What it shows
- Deterministic vs. model-facing phases.
before_reasoning and after_reasoning are
marked deterministic; reasoning is marked model-facing, so it is obvious at a glance which
behaviour you authored and which you delegated to the model.
- Colour-coded references. Variables, actions, outputs, and subagents are chipped, so a
@variables.scheduleState read stands out from surrounding prose.
- Instructions as the model reads them, with the
if branches shown as structure rather
than buried in indentation.
- Tools offered per phase, action definitions with input/output fields and their flags, and
the variable table with kind, type, default, and source.
- A block sidebar for jumping between the system block, config, and each subagent.
Base64-encoded genAiPlannerBundle files are decoded automatically.
Testing (the Tests panel)
The Tests panel runs a generate → review → run → verify → diagnose loop over the agent in its own
editor tab. Open it with the beaker icon in a .agent file's title bar, the AgentPulse Script:
Open Tests command, or by right-clicking a .agent file. Its left rail is resizable and the width
is remembered.
- Generate reads the
.agent with your coding CLI (Claude by default — see Choosing a coding
CLI) and drafts regression scenarios. Fresh drafts land in a Review group; Keep promotes
one into the Suite, Discard sets it aside. Deep edits open the JSON file. A run executes
only the kept set.
- Scenarios are dynamic. Generated scenarios are customers, not scripts — each is a persona
plus objectives. At run time an LLM plays that customer turn-by-turn against the agent's
actual replies, so it answers whatever the agent asks (follow-ups, disambiguation, re-asks) the
way a real person would. A hand-authored scripted scenario (a fixed
utterances list, replayed
blind) still runs but is never generated — use it only when exact wording or message order is what
you're testing. The card shows which mode a scenario is in.
- Grounding table + gate. Every data need a generated scenario has becomes a
{{name}} token
(a real email, a booking id that exists, a known port) registered in a shared table. Until a human
fills a real value, the scenario is flagged needs grounding and cannot run — a sample
example does not count, because the org can't resolve invented data and the run would fail exactly
the way we're trying to prevent. Tokens are substituted at run time, including for the dynamic
customer, which volunteers the real value when the agent asks. The table lives in
scripts/grounding.<bundle>.json, which is git-ignored because it holds real customer data.
- Verification is layered and deterministic: what the agent said (regex on the final reply),
what the planner did (topic + invoked actions from the Agentforce DX traces), and what landed in
the backend (Case classification, plus an optional per-scenario Apex hook).
- Bring your own backend check (Apex verifier). A scenario's
apexVerify runs anonymous Apex
against the org after the conversation, keyed on the real session, and reads a verdict back from a
single System.debug('AGV_VERIFY ' + JSON.serialize(m)) line where m is a
Map<String,Object> with at least ok (Boolean) and reason (String). You can supply it four ways,
resolved in this order — inline { code }, a snippet { file }, a deployed verifier
{ class, method } (signature Map<String,Object> method(String sessionId) — the harness wraps it
into the sentinel for you), or { use: "<name>" } naming a reusable entry in
scripts/verifiers.<bundle>.json (whose fields feed the same resolution; the scenario's own fields
win). Give expect: {…} to assert specific sentinel fields instead of just ok. __SESSION__ /
__CASE__ / __CASENUMBER__ are substituted before the run. The verdict shows as its own layer in
the run result, and --with-apex lets generation draft these checks against the org's real schema.
- Then a qualitative verdict. For dynamic scenarios a final AI pass reads the whole run —
the conversation, the planner traces, the classification and any Apex result — and returns a
pass / warn / fail with a plain-English summary of what worked and what didn't. It is deliberately
not a numeric score, and it can flag a false pass or a real success that tripped an over-strict
assertion. Set
SUITE_ANALYZE=0 to skip it for a fast, purely-deterministic run.
The heavy work (the configured coding CLI and the live-org preview) runs headless from the panel,
streaming output while it runs and collapsing into structured per-scenario results — the failing
checks, what actually happened server-side, the verdict, and the full conversation — when it finishes.
See Choosing a coding CLI below to drive it with something other than Claude.
- Click into a run. Each result carries a View full run button that opens an
Agentforce-app-style detail view: the whole conversation as chat bubbles, and beneath every agent
turn the execution trace the planner actually ran — reasoning (LLM) calls with their prompt and
response, invoked actions with input / output / latency, topic switches with their job and
instructions, and transition events. Any prompt, response or action payload opens full and
untruncated in a Zoom modal. The verdict hero and the verified result layers sit alongside,
and a back link returns to the list. Each turn's trace is correlated to its bubble by the planner's
planId, so what the agent said and what it did line up turn-for-turn.
- Diagnose a failure. A failed run offers Diagnose — an on-demand pass that sends
the whole run (conversation, execution traces, backend classification, failing checks) and the
.agent source to your coding CLI, which returns a root cause and one or more concrete suggested fixes,
each tagged with what to change (an agent instruction, an action, the classification, a grounding
value, or the scenario itself). The diagnosis renders inline in the run and is cached to
scripts/scenarios.<bundle>.diagnosis.json; re-run it anytime.
Choosing a coding CLI (provider)
Every LLM step in the panel — generate, the simulated customer, the qualitative verdict, and
diagnose — runs through a coding CLI on your machine, not a bundled API key. Claude Code
(claude) is the default, but the suite is provider-agnostic: point it at OpenAI Codex, Google
Gemini, or any command you like. Whichever you pick just needs to be installed and on your PATH.
Configure it in Settings → Extensions → Agent Script Preview (or settings.json):
{
// Anthropic Claude Code (default) — nothing to set.
"agentScript.ai.provider": "claude",
// …or OpenAI Codex:
"agentScript.ai.provider": "codex",
"agentScript.ai.model": "gpt-5",
// …or Google Gemini:
"agentScript.ai.provider": "gemini",
// …or ANY other CLI, via the custom provider. {prompt}/{model} are substituted;
// a {model} arg is dropped when no model is set. Use promptMode:"stdin" to pipe the
// prompt to stdin instead of passing it as an argument.
"agentScript.ai.provider": "custom",
"agentScript.ai.bin": "my-llm",
"agentScript.ai.args": ["chat", "--model", "{model}", "--message", "{prompt}"],
"agentScript.ai.model": "some-model",
// Optional: pin a different model per role instead of one for all four.
"agentScript.ai.models": { "generate": "…", "customer": "…", "analyst": "…", "diagnose": "…" },
// Optional: flags appended to every call of any provider (e.g. Codex sandbox flags).
"agentScript.ai.extraArgs": []
}
The scripts read the same choice from the environment (AI_CLI_PROVIDER, AI_CLI_BIN,
AI_CLI_MODEL, …) or from scripts/ai-cli.config.json (copy scripts/ai-cli.config.example.json),
so a bare-terminal or CI run behaves identically to the panel. The legacy CLAUDE_BIN /
SUITE_*_MODEL variables still work. Resolution order: env → settings/config file → legacy env →
claude default. The picker lives in scripts/ai_cli.js; add a new built-in provider there.
Contributing
Building the extension, sideloading a dev .vsix, the internal module layout, and publishing to
the registries are documented in MAINTAINERS.md in the source repository (it is
not shipped in the package).
| |