lights on vs lights off
when the foreman holds the keys, when subagents do — and why the builder must never edit its own primitives.
the factory operates in two modes, and the boundary between them is determined by what is being modified, not by what the operator prefers. the default mode — lights off — is the autonomous one: every role is dispatched to a subagent with fresh context, the foreman is the orchestrator, and the operator’s role is to read status reports. the alternate mode — lights on — is the one where the main session performs building directly and only delegates planning and review. the rule that decides which mode applies is simple: when the work modifies factory primitives, switch to lights on; otherwise stay lights off.
the rule exists because of a single class of failure. when the work target is the factory’s own agents, hooks, ADWs, or configuration, the builder subagent is editing the very primitives it uses to run. a mis-step in that edit can break the next dispatch, introduce hook regressions that lock out recovery, or produce a plausible-looking diff that silently breaks the state machine. the failure mode is not theoretical; the velocity-unlock retro documents five bugs that all came from factory-primitive edits, each of which silently broke a downstream phase. when the bug is in the orchestration layer, the orchestration layer cannot debug itself.
the lights-on rule names the boundary explicitly:
switch to lights on when the work target is:
- .claude/agents/ agent body files
- .claude/hooks/ post-agent and pre-bash hooks
- .claude/commands/ slash commands the foreman dispatches
- adws/ autonomous-development workflows
- bin/ the loswf CLI surface
- plugin/ the plugin package
- .loswf/config.yaml the validate[] + parallel + paths contract
- specs/ vision, SRS, retros (when edited)
each of those paths is something a subagent might be asked to modify mid-session. each one, modified incorrectly, can break the dispatch that the next subagent depends on. the foreman has full conversation context, user guardrails, and can detect “this change will break the foreman’s own tooling” in a way a fresh-context subagent cannot. that detection capability is the value of running building from the main session for factory-on-factory work.
the protocol on lights-on switch:
1. foreman announces mode at start of issue:
"lights on for #<num> — i'll handle building; the team handles
planning and review."
2. intake, planner, plan-reviewer, decomposer, reviewer, documenter
dispatch to subagents as normal.
3. at the building phase transition, foreman does NOT dispatch
loswf-builder. instead foreman reads the plan, checks out the
factory branch, edits the files directly, runs validate[], commits,
pushes, opens the PR.
4. after PR is open, factory takes over: reviewer reviews, ship merges.
5. if user flips back to lights off mid-run, dispatch loswf-builder
for any remaining children.
the asymmetry between phases is deliberate. planning and review are not the failure mode — those agents read the diff and emit verdicts; their failures are caught by the next gate. building is the failure mode because building writes files. the foreman keeping building in the main session preserves the dispatchable surface for everything that does not require write access to factory primitives.
the inverse rule is equally important. when the work target is not factory primitives — feature work, bug fixes in the host repo, docs that do not affect the agent prompts — the default is lights off. building in the main session in those cases burns foreman context for no safety gain and reduces parallelism. a parallel.max: 3 setting is meaningless if the foreman is doing the building serially; the dispatched-builder pattern is what produces the iteration-1 unlock-iteration throughput numbers.
the failure modes when the rule is misapplied:
lights off when it should be lights on. the velocity-unlock retro’s five-bug stack is the canonical case. the orchestration bugs lived in .claude/hooks/ and the verdict-matcher logic. each previous session had dispatched a builder agent to modify those files; each builder’s diff looked correct in isolation; each one introduced a bug whose effect was silent failure in the downstream phase. the bugs accumulated until twenty consecutive sweeps shipped zero PRs. the unlock came when the operator switched to lights on, the foreman read the entire stack, and applied five one-line fixes from the main session with full context.
lights on when it should be lights off. if every issue runs in lights-on mode, the foreman becomes the single-threaded build node and the factory’s parallel-builder ceiling collapses to one. iteration 12 ran 22 direct-builds; if all of them had been lights-on, the iteration would have shipped four or five PRs instead of twenty-two. the throughput cost is severe enough that the default has to be lights off, with the exception narrowly scoped to factory-primitive work.
the broader operating principle is that the builder subagent must never edit its own primitives. the builder is a fresh-context agent; it does not know which lines of its own prompt are load-bearing. an edit to .claude/agents/loswf-builder.md made by loswf-builder is an edit a fresh-context agent makes to the very prompt it is reading from. the edit might be correct, but the verification surface is missing — there is no second perspective to catch the case where the edit silently changes the agent’s contract with the post-agent hook. the foreman, holding the main-session context, can verify the edit against the running pipeline; the builder cannot.
a related guardrail surfaces in the velocity-unlock retro: when a parallel builder switches the main worktree branch underneath the foreman, foreman commits can land on the wrong branch. the fix the retro recorded was to give the foreman its own worktree (/tmp/loswf2-foreman), mirroring the builders’ isolation pattern. that fix is the same shape as the lights-on rule: the agent operating on shared mutable state must own its own isolated copy of that state. lights on does this for the foreman’s building; the foreman-worktree fix does it for the foreman’s branch checkouts.
an operational note: the lights-on switch is not a permission grant, it is a mode change. the operator’s standing instruction is that the factory operates autonomously by default. the foreman does not ask “should i switch to lights on?” — it switches when the work target matches the rule, announces the switch, and proceeds. the operator’s input is needed only on the narrow class of decisions the curator agent cannot resolve. mode selection is not one of those decisions.
the meta-lesson is that the lights-on / lights-off boundary is a self-modification safety rule, not a productivity rule. the productivity argument runs the wrong way: lights off is faster on aggregate; lights on is slower per issue. the safety argument is what justifies the slowdown — factory primitives modified by their own dispatcher introduce silent failures that only surface in production sweeps, and those failures cost more wall-time to recover from than the slower mode cost to prevent. the discipline call is to read the work target before selecting the mode, accept the throughput cost on factory-on-factory work, and capture the rule in a check so the next session does not have to re-derive it from another five-bug stack.