Skip to main content

Concept map — start here

A harness is everything around the model that shapes what an agent sees and what it may do. The model is the same in every lab of this workshop. The harness is what changes, and it is what Ruth, Larkspur's head of Model Risk, will sign or refuse to sign.

This page is the map. Read it once before Lab 2 and come back when a lab asks "which layer does this belong in?"

The harness as layers​

Seven layers, each owned by one lab. Each card says what question the layer answers and how strong its answer is.

Here are the same layers around one tool call. Look at the colors: the orange layers are enforced by config or code and apply whatever Droid decided, the dark one is a person deciding, and the unstyled ones inform the decision without guaranteeing anything. The docs don't say whether PreToolUse hooks or permission rules are checked first, so the diagram doesn't order them.

Labs 0, 1, 9 and 10 don't add a layer. Lab 0 measures, Lab 1 teaches you to read a session, Lab 9 runs the whole harness headless in CI, and Lab 10 runs it at scale as a Mission. Each depends on the layers being there.

The distinction that matters​

The label at the bottom of each card is the most important idea in the workshop. There are four kinds of layer, and they are not equally strong.

KindWhat it meansLayersWhat it cannot do
Shapes behaviorChanges what Droid knows or how it approaches a task. Droid weighs it against everything else it knows.AGENTS.md, skills and slash commandsGuarantee anything. It is an input to a decision.
Adds a checkpointPuts a decision in front of someone before it takes effect: a person approving a plan, or a fresh reviewer reading a diff.Spec mode, custom droidsHold when nobody is there to look. Headless, a checkpoint with no reviewer is just a delay.
Enforced by configDroid's own configuration decides, before the model gets a say.Autonomy levels, permission rulesSee beyond what it matches. Permission rules match command prefixes. They don't see file edits made with the Edit tool.
Enforced by codeYour code runs at a fixed point in the session, every time, and its exit code decides.Hooks, and facts from MCP checked by a hookEnforce anything you didn't write a check for. A hook guards what you name.

The workshop's argument in one line: instructions are requests, controls are code. Lab 2's AGENTS.md is clear, and on one run in three Droid still weighs it against "make the test pass" and edits the rounding. That isn't a defect in Droid. It is what an instruction is. Lab 5's hook makes the same edit impossible, whatever Droid decides.

The weaker layers still matter. They move most of the scoreboard, because a Droid that knows the invariants rarely hits a control. The strong layers matter for the run where it does. You need both: context so the controls rarely fire, and controls for when they must.

I will read every file you show me. Tell me which of them are asking and which of them are enforcing, and do not let me confuse the two.

Ruth Achterberg Head of Model Risk Management

A note on MCP's label. An MCP server gives Droid facts from your own systems, such as the status of a change ticket. On its own, a fact is still context. Lab 8 makes it a control by having a hook check the ticket's status field in code before a migration can be written. The fact comes over MCP. The enforcement is the hook.

Every harness file​

Every file the workshop creates, where it lives, and what it controls.

FileLocationScopeWhat it controlsLab
AGENTS.mdRepo root; nested directories such as src/money/AGENTS.mdProject, or one directory treeWhat every session knows first: commands, layout, invariants, the never-list, when to stop, how to verify2
sessionDefaultSettings.interactionMode, specModeModel.factory/settings.jsonProject, or user in ~/.factory/settings.jsonWhether sessions start in Spec mode, and which model plans3
Saved specs.factory/docs/ by default when Save spec as Markdown is on (the settings page lists specSaveDir as ~/.factory/specs; check your version)Project or userA reviewable record of each approved plan3
sessionDefaultSettings.autonomyLevel.factory/settings.jsonProject, or userWhat runs without asking. Larkspur sets "low"4
permissionRules.factory/settings.jsonOrg, folder, project, user, plus settings.local.json overridesallow, ask or block for shell commands4
.factory/hooks.jsonProject; also ~/.factory/hooks.json for a userProject or userWhich of your scripts run on which events and tools5
.factory/hooks/*.mjsProjectProjectThe checks themselves: protected paths, shell writes, float money, the outcome at Stop5
.factory/skills/<name>/SKILL.mdProject; also folder-specific and ~/.factory/skills/Project, folder or personalA procedure Droid loads when the task matches its description6
.factory/commands/*.md and executable scriptsProject; also ~/.factory/commands/Project or personalSlash commands you invoke by name6
.factory/droids/<name>.mdProject; also ~/.factory/droids/Project or personalA subagent with its own system prompt, model and enforced toolset7
.factory/mcp.jsonProject root; also ~/.factory/mcp.json for a userProject or userWhich MCP servers Droid can call, and how to start them8
.github/workflows/droid-scoreboard.ymlRepoCIThe scoreboard and Droid review on every pull request9
.factory/skills/review-guidelines/SKILL.mdProjectProjectCustom guidelines for Droid's automated code review9
.factory/protected-changes.logProject (written by the Stop hook)ProjectA local record of protected-path changes for the reviewer. It is git-ignored, so CI checks the diff against the base instead5, 9
mission.mdRepoOne MissionThe goal, milestones and validation for a multi-feature run10

Two settings the workshop mentions but doesn't depend on: sandbox (operating-system isolation for commands, an extension in Lab 5 and part of the regulated guardrails guide) and enableDroidShield (secret scanning on commits and pushes Droid makes, on by default, covered in Lab 4).

How the layers interact​

Each layer has its own rules about what wins when two sources disagree. Here is what Factory's docs actually say. Where they say nothing, this page says nothing.

Permission rules​

  • Which definition of a rule ID wins: Org, then Runtime, then Folder, then Project, then User. Within one folder, settings.local.json comes before settings.json. A disabled definition still claims its ID.
  • Which decision wins when several rules match: block beats ask, and ask beats allow.
  • An empty rules array doesn't erase inherited rules. A rule that fails its own tests is skipped. It does not turn into block-all.
  • Project and folder rules require workspace trust.

Autonomy and rules together​

  • Autonomy controls automatic approval, not which tools exist.
  • An allow rule skips the approval prompt. Hooks and the sandbox still apply.
  • An ask rule needs approval even at High autonomy. In droid exec nobody can approve it, so the run fails. --auto high doesn't clear it.
  • A block rule has no approval path, even when permission prompts are skipped with --skip-permissions-unsafe.

Hooks​

  • An allow rule does not skip a hook. The permission rules page says other controls, including hooks and the sandbox, still apply.
  • A PreToolUse hook that exits 2 blocks the tool call. Any other non-zero exit is a non-blocking error, and the tool runs.
  • Droid snapshots hooks at session start and warns when the file changes underneath it. Change one, start a new session (or review the change in /hooks).
  • Hooks from user, project, plugin and org-managed sources add up rather than override each other. Org-managed hooks always load unless hooks are disabled globally, and allowManagedHooksOnly makes Droid ignore user and project hooks.
  • The docs don't state directly that project hooks run in droid exec. Lab 5 has you check it before you trust a headless number.

AGENTS.md​

The docs describe a mental model, not a strict merge order: the current request takes priority over standing instructions, nested files refine the root file for their directory tree, and project files override personal defaults. Droid searches from the working directory up to the git root, and also checks .factory/, .agents/ and .agent/ at each level.

Skills, commands and droids​

  • Skills: folder-specific and project skills, then project plugin skills, then personal, then user plugin skills, then built-in.
  • Slash commands: the workspace .factory/commands wins over ~/.factory/commands. If a custom command and a skill share a name, the command keeps the slash command.
  • Custom droids: a project droid wins over a personal droid with the same name.

Settings and the sandbox​

  • Local overrides (settings.local.json) merge on top of settings.json at the same level.
  • Sandbox settings resolve org, then project, then user.
  • Missions inherit MCP, skills, hooks, custom droids and AGENTS.md: the docs say hooks fire during mission execution and project droids are available to workers. So the AGENTS.md, hooks, skills, custom droids and MCP server you build in Labs 2 to 8 carry into Lab 10. Permission rules (Lab 4) aren't on that list. They live in the project settings.json, which should load for any session in the repository, but the docs don't say Missions inherit them, so check with droid rules check before you rely on one.

Where each layer lives in .factory/​

This is the finished harness. Everything marked new is in harness-reference/ in the companion repo, including review-guidelines/SKILL.md from Lab 9. protected-changes.log is generated, not committed.

larkspur-payments (finished harness)
AGENTS.mdnew# Lab 2 · shapes behavior
mission.mdnew# Lab 10
.factory/
settings.jsonnew# Lab 4 autonomy + permissionRules (Lab 3's spec settings are optional)
hooks.jsonnew# Lab 5 · enforced by code
hooks/
lib/
protected.mjsnew# shared by every hook
protect-paths.mjsnew# PreToolUse · file tools
protect-shell.mjsnew# PreToolUse · Execute
protected-diff.mjsnew# Stop · checks the outcome
money-lint.mjsnew# PostToolUse · feedback
protect-paths.lab8.mjsnew# Lab 8 · allows migrations with an approved CHG
skills/
money-change/SKILL.mdnew# Lab 6
flaky-test-triage/SKILL.mdnew# Lab 6
review-guidelines/SKILL.md# Lab 9 · you write it
commands/
fee-change.mdnew# Lab 6 · Markdown command
ship-check.shnew# Lab 6 · executable command
droids/
money-reviewer.mdnew# Lab 7 · tools: read-only
mcp.jsonnew# Lab 8 · change-control server
protected-changes.log# written by the Stop hook, git-ignored
.github/
workflows/
droid-scoreboard.ymlnew# Lab 9
src/
money/protected
migrations/protected
legacy/frozen

Where to go next​