Write operations for fixing and managing host-platform permissions - add, remove, consolidate, ensure, apply-fixes, executor migration, wildcard generation.
Resources
1Install
npx skillscat add cuioss/plan-marshall/tools-permission-fix Install via the SkillsCat registry.
Permission Fix Skill
PURPOSE: Write operations for fixing and managing host-platform permissions, including marketplace permission synchronization and executor pattern migration.
COMPLEMENTARY SKILL: Use plan-marshall:tools-permission-doctor for read-only analysis before applying fixes.
Enforcement
Execution mode: Run scripts exactly as documented; use --dry-run before applying changes.
Prohibited actions:
- Do not modify settings without running analysis first (use
tools-permission-doctor) - Do not invent script arguments not listed in the operations table
- Do not skip dry-run verification for bulk operations
- Do not hardcode a platform settings-file path (no
~/.claude/settings.json, no--settings <path>literal). Address the host platform by--scope/--target; the runtime layer resolves the settings location for the active platform.
Constraints:
- Platform-routed permission edits go through
python3 .plan/execute-script.py plan-marshall:platform-runtime:platform_runtime permission {operation} {args}— the runtime owns settings path-resolution + I/O for the active platform. - Executor-pattern and marketplace-wildcard operations that have no runtime op run through
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix {command} {args}, addressed by--scope/--target(never a literal settings path). - Always use
--dry-runfirst to preview changes before applying.
Platform-routed permission edits
The common permission mutations are platform-neutral: they flow through the platform-runtime permission ops, which carry the operation's semantic intent and let the runtime resolve + write the active platform's settings. The runtime is the single home for settings path-resolution and load/save — the body never names a settings file.
| Intent | Platform-routed command |
|---|---|
| Normalize / dedupe / sort + add defaults | platform_runtime permission fix --scope project --operation normalize [--dry-run] |
| Add a permission | platform_runtime permission fix --scope project --operation add --permissions "Bash(docker:*)" [--dry-run] |
| Remove a permission | platform_runtime permission fix --scope project --operation remove --permissions "Bash(docker:*)" [--dry-run] |
| Ensure permissions exist | platform_runtime permission fix --scope global --operation ensure --permissions "Bash(git:*)" "Bash(npm:*)" [--dry-run] |
| Consolidate enumerated entries into wildcards | platform_runtime permission fix --scope project --operation consolidate [--dry-run] |
| Set the full permission list | platform_runtime permission configure --scope project --permissions "Read(**)" "Write(.plan/**)" |
| Ensure marketplace bundle wildcards | platform_runtime permission ensure-wildcards --scope project --marketplace-dir marketplace [--dry-run] |
Ensure project:{skill} step permissions |
platform_runtime permission ensure-steps --marshal .plan/marshal.json --scope project [--dry-run] |
python3 .plan/execute-script.py plan-marshall:platform-runtime:platform_runtime permission fix \
--scope project --operation normalize --dry-runOutput (TOON):
status: success
scope: project
fix_operation: normalize
changes_applied: 3
dry_run: trueOn a platform with no validated permission backend (e.g. OpenCode), each op returns an honest no-op with a reason and alternative — never a fabricated success. The body does not branch on the platform; it routes the intent and the runtime reports what it did.
Executor-pattern and marketplace-wildcard operations
These operations have no platform-runtime permission op; they run on permission_fix directly, addressed by --scope / --target so the script's settings resolver (delegating to the runtime layer) targets the active platform's settings without a literal path.
apply-project-step-permissions — Add Skill() rules for project: steps
Append Skill({skill}) allow rules for every project:{skill} entry in marshal.json (under phase-5-execute.steps and phase-6-finalize.steps) that lacks a matching rule.
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix apply-project-step-permissions \
--marshal .plan/marshal.json \
--settings {settings_path} \
--dry-run{settings_path} is the active platform's settings file; resolve it from the platform layer rather than hardcoding a .claude/ path. Pair with tools-permission-doctor:detect-missing-project-step-permissions — run doctor to detect, then fix to apply.
Output (TOON):
added[1]:
- Skill(finalize-step-plugin-doctor)
summary:
added_count: 1
already_present_count: 1
project_steps_checked: 2
dry_run: true
applied: falseremove-redundant — Remove redundant local-settings permissions
Remove permissions from the project-local settings that are exact duplicates of the global settings or covered by a broader global wildcard, optionally moving marketplace permissions to global.
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix remove-redundant \
--scope both \
--dry-runOptions:
--move-marketplace(default: true): Move marketplace permissions (Skill/SlashCommand) from local to global.--no-move-marketplace: Skip moving marketplace permissions; only remove duplicates and wildcard-covered entries.--dry-run: Preview without writing.
Usage: Run after tools-permission-doctor detect-redundant to clean up permission drift.
generate-wildcards — Generate permission wildcards
Generate Skill and SlashCommand wildcards from marketplace inventory.
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix generate-wildcards \
--marketplace-dir marketplaceensure-executor — Ensure executor permission
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix ensure-executor \
--target global \
--dry-runcleanup-scripts — Remove redundant script permissions
Remove individual script path permissions (redundant with the executor pattern).
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix cleanup-scripts \
--target global \
--remove-broad-python \
--dry-runmigrate-executor — Full migration to executor pattern
Add the executor permission and clean up redundant per-script permissions in one step.
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix migrate-executor \
--target global \
--remove-broad-python \
--dry-runDry run
All write operations support --dry-run to preview changes without modifying any settings.
Integration with Permission Doctor
Recommended workflow:
- Analyze first: Use
tools-permission-doctor detect-redundantordetect-suspicious. - Review findings: Check the analysis output.
- Apply fixes: Route common edits through
platform_runtime permission fix; run executor-pattern operations onpermission_fix. - Verify: Re-run analysis to confirm.
Executor Permission Pattern
The executor pattern uses a single permission for all marketplace scripts:
Bash(python3 .plan/execute-script.py *)
This replaces individual script path permissions because the executor invokes scripts via subprocess (not checked by the host platform's permission system).
Migration Path
- Run
ensure-executorto add the executor permission. - Run
cleanup-scriptsto remove redundant individual permissions. - Or run
migrate-executorto do both in one step.
Error Handling
All operations return TOON with error details:
error: invalid_scope
status: errorCanonical invocations
The canonical argparse surface for permission_fix.py. The plugin-doctor analyzer (_analyze_manage_invocation.py) reads this section as source-of-truth for the manage-invocation-invalid and missing-canonical-block rules. Consuming docs xref this section by name instead of restating the command inline. See `pm-plugin-development:plugin-script-architecture` cross-skill-integration.md § "Script invocation in documentation".
apply-fixes
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix apply-fixes \
(--settings SETTINGS | --scope {global,project}) [--dry-run]--settings and --scope are mutually exclusive.
add
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix add \
--permission PERMISSION [--target {global,project}]remove
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix remove \
--permission PERMISSION [--target {global,project}]ensure
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix ensure \
--permissions PERMISSIONS [--target {global,project}]consolidate
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix consolidate \
(--settings SETTINGS | --scope {global,project}) [--dry-run]--settings and --scope are mutually exclusive.
ensure-wildcards
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix ensure-wildcards \
--settings SETTINGS --marketplace-json MARKETPLACE_JSON [--dry-run]remove-redundant
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix remove-redundant \
(--scope both | --global-settings GLOBAL_SETTINGS) [--local-settings LOCAL_SETTINGS] \
[--move-marketplace] [--no-move-marketplace] [--dry-run]--scope and --global-settings are mutually exclusive; --global-settings requires --local-settings.
apply-project-step-permissions
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix apply-project-step-permissions \
--marshal MARSHAL --settings SETTINGS [--dry-run]generate-wildcards
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix generate-wildcards \
[--marketplace-dir MARKETPLACE_DIR | --input INPUT]--marketplace-dir and --input are mutually exclusive; --input defaults to stdin.
ensure-executor
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix ensure-executor \
[--target {global,project}] [--dry-run]cleanup-scripts
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix cleanup-scripts \
[--target {global,project}] [--remove-broad-python] [--dry-run]migrate-executor
python3 .plan/execute-script.py plan-marshall:tools-permission-fix:permission_fix migrate-executor \
[--target {global,project}] [--remove-broad-python] [--dry-run]