Skip to content

Config rules don't match commands with global flags (e.g. git -C /path commit) #136

@berk-karaal

Description

@berk-karaal

Description

PR #17 fixed Dippy to show clean descriptions when asking for permission — git -C /some/path commit is displayed to the user as "git commit", not "git -C". This is correct, but it creates a confusing inconsistency:

  1. Dippy asks permission for "git commit" (global flags stripped in the description)
  2. User adds allow git commit to their .dippy config based on what they saw
  3. Next time the same command runs, Dippy still asks for permission — because the config matcher checks against the raw tokens git -C /some/path commit, which doesn't match the pattern git commit

In other words, the description and the config matching use different representations of the same command. The user sees "git commit" but can't write a rule that matches it when global flags are present.

This commonly happens when Claude Code works with worktrees, where git commands are invoked as git -C /path/to/worktree ....

Steps to reproduce

  1. Add allow git commit to your project .dippy file
  2. Trigger a git -C /some/worktree commit -m "message" command (e.g. Claude Code working in a worktree)
  3. Dippy shows the permission prompt as "git commit"
  4. Despite the config rule matching exactly what's displayed, Dippy still asks

Reproduction script

# uv run python repro.py
from dippy.core.config import Config, Rule, match_command, SimpleCommand
from pathlib import Path

cfg = Config(rules=[Rule("allow", "git commit")])
cwd = Path("/tmp")

r1 = match_command(SimpleCommand(words="git commit -m test".split()), cfg, cwd)
r2 = match_command(SimpleCommand(words="git -C /some/path commit -m test".split()), cfg, cwd)

print(f"git commit -m test          -> {'MATCH' if r1 else 'NO MATCH'}")
print(f"git -C /path commit -m test -> {'MATCH' if r2 else 'NO MATCH'}")

Output:

git commit -m test          -> MATCH
git -C /path commit -m test -> NO MATCH

Expected behavior

allow git commit should match git -C /some/path commit -m "test". The config matcher should recognize the same command that the description shows the user.

Root cause

_match_words() in config.py joins raw tokens into "git -C /some/path commit -m test" and tries to match against the pattern "git commit *" via fnmatch. This fails because -C /some/path sits between git and commit.

PR #17 added _find_action() to the git handler to skip global flags for description and classification purposes, but this normalization is not applied during config rule matching.

Affected handlers

Multiple CLI handlers define GLOBAL_FLAGS_WITH_ARG / GLOBAL_FLAGS_NO_ARG constants that would be affected: git, docker, auth0, ip.

Environment

  • Dippy v0.2.7
  • Observed when Claude Code uses worktrees (git -C) or --work-tree

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions