Workflow SDK
TypeScript SDK format for building agent workflows
When editing agents via the MCP server, you work with TypeScript source using the @dograh/sdk format. The SDK is a restricted DSL — not full TypeScript.
Allowed Grammar
typescript
// 1. Any import
import { startCall, endCall, transferCall } from "@dograh/sdk/nodes";
import { Workflow } from "@dograh/sdk";
// 2. Const bindings — three valid initialiser forms
const wf = new Workflow({ name: "My Agent" });
const greet = wf.addTyped(startCall({ name: "Greet", prompt: "Hello!" }));
const done = wf.add({ type: "endCall", name: "Done", prompt: "Goodbye." });
// 3. Edge declarations
wf.edge(greet, done, {
label: "wrap up",
condition: "caller has been helped and conversation is naturally ending",
});What is NOT Allowed
| Parameter | Type | Required | Description |
|---|---|---|---|
Functions / arrow functions | — | Optional | Parser is AST-only, not an executor |
Loops (for, while, forEach, map) | — | Optional | Same reason |
Conditionals (if, ternary) | — | Optional | Same reason |
Template literal interpolation (`${x}`) | — | Optional | Same reason |
Spreads / destructuring | — | Optional | Same reason |
export statements | — | Optional | Not a module — file is a single execution unit |
More than one new Workflow(...) | — | Optional | Only one agent per file |
Edge Syntax Rules
typescript
wf.edge(source, target, {
label: "short label", // ≤4 words
condition: "full predicate", // complete natural-language sentence
});sourceandtargetare variable identifiers — not strings, not.id- Both must be declared earlier in the same file
- Both
labelandconditionare required and non-empty - Place all edges after all node declarations
- Group edges by source node
Save / Create Error Codes
| Parameter | Type | Required | Description |
|---|---|---|---|
PARSE_ERROR | — | Optional | TypeScript could not be parsed — syntax error |
VALIDATION_ERROR | — | Optional | Parsed OK but graph is invalid (missing nodes, dangling edges) |
NAME_MISSING | — | Optional | new Workflow({ name: "..." }) is absent or name is empty |
INTERNAL_ERROR | — | Optional | Server error — retry once before surfacing to user |
When
save_workflow or create_workflow returns "saved": false, read the error message and line/column if present, fix at that location, and resubmit the complete source (not a diff).Complete Example
typescript
import { startCall, extractData, transferCall, endCall } from "@dograh/sdk/nodes";
import { Workflow } from "@dograh/sdk";
const wf = new Workflow({ name: "Lead Qualification Agent" });
const greet = wf.addTyped(startCall({
name: "Greet",
prompt: "Hi, this is Alex from Sysevo. Am I speaking with {{customer_name}}?",
}));
const qualify = wf.addTyped(extractData({
name: "Qualify",
prompt: "Great to speak with you! What's the main challenge you're trying to solve?",
fields: [
{ key: "pain_point", description: "The main challenge or pain point the caller described" },
{ key: "budget", description: "Any budget range the caller mentioned" },
],
}));
const book = wf.addTyped(transferCall({
name: "Book Demo",
prompt: "Fantastic — let me connect you with our demo team right now.",
transfer_number: "+14155550199",
}));
const decline = wf.addTyped(endCall({
name: "Not a Fit",
prompt: "Thanks so much for your time. We'll send some useful resources your way.",
}));
wf.edge(greet, qualify, {
label: "confirmed",
condition: "caller confirmed they are the right person and agreed to speak",
});
wf.edge(greet, decline, {
label: "wrong person",
condition: "caller is not the target contact or is not interested in speaking",
});
wf.edge(qualify, book, {
label: "qualified",
condition: "caller described a genuine pain point and showed interest in seeing a demo",
});
wf.edge(qualify, decline, {
label: "not qualified",
condition: "caller does not have a relevant need, budget, or decision-making authority",
});Was this page helpful?
Open Dashboard →