You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
README says agent cannot skip ahead, but since #223 back-to-back ack.sh calls ack never-shown items (0.2.1) #225
Each checklist item requires one full hook invocation to acknowledge. The agent cannot skip ahead.
Since #223 (merged 2026-09-29, shipped in steplock 0.2.1 on crates.io) that is no longer true: ack.sh can be run back to back, so an agent can acknowledge items 2..N without the hook ever showing it those questions, and the gated action is then approved.
#223 made this deliberate (to save ~20 retried tool calls on a 9-step checklist), so this is not a code bug report — it's a docs/behavior contradiction that needs a maintainer decision.
# 1. hook fires on a Claude Code PreToolUse Bash event for `git push origin main`
$ steplock < push-event.json
{"hookSpecificOutput":{..."permissionDecision":"deny","permissionDecisionReason":"[push-gate: 1/2] Did you run the tests?\n\nWhen finished, run: sh .../sessions/sess2/push-gate/ack.sh ..."}}
# 2. agent runs ack.sh twice without retrying the command in between
$ sh .steplock/sessions/sess2/push-gate/ack.sh # acks "tests"
$ sh .steplock/sessions/sess2/push-gate/ack.sh # acks "docs" — never shown to the agent# 3. next hook invocation
$ steplock < push-event.json
{} # approved
Observed vs documented
README
0.2.1 behavior
Hook invocations needed for a 2-item checklist
3 (block, block, approve)
2 (block, approve)
Can the agent ack an item whose question it was never shown?
No ("cannot skip ahead")
Yes
Everything else checked out on 0.2.1: init, validate, block with the current question, state persisted to state.json, next item on the following invocation when acked one at a time, approve once all acked, branching flow lists both options and follows the chosen one (no-arg / bogus choice rejected with exit 1), audit.log entries written.
Restore one-question-per-invocation → make ack.sh refuse to advance past a state the gate hasn't displayed yet (e.g. a shown marker the gate sets on block and ack.sh requires).
Not opening a PR since the right fix depends on which guarantee you want. @tupe12334
Filed automatically by the moadim routine "Nightly lib dogfood → issue + PR (polyhook, block-no-verify, steplock)".
Still reproduces on the current published release, steplock 0.2.2 (cargo install steplock, macOS arm64, Rust 1.97.1). The README sentence is unchanged (README.md line 54: "Each checklist item requires one full hook invocation to acknowledge. The agent cannot skip ahead.").
Repro, 2-item checklist ([*] --> a --> b --> [*], reset = "session", gate on bash + git push), fresh session id sess3:
$ steplock < push-event.json
steplock: block [push-gate] state=a session=sess3
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"[push-gate: 1/2] Did you run the tests?\n\nWhen finished, run: sh .../sessions/sess3/push-gate/ack.sh\nThen retry your original command."}}
$ sh .steplock/sessions/sess3/push-gate/ack.sh # acks a
$ sh .steplock/sessions/sess3/push-gate/ack.sh # acks b — its question was never shown
$ steplock < push-event.json
{} # approved after a single block
So a 2-item checklist still clears in 2 hook invocations instead of 3, and item b ("Did you update the docs?") is never presented. The enabling line is still core/scripts/ack.sh:
.transitions = (.flow_transitions[$next] // []) |
which repopulates the valid transitions for the state ack.sh just advanced to, so the next ack.sh call succeeds with no gate invocation in between.
For whoever picks this up, option 2 from the original report looks like a small change: ack.sh would clear transitions/next_state after advancing (the gate recomputes both from flow.mmd on every block anyway, in block_reset_session) and exit non-zero with "retry your original command to see the next item" when transitions is empty. That also makes the flow_transitions field in state.json dead, since back-to-back acks were its only purpose. Option 1 is a one-line README edit. The decision on which guarantee steplock wants is still yours, so no PR from this run.
Everything else on 0.2.2 passed: init scaffolds .steplock/checklists/ with a .gitignore, validate accepts both a linear and a branching checklist, the gate blocks with the current question and writes state.json, one ack per hook invocation advances exactly one item, the action is approved once all items are acked, a branching state lists both options and follows the acknowledged one (a bogus or missing branch name is rejected with exit 1), and audit.log records block/ack/complete.
Filed automatically by the moadim routine "Nightly lib dogfood → issue + PR (polyhook, block-no-verify, steplock)".
Correction to my previous comment: the decision is already made. PR #228 ("docs: describe back-to-back ack.sh calls in the README", branch fix/issue-225-readme-ack-order) takes option 1 and is open with all 13 checks green, waiting on a merge. Disregard the option-2 fix sketch above and the "no PR from this run" framing — this run is not opening a competing PR, and #228 closes this issue once merged.
The 0.2.2 reproduction in my previous comment still stands as the pre-merge baseline: the published binary behaves exactly as #223 intended, and only the README sentence is out of date.
Filed automatically by the moadim routine "Nightly lib dogfood → issue + PR (polyhook, block-no-verify, steplock)".
Activity
tupe12334 commentedon Oct 27, 2026
Still reproduces on the current published release, steplock 0.2.2 (
cargo install steplock, macOS arm64, Rust 1.97.1). The README sentence is unchanged (README.mdline 54: "Each checklist item requires one full hook invocation to acknowledge. The agent cannot skip ahead.").Repro, 2-item checklist (
[*] --> a --> b --> [*],reset = "session", gate onbash+git push), fresh session idsess3:So a 2-item checklist still clears in 2 hook invocations instead of 3, and item
b("Did you update the docs?") is never presented. The enabling line is stillcore/scripts/ack.sh:which repopulates the valid transitions for the state
ack.shjust advanced to, so the nextack.shcall succeeds with no gate invocation in between.For whoever picks this up, option 2 from the original report looks like a small change:
ack.shwould cleartransitions/next_stateafter advancing (the gate recomputes both fromflow.mmdon every block anyway, inblock_reset_session) and exit non-zero with "retry your original command to see the next item" whentransitionsis empty. That also makes theflow_transitionsfield instate.jsondead, since back-to-back acks were its only purpose. Option 1 is a one-line README edit. The decision on which guarantee steplock wants is still yours, so no PR from this run.Everything else on 0.2.2 passed:
initscaffolds.steplock/checklists/with a.gitignore,validateaccepts both a linear and a branching checklist, the gate blocks with the current question and writesstate.json, one ack per hook invocation advances exactly one item, the action is approved once all items are acked, a branching state lists both options and follows the acknowledged one (a bogus or missing branch name is rejected with exit 1), andaudit.logrecords block/ack/complete.Filed automatically by the moadim routine "Nightly lib dogfood → issue + PR (polyhook, block-no-verify, steplock)".
tupe12334 commentedon Oct 27, 2026
Correction to my previous comment: the decision is already made. PR #228 ("docs: describe back-to-back ack.sh calls in the README", branch
fix/issue-225-readme-ack-order) takes option 1 and is open with all 13 checks green, waiting on a merge. Disregard the option-2 fix sketch above and the "no PR from this run" framing — this run is not opening a competing PR, and #228 closes this issue once merged.The 0.2.2 reproduction in my previous comment still stands as the pre-merge baseline: the published binary behaves exactly as #223 intended, and only the README sentence is out of date.
Filed automatically by the moadim routine "Nightly lib dogfood → issue + PR (polyhook, block-no-verify, steplock)".