Setup
This page gets you from nothing to a working Droid session in the Larkspur repository. It takes about fifteen minutes. Do it before Lab 0, and before the workshop if you are attending one: installs over conference Wi-Fi are nobody's favorite start.
Prerequisites
| You need | Why | Check |
|---|---|---|
| Node 20 or newer | The companion repo is TypeScript on Node. Its package.json asks for 20.11 or later. | node --version |
| git | You clone the repo, and later labs read git diff and git status to check what changed. | git --version |
| A Factory account | Droid asks you to sign in through the browser when you first start it. | Sign in at app.factory.ai |
| A terminal you like | Everything in the labs happens in one. Your editor's integrated terminal works too: Factory's docs say Droid runs in any editor with one. |
On Linux, Factory's quickstart asks you to install xdg-utils first. On Debian or Ubuntu:
sudo apt-get install xdg-utils
Install Droid
Pick one. They install the same CLI.
curl -fsSL https://app.factory.ai/cli | sh
brew install --cask droid
npm install -g droid
irm https://app.factory.ai/cli/windows | iex
Open a new terminal afterward so your shell picks up the new command, then check it:
droid --version
A room full of people on different Droid versions is a room full of slightly different transcripts. Pick one version and have everyone use it. With npm, npm install -g droid@0.174.0 pins it, and npm builds ship with auto-update turned off. With the standalone installer, droid update --version 0.174.0 pins it, and export FACTORY_DROID_AUTO_UPDATE_ENABLED=false stops it updating mid-workshop. droid update --check tells you whether a newer version exists without installing it. (0.174.0 is the example from Factory's docs. Use whatever version you piloted with.)
Sign in
There is no droid login command. You sign in by starting Droid: if it isn't signed in yet, it prompts you to sign in through your browser. Inside a session, /login signs you in and /logout signs you out.
droid
When the session opens, type /quit to leave. You'll come back in Lab 1.
Headless runs use an API key. Factory's droid exec docs have you create one at app.factory.ai/settings/api-keys and export it, so do that before you run the scoreboard, and in CI:
export FACTORY_API_KEY=fk-...
Treat it like any other credential. Don't put it in the repository, a shell history you share, or a screenshot for the workshop channel.
Clone the companion repo
git clone https://github.com/mrlynn/larkspur-payments cd larkspur-payments npm ci
Clone it; don't download a zip. Lab 0's /readiness-report needs a git repository with an origin remote, and a clone gives you one.
AGENTS.md# not yet: you write it in Lab 2src/money/protected# Money type, arithmetic, roundingfees/# fee schedule and calculationtransfers/# ACH transfers, daily limitsledger/# double-entry postingsaudit/# audit log, PII maskingapi/# HTTP routesmigrations/protected# SQL, needs a CHG ticketlegacy/frozen# vendored file parsertest/scoreboard/# the eight tasks and their checkstools/change-control-mcp/# the MCP server from Lab 8harness-reference/# the finished state of every lab
harness-reference/ holds the finished harness from every lab. Don't copy from it before you've tried the lab. The point of most labs is the step where your first version breaks.
Run the tests
npm test
You should see every test pass, except possibly one: test/fees/overdraft.test.ts, the pro-rated overdraft fee.
That test is flaky by date. It works out the expected fee from today's real date, and on some days of the month the pro-rated fee lands on exactly half a cent. On those days the test's expected value and the code disagree by one cent. So it may fail today and pass tomorrow.
Don't fix it. It is task T2 on the scoreboard, and it is the test that caused the March incident. If it passes for you today, that's fine too: the scoreboard's check for T2 doesn't depend on the date. Note which it did, because Lab 0 asks.
Check the rest
droid --version npm run typecheck npm run scoreboard -- --dry-run
--dry-run lists the eight tasks and their checks without calling Droid, so it costs nothing. If all three commands work, you are ready for Lab 0.
Workspace trust
Workspace trust matters for the permission rules you write in Lab 4. Factory's docs say it plainly: project and folder permission rules require workspace trust, and untrusted project and folder rules are excluded. The reason is sound. A repository you just cloned shouldn't be able to set its own command policy.
For this workshop, trust larkspur-payments: you are about to write its configuration yourself. If the permission rules you add in Lab 4 seem to have no effect, check trust first. The docs don't describe how trust is granted or revoked, so follow what your version of Droid shows you.
Cost
The playgrounds cost nothing. Droid sessions use real models, so they cost real tokens, and the scoreboard is where most of that goes.
A full scoreboard run is 8 tasks × 3 runs = 24 headless sessions. The labs ask you to run it at the end of every lab. Here is how to spend less:
| Flag | What it does | When to use it |
|---|---|---|
--runs 1 | One run per task instead of three | Labs where the scoreboard should hold (1, 3, 4, 7, 9, 10), or any time your budget is tight |
--task T2 | Only that task | When a lab is about one task, like Lab 5 and T2 |
--dry-run | Shows the tasks and checks without calling Droid | Setup, and checking the harness is wired up |
--json | Machine-readable results | CI in Lab 9 |
Flags combine: npm run scoreboard -- --task T2 --runs 1 is a single session.
One run per task tells you less. Agents are stochastic, and the difference between 2/3 and 3/3 on T2 is the difference between "usually safe" and "safe". Three runs is the default for a reason. Use --runs 1 to check your work and three runs when you want a number you would show someone.
Inside an interactive session, /cost shows usage statistics, and /stats shows usage over a period you choose. If your company pays for Factory, find out how usage is tracked and who sees it before the workshop, not after.
cloudSessionSync defaults to true, which mirrors your sessions to Factory's web app. includeCoAuthoredByDroid defaults to true, which adds a co-author trailer to commits Droid makes. Both are settings keys, so you can change them in ~/.factory/settings.json. Neither is a problem for a fictional bank, and both are worth knowing about before you point Droid at a real one.
What you edit and what you run
You'll switch between three places all day. Keep them straight and most confusion goes away.
| Where | What you do there | Examples |
|---|---|---|
| Your editor | Write the harness | AGENTS.md, .factory/settings.json, .factory/hooks.json, hook scripts, skills, droids |
| Your shell | Run things yourself | npm test, npm run scoreboard, droid rules check, droid exec, git diff |
Inside droid | Talk to Droid and drive the session | Prompts, /hooks, /mcp, /cost, Shift+Tab for Spec mode, Ctrl+L for autonomy |
The labs mark which is which. A <Terminal> block titled "in droid" is something you type inside a session. Anything else runs in your shell.
When you change a hook, start a new droid session. Droid snapshots hooks at startup and warns when they're modified outside the session, and the docs say to review changes in /hooks before relying on them.
Troubleshooting
droid: command not found after installing. Open a new terminal. If you used npm, check that npm's global bin directory is on your PATH.
The browser doesn't open to sign in (Linux). Check that xdg-utils is installed (see Prerequisites).
You can't open a browser at all (a remote box, a container). Use an API key: create one at app.factory.ai/settings/api-keys and export FACTORY_API_KEY=.... That covers droid exec and the scoreboard. The CLI reference documents the same variable under Authentication.
npm ci fails. Check node --version. The repo needs Node 20.11 or later.
/readiness-report complains about the repository. It needs a git repository with an origin remote. Run git remote -v. If you downloaded a zip instead of cloning, clone it.
Shift+Enter sends the prompt instead of adding a newline. Run /terminal-setup once inside droid.
A permission rule you wrote does nothing. Three usual causes. The folder isn't trusted. The rule failed its own tests, and a rule whose examples fail is skipped rather than enforced. Or the command doesn't match the prefix exactly: prefixes match exact, case-sensitive tokens in order. Run droid rules check and read its output: it reports invalid rules and failed examples. Lab 4 covers all three.
A hook you wrote does nothing. Start a new session, since Droid snapshots hooks at startup. Check /hooks lists it on the Project tab. Check the matcher's spelling and case: Edit, not edit. And check the script exits 2, not 1, to block. Lab 5 covers this.
The overdraft test fails. That's expected on some days. See Run the tests.
Scoreboard runs are slow. Each run is a real Droid session. Use --task and --runs 1 while you iterate, and start a full run while you read the next section of the lab.
Still stuck? Ask in the workshop discussions, and include droid --version, your OS and the command you ran.