Quick Start
Build your first DIAL state machine with specialists. This guide focuses on the code—for the concepts behind what you're building, see Concepts.
What We'll Build
A trivially simple machine that asks "Should we complete this task?" and transitions from pending to done:
Step 1: Define the Machine
Save this as examples/simple-machine.json:
{
"machineName": "simple-task",
"initialState": "pending",
"goalState": "done",
"states": {
"pending": {
"prompt": "Should we complete this task?",
"transitions": { "complete": "done" }
},
"done": {}
}
}
initialState: where the session starts (pending)goalState: the rest state where the session is headed (done); no action needed when reachedprompt: the question specialists answer when the session is in that statetransitions: the available answers and what state each leads to
Only one transition (complete) leads to done, so the machine always resolves in one cycle.
Or define the same thing in TypeScript:
import type { MachineDefinition } from "dialai";
const machine: MachineDefinition = {
machineName: "simple-task",
initialState: "pending",
goalState: "done",
states: {
pending: {
prompt: "Should we complete this task?",
transitions: { complete: "done" },
},
done: {},
},
};
Step 2: Run It
The quickest way to run a machine is with runSession, which registers a built-in proposer (firstAvailable) and a built-in arbiter (firstProposal) to drive the machine to its goal state:
import { runSession } from "dialai";
const session = await runSession(machine);
console.log(session.currentState); // "done"
That's it. One cycle, done.
Step 3: Walk the Decision Cycle Manually
Let's register specialists, submit proposals, and run arbitration step by step.
import {
createSession,
getSession,
registerProposer,
registerArbiter,
submitProposal,
submitArbitration,
} from "dialai";
// Create a session - starts in "pending"
const session = await createSession(machine);
console.log(session.currentState); // "pending"
console.log(session.currentRoundId); // "e5f6g7h8-..."
// Register two proposers and an arbiter
await registerProposer({
specialistId: "ai-specialist",
machineName: "simple-task",
strategyFnName: "firstAvailable",
});
await registerProposer({
specialistId: "contrarian-ai",
machineName: "simple-task",
strategyFnName: "firstAvailable",
});
await registerArbiter({
specialistId: "consensus-arbiter",
machineName: "simple-task",
strategyFnName: "alignmentMargin",
});
// Two AI specialists each submit a proposal
const proposalA = await submitProposal({
sessionId: session.sessionId,
specialistId: "ai-specialist",
roundId: session.currentRoundId,
transitionName: "complete",
reasoning: "The task is ready to complete",
metaJson: { source: "automated-check" },
});
const proposalB = await submitProposal({
sessionId: session.sessionId,
specialistId: "contrarian-ai",
roundId: session.currentRoundId,
transitionName: "complete",
reasoning: "I agree, let's complete it",
});
// Submit arbitration - checks for consensus (both propose "complete")
const result = await submitArbitration({ sessionId: session.sessionId, roundId: session.currentRoundId });
console.log(result.executed); // true (both proposers agreed)
console.log(result.toState); // "done"
// Fetch the updated session (the original variable is stale after transition)
const updated = await getSession(session.sessionId);
console.log(updated.currentState); // "done"
console.log(updated.history); // [{ transitionName: "complete", reasoning: "...", ... }]
Human primacy means that when AI cannot reach consensus, a human can force a decision by calling submitArbitration with an explicit transition. A human proposal always wins.
Step 4: Use the CLI
Run a machine definition from the command line:
npx dialai examples/simple-machine.json
Output:
Machine: simple-task
Initial state: pending
Goal state: done
Final state: done
Session ID: a1b2c3d4-...
What's Happening Under the Hood
- Session created in
initialState(pending) with a freshcurrentRoundId - Proposers solicited: each returns a proposed transition (
complete) - Arbitration submitted: guards checked, alignment margin consensus evaluated
- Transition executed:
currentStatemoves todone,currentRoundIdregenerated - Cycle repeats until
currentState === goalState(already there, done)
Next Steps
- State Machines: Design more complex workflows
- Registering Specialists: Configure specialists with strategies
- Implementing Strategies: Customize strategy functions
- Concepts: Deep dive into DIAL's architecture