Quickstart: put an agent under the Ladder
examples/quickstart-agent.mjs is a complete agent in 40 lines with no dependencies (Node 18 or later). It:
- tells the Ladder what its queue looks like (
queue.defined, sent every run; the same id is stored once); - for each item, sends
item.created, then asksPOST /v1/routebefore acting; - obeys the answer:
act_aloneโ acts and logs roleact;proposeโ logs aproposalfor a person to confirm;human_onlyโ does not act, logs its answer asshadow.
LADDER_URL=https://ladder.ankitu.com LADDER_KEY=<your workspace key> node examples/quickstart-agent.mjs
{"queue":"invoices","items":10,"act_alone":0,"propose":0,"human_only":10,"audit":0}
A new step starts in Shadow, so every answer is human_only. As people do the same items (their step.done events with role work) and disagreements are settled, the step earns Assist and then Auto, and the same script starts proposing and then acting, without a code change.
Options: LADDER_QUEUE (default invoices), ITEMS (default 10), LADDER_AT (stamp the run at a given time, for replays and tests).
Proven end to end
npx tsx scripts/test-live.ts runs it against the deployed API in a fresh queue: first run all human_only; re-run stores nothing twice; people's work for 420 items arrives; the next run's first route call closes the week, the step moves to Assist, and the agent is told to propose and does; the lane.changed webhook lands in the test inbox with a valid signature; CSV, ServiceNow and Salesforce imports map; the three MCP tools answer. Latest results are in RESULTS.md.
What the person's side sends
| When | Event |
|---|---|
| A person does an item in Shadow | step.done with actor.kind: "operator", role work |
| A person confirms or edits a proposal in Assist | step.done, role confirm (their final output) |
| Someone settles a disagreement | settlement with agent_right, operator_right or both_wrong and a one-line reason |
| A person checks an audited Auto item | audit.result, pass or fail with a severity |
| A named approver allows a money-moving step into Auto | signoff (answering the signoff.requested webhook) |