muse-hooks-valid¶
.muse/hooks.json must use Muse's events, matcher groups and handler fields
| Severity | error (disabled) |
| Autofix | - |
| Since | v0.20.0 |
| Repo Types | muse |
| Category | Muse Code |
Activation¶
This rule is opt-in while Muse loader compatibility and public repository
coverage are still limited. Enable it with --rule muse-hooks-valid or:
Hook discovery and the shared hooks-dangerous and hooks-prohibited rules
keep their existing activation settings independently of this shape rule.
Why¶
.muse/hooks.json lets you automate shell commands during Muse Code agent
lifecycle events — such as right before a tool runs, when a session starts,
or when the agent finishes its work. Because hooks are committed to the
repository, they provide a reliable, shared way to automate setup and
checks for everyone on the team.
During headless runs, Muse Code executes hooks quietly without printing
console warnings if a configuration option is unsupported. When a hook
doesn't trigger, it can be hard to tell whether the event simply hasn't fired
yet or was skipped due to an unrecognized field. This rule inspects
.muse/hooks.json against Muse's supported events, matcher groups, and handler
options so that your automations run smoothly and reliably.
The commands themselves are also scanned for risky patterns by
hooks-dangerous and can be inventoried against an
explicit allowlist with hooks-prohibited.
Severity¶
Severity reflects the impact on your hook configuration:
Errors — prevent the entire file, a matcher group, or a specific handler from running:
- The whole file is skipped: invalid JSON, non-finite numbers (
NaN,Infinity,-Infinity), an event value that is not an array, a matcher group that is not an object, a non-stringmatcher, a group missing itshooksarray, a handler that is not an object, or a known handler field of the wrong type (such astimeout: "10"orasync: 1). - A matcher group is skipped: keys other than
matcherandhooks(such as a leftoverdescriptionfrom a Claude Code hooks file). Sibling groups and other events continue to load. - A handler is skipped: a missing
type, a type other thancommand, an emptycommand, an unrecognized handler key, or options unsupported by Muse (if,once: true,asyncRewake: true). Other handlers in the same group continue to run.
Warnings — the file loads, but specific hooks or matchers may not run as intended:
- Unrecognized event names. Event names are case-sensitive (e.g.
SessionStartvssessionStart). - The
Setupevent, which Muse parses from Claude Code configurations but does not execute. - An empty
hooksobject, event array, or matcher-grouphooksarray (valid JSON, but configures no actions). - A regex
matcherthat does not compile under Rust's regex engine. Muse uses Rust's regex syntax, which supports Unicode property classes (\p{...}), character-class set operations (&&,--,~~), named capture groups ((?<name>...)), and\z, but does not support lookarounds, backreferences, or conditional/atomic groups. Matchers longer than 1,000 characters are skipped to keep checks fast. - A handler defining
commandWindowswithout a fallbackcommandfor Linux or macOS environments.
Info — advisory notices:
- Events present in Muse's binary but omitted from official documentation
(
StopFailure,PostToolBatch). Be sure to test these in your environment before relying on them.
When an unknown key appears across multiple groups or handlers — common when migrating a file from another tool — skillsaw groups them into a single concise finding.
Examples¶
Bad — an unexpected key prevents the first matcher group from running, and an unsupported handler option is dropped:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"enabled": true,
"hooks": [
{ "type": "command", "command": "./scripts/audit.sh", "args": ["--json"] }
]
}
],
"sessionStart": [
{ "hooks": [{ "type": "command", "command": "./scripts/bootstrap.sh" }] }
]
}
}
Good — matcher groups using Muse's supported fields and PascalCase event names:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{ "type": "command", "command": "./scripts/bootstrap.sh", "timeout": 30 }
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "./scripts/audit.sh --json",
"statusMessage": "Auditing command",
"async": true
}
]
}
]
}
}
How to fix¶
- Give each matcher group only
hooksand, optionally,matcher. Notes or descriptions can be kept in companion documentation or inside invoked hook scripts. - Give every handler
"type": "command"and a non-emptycommandstring. Include a POSIXcommandalongside anycommandWindowsso your hooks work across all platforms. - When migrating from Claude Code: combine
argsinto thecommandstring, set environment variables within the script, and handle conditional logic directly in the command script. - Specify
timeoutas a non-negative integer representing seconds (30, rather than30.0or"30"). - Use Muse's standard PascalCase event names (e.g.,
SessionStart,PreToolUse).
If Muse introduces newer events, fields, or group keys, you can allow them
directly in your .skillsaw.yaml configuration without disabling the rule:
rules:
muse-hooks-valid:
enabled: true
# Additional event names dispatched by newer Muse releases:
extra-events:
- PreSomethingNew
# Additional handler fields supported by newer Muse releases:
extra-handler-fields:
- retries
# Additional matcher-group keys:
extra-group-keys:
- priority
Matcher check limits¶
Matcher validation is conservative: it translates Rust inline flags and
braced hexadecimal escapes only for syntax checking. For example,
Bash|(?i)Write, (?-u:\w+), (?U).*, \x{42}ash, \u{42}ash and
\U{42}ash are accepted.
Unclosed groups/classes and unsupported look-around/backreferences are still
reported in the checked subset. Extended-mode (x) patterns are left
unresolved because comments change tokenization. No finding is a complete
Rust regex validation guarantee.
Notification and PostToolUseFailure are now documented Muse events and
do not receive the undocumented-event advisory. Handler and group checks
still apply to both events.
Configuration¶
| Parameter | Description | Default |
|---|---|---|
extra-events |
Additional hook event names to accept, for events newer than this skillsaw release | [] |
extra-handler-fields |
Additional handler field names to accept, for fields newer than this skillsaw release | [] |
extra-group-keys |
Additional matcher-group key names to accept, for keys newer than this skillsaw release | [] |
Run skillsaw explain muse-hooks-valid to see this documentation and the rule's effective configuration in your terminal.