Skip to content

feat(hook): add Muse plugin integration with conservative policy guard - #4931

Open
superbiche wants to merge 1 commit into
rtk-ai:developfrom
superbiche:feat/muse-integration
Open

superbiche wants to merge 1 commit into
rtk-ai:developfrom
superbiche:feat/muse-integration

Conversation

@superbiche

Copy link
Copy Markdown

Summary

Add rtk hook muse, a conservative approval-policy overlay, and
rtk init --agent muse. Installed-plugin detection feeds init --show and the
hook-warning probe; hook check --agent muse <cmd> is the rewrite dry-run.

The hook accepts fixture Bash and native bash tool names, preserves
tool-input metadata and emits only Claude-shaped
hookSpecificOutput with hookEventName and updatedInput. It never emits an
allow decision or installs permission rules.

Measured Muse contract

Muse Code 1.4.14 (1.4.14-R7309.1):

Hook output / exit Fixture result
Bare PreToolUse updatedInput, exit 0 rewrite_selected
Same with permissionDecision: allow Rewrite selected; permission_decision null
Reason without a permission decision Failed; original input retained
decision: block without reason, exit 0 Failed; non-empty reason required
Exit 2 plus stderr reason Blocked

Twenty-three native approval-policy cases established schema-2 strictness,
argv-prefix matching scoped to the exact session workspace root, global
exact-raw matching, deny precedence and per-stage compound-command approval.
Measured under --approval-mode untrusted, contributor mode on, under Muse's
no-named-profile fallback and under an explicit :ask-me profile
(permissions.schema_version: 1). Both settings shapes are accepted.
Other profiles, on-request and session profile overrides are unmeasured and
defer where detectable.

Policy boundary

RTK steps aside whenever any persisted Muse rule names either the original or
the rewritten command; it never arbitrates scope or effect. Prefix matching
checks every plain-word stage at every workspace root. Exact-raw matching checks
raw, trimmed and whitespace-normalised whole commands and all stages on both
sides. Stages that start with a wrapper RTK itself peels (timeout, time,
nice, nohup, stdbuf, env, sudo, command, exec, builtin,
noglob, nocorrect, xargs, shells) defer when rules exist. This avoids relying
on unmeasured exact-raw compound/whitespace semantics or equating hook cwd with
session root. Missing policy and empty rule lists retain normal rewriting.
Malformed policies, unknown fields/rules/profiles and complex syntax with rules
present defer. Carriage returns always defer.

Muse strips XDG variables from hook subprocesses: the hook reads
$HOME/.config/muse. A shell dry-run with a different XDG_CONFIG_HOME treats
policy as unknown and passes through; custom XDG activation remains unqualified.

Installation

rtk init --agent muse generates .rtk/muse-plugin; -g generates a user
bundle. The Agent Plugins 1.0.0 bundle contains .claude-plugin/plugin.json and
hooks/hooks.json (PreToolUse/Bash, rtk hook muse, timeout 10 seconds).
Init prints muse plugins install <bundle> --scope project|user and
muse plugins approve rtk. RTK never invokes Muse or grants plugin trust.
--show, --dry-run, and --uninstall cover the generated bundle; uninstall
prints the separate Muse removal command and leaves installed copies alone.
Detection reports enabled installation, not capability approval. No awareness
rules are shipped because their consumption remains unqualified.

Test plan

  • Table-driven tests reproduce all 23 oracle rows, including malformed files,
    plus review regressions for workspace roots, exact raw whitespace/compounds,
    both settings shapes, XDG mismatch and shell boundaries.
  • Binary protocol and bundle lifecycle tests; isolated-home lowercase bash hook
    fixtures: no policy, same-root and unrelated-root prefix rules, whole-compound
    exact-raw rule, CR input, and no-policy compound.
  • Native proof: nine headless muse exec runs against Muse Code 1.4.14 with the generated bundle
    installed and approved in disposable homes. Six implementer runs established the native hook
    envelope (tool_name: "bash", cwd = session workspace root) and exposed a renderer that only
    accepted the fixture's Bash; that is fixed and the captured envelope is replayed in a regression
    test. Three runs on the round-2 binary (628c27c8; the renderer is unchanged since and
    the comparator change only adds pass-throughs): with no policy the hook rewrites and Muse executes the
    rewritten command; with a persisted [git, status] allow (prefix) or a global exact-raw allow for
    git status, the hook passes through and Muse runs the original under its own allow:policy
    decision, so the user's verdict is preserved.
  • Root/proxy formatting, clippy, offline locked test suite, patch application
    and unchanged Cargo.lock checked locally.
  • Two environment-dependent tests were skipped locally; please rely on CI.

Closes #4917


@superbiche · user · drafted with GPT 6.1 Sol and Claude Fable 5.1, reviewed before posting; the voice and decisions are mine.

@rtk-wshm-sync-bot

Copy link
Copy Markdown

wshm · Automated triage by AI

📊 Automated PR Analysis

✨ Type feature
🟡 Risk medium

Summary

Adds a new agent integration for Muse Code, including rtk hook muse (a conservative PreToolUse hook that rewrites commands only when no persisted Muse approval-policy rule touches them) and rtk init --agent muse for generating/installing an Agent Plugins bundle. Behavior was empirically measured against Muse Code 1.4.14 across native and fixture test suites, with conservative defer-to-Muse fallbacks for unmeasured policy shapes.

Review Checklist

  • Tests present
  • Breaking change
  • Docs updated

Linked issues: #4917


Analyzed automatically by wshm · This is an automated analysis, not a human review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Muse Code integration: rtk hook muse (Claude-shape I/O, verdict parity against Muse approval policy) + rtk init --agent muse

1 participant