Skip to content

Latest commit

 

History

History
96 lines (75 loc) · 3.96 KB

File metadata and controls

96 lines (75 loc) · 3.96 KB

git-guards — Architecture

Always-on protection through four hooks that intercept operations across every workflow. Unlike guidance-based plugins that load on demand, these hooks run unconditionally for every user prompt and every tool invocation.

Hook Interception Map

flowchart TD
    UP["User Prompt Submitted"]
    PT_BASH["PreToolUse: Bash"]
    PT_EDIT["PreToolUse: Edit / Write / NotebookEdit"]

    UP -->|"matcher: *"| WR["worktree-reminder.sh\n(UserPromptSubmit)"]
    PT_BASH -->|"matcher: Bash"| PG["git-permission-guard.py\n(PreToolUse)"]
    PT_BASH -->|"matcher: Bash"| TG["commit-trailer-guard.py\n(PreToolUse)"]
    PT_EDIT -->|"matcher: Edit, Write, NotebookEdit"| MBG["main-branch-guard.py\n(PreToolUse)"]

    WR --> WR_CHECK{"On main\nbranch?"}
    WR_CHECK -->|No| WR_ALLOW["{} / no reminder\n(allowed)"]
    WR_CHECK -->|Yes| WR_WARN["systemMessage:\nrequire a worktree"]

    PG --> PG_CLASSIFY{"Classify\ncommand"}
    PG_CLASSIFY -->|"force-push to main\nhook bypass --no-verify\nmerge on main\nhard reset\nbranch -D on main\ngh pr comment"| PG_BLOCK["permissionDecision: deny\n(BLOCKED)"]
    PG_CLASSIFY -->|"merge, rebase\nforce-push to branch\nworktree remove"| PG_CONFIRM["permissionDecision: ask\n(CONFIRM)"]
    PG_CLASSIFY -->|"Everything else"| PG_ALLOW["exit 0 / no decision\n(allowed)"]

    MBG --> MBG_CHECK{"On main\nbranch?"}
    MBG_CHECK -->|No / local-only file| MBG_ALLOW["exit 0 / no decision\n(allowed)"]
    MBG_CHECK -->|Yes & not exempt| MBG_BLOCK["permissionDecision: deny\n(force worktree workflow)"]

    classDef hook fill:#fff3e0,stroke:#e65100,color:#bf360c
    classDef block fill:#ffebee,stroke:#c62828,color:#b71c1c
    classDef allow fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20

    class WR,PG,MBG hook
    class PG_BLOCK,PG_CONFIRM,MBG_BLOCK block
    class WR_ALLOW,PG_ALLOW,MBG_ALLOW allow
Loading

Always-On Nature

These hooks wrap around every other plugin operation. No workflow bypasses them.

flowchart LR
    subgraph OUTER["git-guards — always active"]
        direction TB
        WR2["worktree-reminder.sh\nfires on every prompt"]
        PG2["git-permission-guard.py\nfires on every Bash call"]
        TG2["commit-trailer-guard.py\nfires on every Bash call"]
        MBG2["main-branch-guard.py\nfires on every file edit"]

        subgraph INNER["All other plugin operations"]
            direction LR
            SHIP["/ship"]
            FINALIZE["/finalize-pr"]
            REBASE["/rebase-pr"]
            MANUAL["Manual edits"]
            OTHER["Any workflow..."]
        end

        WR2 -.->|wraps| INNER
        PG2 -.->|wraps| INNER
        MBG2 -.->|wraps| INNER
    end

    classDef hook fill:#fff3e0,stroke:#e65100,color:#bf360c
    class WR2,PG2,MBG2 hook
Loading

Fail-Open Philosophy

Every hook follows a strict fail-open contract: if the hook errors or crashes, it exits 0 with no decision and the operation proceeds. Blocking is signalled by emitting a JSON permissionDecision (deny or ask) on stdout while still exiting 0; the worktree reminder never blocks — it injects a systemMessage on stdout to require a worktree.

Outcome Mechanism Effect
Intentional allow exit 0, no decision Operation proceeds
Intentional block exit 0 with permissionDecision: deny Operation denied
User confirmation exit 0 with permissionDecision: ask User prompted
Hook crash / error exit 0 (no JSON) Fail-open — proceeds anyway

Relationship to git-standards

git-guards and git-standards are complementary: one enforces, one advises.

Dimension git-guards git-standards
Activation Automatic — every operation On demand — loaded when relevant
Mechanism permissionDecision JSON on stdout Skill text injected into context
Effect Hard block, confirmation prompt, or worktree reminder Soft guidance and conventions
Scope Runtime tool calls Planning and workflow decisions