Skip to content

v0.1.2

Released on 2026-03-06. Full changelog

A new interactive setup wizard that configures runok and registers it as a Claude Code PreToolUse hook in one step:

Terminal window
$ runok init

The wizard handles:

  • Scope selection (global or project-level configuration)
  • Detection and migration of existing Claude Code Bash permission patterns from settings.json into runok.yml rules
  • Hook registration in .claude/settings.json
  • Generation of runok.yml with migrated rules

If you already have Bash permission patterns configured in Claude Code’s settings.json, runok init detects them and offers to convert them into equivalent runok rules automatically.

See runok init for details.

Command substitutions ($()) nested inside quoted strings were not being evaluated, allowing dangerous sub-commands to bypass deny rules entirely:

runok.yml
rules:
- deny: 'rm -rf *'
Terminal window
# Before: the inner $(rm -rf /) was not evaluated
curl -u "user:$(rm -rf /)" https://example.com # → allow (wrong)
# After: sub-commands inside quotes are extracted and evaluated
curl -u "user:$(rm -rf /)" https://example.com # → deny (correct)

Compound commands containing command substitutions combined with redirections (2>&1) or pipes caused a stack overflow crash. Commands like the following now evaluate correctly without crashing:

Terminal window
echo $(cat file.txt 2>&1) | grep pattern

The double-dash -- was incorrectly classified as a flag, causing it to participate in order-independent flag matching. This broke positional semantics for commands that use -- to separate options from arguments:

Terminal window
# Before: -- was treated as a flag, breaking positional matching
git checkout HEAD~1 -- README.md # → unexpected evaluation
# After: -- is a positional literal, preserving standard Unix semantics
git checkout HEAD~1 -- README.md # → correct evaluation

In patterns like find * -exec <cmd> \;, the -exec flag alternation was consuming the <cmd> placeholder as its value, preventing the wrapper evaluation from working:

runok.yml
definitions:
wrappers:
- 'find * -exec <cmd> \;'
Terminal window
# Before: <cmd> was consumed as -exec's value
find . -exec rm {} \; # → wrapper evaluation broken
# After: <cmd> correctly captures the inner command
find . -exec rm {} \; # → inner "rm {}" is evaluated separately