Support project-level config overlay with restrict-only semantics #8

Open
opened 2026-04-20 16:31:47 +00:00 by jbr870 · 0 comments
Owner

Summary

The config is purely global (~/.config/claude-permit/config.toml). All rules apply to all projects. In practice, different projects have different safety profiles — a personal toy project vs. a production codebase, a Rust project vs. a Node project. The example config already shows this tension: file_path = '^/home/jochem/' is inherently project-specific.

What's needed

Support a project-level config (e.g., .claude-permit/config.toml in the repo root) that layers on top of global config.

Critical constraint: restrict-only semantics. A project config must only be able to add restrictions, never weaken global rules. Otherwise a malicious repo could ship a config that allows dangerous operations.

Merge semantics:

  • Project deny rules — always apply (project can add restrictions)
  • Project allow rules — only apply if the global config doesn't deny the same pattern (project can never override global denies)
  • Global deny rules — immutable from the project level

Possible approaches

  1. Full config overlay — Load both configs, merge rule lists with the restrict-only constraint. Most flexible but complex merge logic.

  2. $CLAUDE_PROJECT_DIR substitution — Simpler intermediate step: auto-substitute $CLAUDE_PROJECT_DIR in regex patterns at config load time, so global rules can be project-aware without a second config file. Claude Code already provides this env var in the hook context.

  3. Project config = deny-only — Simplest secure option: project configs can only add [[deny]] rules, never [[allow]]. Eliminates the merge complexity entirely.

Design considerations

  • Claude Code itself layers three levels: global settings.json, project .claude/settings.json, project-local .claude/settings.local.json. Our design should feel consistent with this.
  • Don't build until we have real usage patterns from live sessions. The audit log data will inform which rules people actually need per-project.
  • The $CLAUDE_PROJECT_DIR substitution approach could ship first as a low-risk stepping stone.

Context

Severity: Feature gap (future)
Affected: Config loading, rule evaluation
Discovered: 2026-02-27

## Summary The config is purely global (`~/.config/claude-permit/config.toml`). All rules apply to all projects. In practice, different projects have different safety profiles — a personal toy project vs. a production codebase, a Rust project vs. a Node project. The example config already shows this tension: `file_path = '^/home/jochem/'` is inherently project-specific. ## What's needed Support a project-level config (e.g., `.claude-permit/config.toml` in the repo root) that layers on top of global config. **Critical constraint: restrict-only semantics.** A project config must only be able to *add* restrictions, never *weaken* global rules. Otherwise a malicious repo could ship a config that allows dangerous operations. Merge semantics: - **Project deny rules** — always apply (project can add restrictions) - **Project allow rules** — only apply if the global config doesn't deny the same pattern (project can never override global denies) - **Global deny rules** — immutable from the project level ## Possible approaches 1. **Full config overlay** — Load both configs, merge rule lists with the restrict-only constraint. Most flexible but complex merge logic. 2. **`$CLAUDE_PROJECT_DIR` substitution** — Simpler intermediate step: auto-substitute `$CLAUDE_PROJECT_DIR` in regex patterns at config load time, so global rules can be project-aware without a second config file. Claude Code already provides this env var in the hook context. 3. **Project config = deny-only** — Simplest secure option: project configs can only add `[[deny]]` rules, never `[[allow]]`. Eliminates the merge complexity entirely. ## Design considerations - Claude Code itself layers three levels: global `settings.json`, project `.claude/settings.json`, project-local `.claude/settings.local.json`. Our design should feel consistent with this. - Don't build until we have real usage patterns from live sessions. The audit log data will inform which rules people actually need per-project. - The `$CLAUDE_PROJECT_DIR` substitution approach could ship first as a low-risk stepping stone. ## Context Severity: Feature gap (future) Affected: Config loading, rule evaluation Discovered: 2026-02-27
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
jbr870/claude-permit#8
No description provided.