Intent Locks
What you'll learn
- What an intent lock is and why every task gets one.
- The split between the user's request and the runtime's accepted interpretation.
- When a runner should pause for a scope update vs. continue.
- How locks integrate with case files, handoffs, and the work graph.
Intent lock
The runtime's accepted interpretation of a task — explicit, durable, and separate from the original request. The lock declares what's in scope, what's out of scope, how much autonomy the runner has, and what conditions should stop the run.
Why bother?
Long-running agent work drifts. Mid-run, a new finding makes a nearby change tempting. A tool returns output that implies "I should also fix this related thing." Partial progress nudges the runner toward "while I'm here, let me clean up..." Each step in isolation looks reasonable; the cumulative effect is scope creep that nobody approved.
Intent locks make that drift visible and reviewable. The lock is what the runtime committed to before the work began — every later decision can be checked against it.
What a lock records
The lock persists as a craik.intent_lock record and is referenced from
the matching case file and every subsequent handoff. Handoff contracts
include an intent-lock field so future handoff writers can preserve the
same boundary across runs.
When a runner should pause
The requested work no longer matches the accepted interpretation. Mid-run discovery: the user really meant something narrower or wider. Stop and ask for a lock update.
A required action is listed as out of scope. The runner identifies a step it would have to take to finish, but
excludedforbids it. Stop and ask.The task would cross a stop condition. A stop condition fired (reviewer required, budget exceeded, contradiction surfaced). Halt and write a handoff that names what stopped the run.
The task requires new autonomy not listed in the lock. The runner needs a capability the lock doesn't grant (e.g., wants to run a shell command but
allowed_autonomydoesn't include shell). Request the grant or stop.
How locks compose with the rest of the runtime
Intent locks aren't a separate system — they're a typed object that other parts of the runtime cite:
Case files
Every case file references its intent lock id, so the runner sees the boundary alongside the evidence and verification plan.
Handoffs
Handoffs reference the same lock id. The next agent picks up with the original boundary, not without it.
Policy
The policy envelope and the intent lock together describe what's permitted. The lock declares scope; the envelope declares capability.
Work graph
Locks are queryable nodes — useful when auditing how a task's interpretation evolved across multiple runs.
Use intent locks day-to-day
craik task create --out-of-scope "ADR edits" --out-of-scope "schema migrations"The task-creation command produces the matching intent lock from the flags you pass.
craik intent show task_review_docsPrint the lock by task id or intent-lock id. Useful for review before authorizing a run.
craik case build task_review_docsEnsures the task has an intent lock and includes its id in the resulting case file.
Why locks are separate from the request
It's tempting to skip locks and just "do what the user asked." That conflates two distinct things:
- What the user said — preserved as
original_request. - What the runtime committed to do about it — the lock.
When those two diverge — and they do, often — having both addressable makes review tractable. You can ask: "Did the runtime's accepted interpretation match what the user actually wanted?" and have a machine-readable answer.