Repository navigation
feat: stateless phase gate and gated tools - #39
Merged
Merged
Conversation
- phase gate: ordered phases with requires; being in a phase needs its gates and every earlier phase's to pass now. The marker only names the phase; nothing is stored or signed. - skillgate phase [<id>]: status, and move only when the target's gates pass. - gatedTools: agent tools (MCP publish/deploy tools) cross the finish line like finishLine commands, in the gate CLI, the opencode plugin and hook installs. - when.tool scopes a gate to gated tools.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
phasegate. Ordered phases, each withrequires(ids of other gates). Being in a phase requires the gates of that phase and every earlier one to pass when checked. The active phase is read from a plain marker file (.skillgate/phaseby default). Nothing is stored or signed, and each required gate runs once per run.skillgate phase [<id>]. Without an id it shows each phase's status. With an id it moves to that phase only if the phase's requirements pass (exit 2 otherwise).gatedTools. Tool-name globs that cross the finish line likefinishLinecommands, for example MCP tools that publish or deploy. Where it is checked:skillgate gatereads the tool name from the Claude Code, Codex and Gemini CLI hook payload, or takes--tool <name>.tool.execute.before.installadds the tools to the hook matcher, anddoctorflags a hook whose matcher does not cover them.when.tool. Scopes a gate to gated tools, alongsidewhen.command.Why
Closes #18. This is the reduced design agreed in that thread: a stateless phase gate evaluated live, plus tool gating. There is no salt and no hash chain. A phase marker can't be forged into passing, because every check re-runs the requirements against the workspace. Thanks @watanabefam for the proposal.
How I verified it
test/phase.test.ts:skillgate phase: moving between phases and the status outputdecideToolandwhen.tool, hook payloads (Claude, Gemini format,--tool)doctorcoverage checkgatedTools: ['Write']and the matcher written byinstall claude-code(Bash|Write), a real Claude Code session'sWritecall was blocked with the unmet gate, and the file was never created.Review notes
gatedToolsdoes not apply there. The docs say so.## Unreleased. Tagv0.11.0after merge.Checklist
test/phase.test.ts)npm run test:coveragepasses locallydocs/spec-reference.mdandschema/done.schema.json## Unreleased