
╭─── Claude Code v2.1.59 ──────────────────────────────────────────────────────╮
│                                                    │ Tips for getting        │
│                Welcome back arhtas!                │ started                 │
│                                                    │ Run /init to create a … │
│                       ▐▛███▜▌                      │ ─────────────────────── │
│                      ▝▜█████▛▘                     │ Recent activity         │
│                        ▘▘ ▝▝                       │ No recent activity      │
│                                                    │                         │
│     Opus 4.6 · Claude API ·                        │                         │
│     arthas.zihan.zhou@gmail.com's Organization     │                         │
│               ~/LocalYihan/ccprofile               │                         │
╰──────────────────────────────────────────────────────────────────────────────╯

╭──────────────────────────────────────────────────────────────────────────────╮
│ Plan to implement                                                            │
│                                                                              │
│ ccprofile — Claude Code Permission Profile Manager                           │
│                                                                              │
│ Context                                                                      │
│                                                                              │
│ Claude Code has no native profile/preset system for permissions. Each        │
│ project needs manual allow-listing in .claude/settings.local.json, and       │
│ switching between different permission sets (e.g., Notion workspace vs       │
│ Python dev vs read-only) requires manual JSON editing. With 44+ projects,    │
│ this creates friction every time a new session or project is started.        │
│                                                                              │
│ Goal: Build a ccprofile CLI tool that stores named permission profiles and   │
│ applies them to user-level or project-level settings with a single command.  │
│                                                                              │
│ Design                                                                       │
│                                                                              │
│ - Scope: Only manages the permissions block (allow/deny/ask). Other settings │
│  (model, statusLine, etc.) are preserved untouched.                          │
│ - Storage: Profiles stored as JSON in ~/.claude/profiles/<name>.json         │
│ - Stack: Python + typer + pydantic + rich, packaged via uv tool install      │
│ - Location: /Users/yihan/LocalYihan/ccprofile/                               │
│                                                                              │
│ CLI Commands                                                                 │
│                                                                              │
│ ┌─────────────────────────────────────────┬───────────────────────────────┐  │
│ │                 Command                 │          Description          │  │
│ ├─────────────────────────────────────────┼───────────────────────────────┤  │
│ │ ccprofile list                          │ List all profiles (built-in + │  │
│ │                                         │  custom)                      │  │
│ ├─────────────────────────────────────────┼───────────────────────────────┤  │
│ │ ccprofile show <name>                   │ Display a profile's           │  │
│ │                                         │ permissions                   │  │
│ ├─────────────────────────────────────────┼───────────────────────────────┤  │
│ │ ccprofile save <name> [--from           │ Snapshot current permissions  │  │
│ │ user|project]                           │ as a profile                  │  │
│ ├─────────────────────────────────────────┼───────────────────────────────┤  │
│ │ ccprofile use <name> [--scope           │ Apply a profile               │  │
│ │ user|project] [--merge] [--dry-run]     │                               │  │
│ ├─────────────────────────────────────────┼───────────────────────────────┤  │
│ │ ccprofile create <name>                 │                               │  │
│ │ [--from-template NAME] [--allow         │ Create a new profile          │  │
│ │ PERM...]                                │                               │  │
│ ├─────────────────────────────────────────┼───────────────────────────────┤  │
│ │ ccprofile delete <name>                 │ Delete a profile              │  │
│ ├─────────────────────────────────────────┼───────────────────────────────┤  │
│ │ ccprofile diff <name1> <name2>          │ Compare two profiles          │  │
│ │                                         │ (supports @user/@project)     │  │
│ ├─────────────────────────────────────────┼───────────────────────────────┤  │
│ │ ccprofile current [--scope              │ Show active permissions       │  │
│ │ user|project|both]                      │                               │  │
│ └─────────────────────────────────────────┴───────────────────────────────┘  │
│                                                                              │
│ Profile Schema                                                               │
│                                                                              │
│ {                                                                            │
│   "_meta": {                                                                 │
│     "name": "notion-workspace",                                              │
│     "description": "All Notion MCP tools + web search",                      │
│     "created": "2026-02-27T14:30:00Z",                                       │
│     "builtin": false,                                                        │
│     "version": 1                                                             │
│   },                                                                         │
│   "permissions": {                                                           │
│     "allow": ["WebSearch", "mcp__notion__notion-fetch", ...],                │
│     "deny": [],                                                              │
│     "ask": []                                                                │
│   }                                                                          │
│ }                                                                            │
│                                                                              │
│ Safety                                                                       │
│                                                                              │
│ - use creates a timestamped backup in ~/.claude/backups/ before writing      │
│ - Only permissions key is replaced; all other settings keys preserved        │
│ - --dry-run previews changes without writing                                 │
│ - --merge unions permissions instead of replacing                            │
│                                                                              │
│ Built-in Profiles (6)                                                        │
│                                                                              │
│ ┌──────────────────┬─────────────────────────────────────────────┐           │
│ │     Profile      │               Key permissions               │           │
│ ├──────────────────┼─────────────────────────────────────────────┤           │
│ │ readonly         │ ls, grep, git log/status/diff, WebSearch    │           │
│ ├──────────────────┼─────────────────────────────────────────────┤           │
│ │ git-basics       │ git add/commit/push/branch/checkout         │           │
│ ├──────────────────┼─────────────────────────────────────────────┤           │
│ │ python-dev       │ uv run/add/sync, git basics, WebSearch      │           │
│ ├──────────────────┼─────────────────────────────────────────────┤           │
│ │ node-dev         │ npm/npx/pnpm, git basics, WebSearch         │           │
│ ├──────────────────┼─────────────────────────────────────────────┤           │
│ │ notion-workspace │ All Notion MCP tools, WebSearch, WebFetch   │           │
│ ├──────────────────┼─────────────────────────────────────────────┤           │
│ │ full-dev         │ Permissive: git, uv, npm, file ops, web, gh │           │
│ └──────────────────┴─────────────────────────────────────────────┘           │
│                                                                              │
│ Project Structure                                                            │
│                                                                              │
│ ccprofile/                                                                   │
│   pyproject.toml          # uv package config, [project.scripts] entry point │
│   src/ccprofile/                                                             │
│     __init__.py                                                              │
│     cli.py                # Typer commands (thin wiring layer)               │
│     core.py               # Read/write/merge/backup settings                 │
│ (safety-critical)                                                            │
│     models.py             # Pydantic: Profile, Permissions, ProfileMeta      │
│     profiles.py           # Profile CRUD on ~/.claude/profiles/              │
│     diff.py               # Diff computation between two permission sets     │
│     builtins.py           # Built-in profile definitions                     │
│     constants.py          # Path constants                                   │
│   tests/                                                                     │
│     test_core.py                                                             │
│     test_profiles.py                                                         │
│                                                                              │
│ Implementation Order                                                         │
│                                                                              │
│ 1. constants.py — path definitions                                           │
│ 2. models.py — Pydantic schemas                                              │
│ 3. builtins.py — 6 starter profiles                                          │
│ 4. core.py — read/write/merge/backup logic                                   │
│ 5. profiles.py — profile storage layer                                       │
│ 6. diff.py — permission set comparison                                       │
│ 7. cli.py — typer commands                                                   │
│ 8. pyproject.toml — packaging                                                │
│ 9. Tests for core.py and profiles.py                                         │
│                                                                              │
│ Installation & Verification                                                  │
│                                                                              │
│ cd ~/LocalYihan/ccprofile                                                    │
│ uv init --package --name ccprofile                                           │
│ uv add "typer[all]" pydantic rich                                            │
│ # ... implement ...                                                          │
│ uv tool install --editable .                                                 │
│                                                                              │
│ # Verify                                                                     │
│ ccprofile list                          # shows 6 built-in profiles          │
│ ccprofile save my-notion --from user    # snapshots current user permissions │
│ ccprofile use python-dev --scope project --dry-run  # preview                │
│ ccprofile use python-dev --scope project            # apply                  │
│ ccprofile diff @user @project           # compare active settings            │
│ ccprofile current --scope both          # show effective permissions         │
╰──────────────────────────────────────────────────────────────────────────────╯

⏺ I'll implement the ccprofile CLI tool. Let me start by setting up the project
  and implementing all files in order.

⏺ Read 2 files (ctrl+o to expand)

⏺ Good, I can see the settings structure. Let me initialize the project and
  implement all files.

⏺ Bash(mkdir -p /Users/yihan/LocalYihan/ccprofile && cd
      /Users/yihan/LocalYihan/ccprofile && uv init --package --name ccprofile)
  ⎿  Initialized project `ccprofile`
  ⎿  Shell cwd was reset to /Users/yihan/LocalYihan/nora/nora-notion

⏺ Bash(cd /Users/yihan/LocalYihan/ccprofile && uv add "typer[all]" pydantic
      rich)
  ⎿  Using CPython 3.12.10
     Creating virtual environment at: .venv
     Resolved 15 packages in 1.40s
     … +22 lines (ctrl+o to expand)
  ⎿  Shell cwd was reset to /Users/yihan/LocalYihan/nora/nora-notion

⏺ Read 1 file (ctrl+o to expand)

⏺ Now let me implement all the files. I'll create them in parallel where
  possible.

⏺ Write(pyproject.toml)
  ⎿  Added 6 lines, removed 3 lines
      1  [project]
      2  name = "ccprofile"
      3  version = "0.1.0"
      4 -description = "Add your description here"                       
      4 +description = "Claude Code permission profile manager"          
      5  readme = "README.md"
      6  authors = [
      7      { name = "FIKS", email = "zh3036@gmail.com" }
     ...
      10  dependencies = [
      11      "pydantic>=2.12.5",
      12      "rich>=14.3.3",
      13 -    "typer[all]>=0.24.1",                                      
      13 +    "typer>=0.24.1",                                           
      14  ]
      15  
      16  [project.scripts]
      17 -ccprofile = "ccprofile:main"                                   
      17 +ccprofile = "ccprofile.cli:app"                                
      18  
      19  [build-system]
      20  requires = ["hatchling"]
      21  build-backend = "hatchling.build"
      22 +                                                               
      23 +[tool.hatch.build.targets.wheel]                               
      24 +packages = ["src/ccprofile"]                                   

⏺ Write(src/ccprofile/__init__.py)
  ⎿  Error writing file

⏺ Write(src/ccprofile/constants.py)
  ⎿  Wrote 10 lines to src/ccprofile/constants.py
       1 """Path constants for ccprofile."""
       2 
       3 from pathlib import Path
       4 
       5 CLAUDE_DIR = Path.home() / ".claude"
       6 PROFILES_DIR = CLAUDE_DIR / "profiles"
       7 BACKUPS_DIR = CLAUDE_DIR / "backups"
       8 
       9 USER_SETTINGS = CLAUDE_DIR / "settings.json"
      10 PROJECT_SETTINGS = Path(".claude") / "settings.local.json"

⏺ Write(src/ccprofile/models.py)
  ⎿  Wrote 26 lines to src/ccprofile/models.py
       1 """Pydantic models for ccprofile."""
       2 
       3 from datetime import datetime, timezone
       4 
       5 from pydantic import BaseModel, Field
       6 
       7 
       8 class Permissions(BaseModel):
       9     allow: list[str] = Field(default_factory=list)
      10     deny: list[str] = Field(default_factory=list)
     … +16 lines (ctrl+o to expand)

⏺ Read 1 file (ctrl+o to expand)

⏺ Write(src/ccprofile/__init__.py)
  ⎿  Added 1 line, removed 2 lines
      1 -def main() -> None:                                             
      2 -    print("Hello from ccprofile!")                              
      1 +"""ccprofile — Claude Code Permission Profile Manager."""       

⏺ Now let me create the remaining implementation files.

⏺ Write(src/ccprofile/builtins.py)
  ⎿  Wrote 168 lines to src/ccprofile/builtins.py
       1 """Built-in profile definitions."""
       2 
       3 from .models import Permissions, Profile, ProfileMeta
       4 
       5 _BUILTINS: dict[str, tuple[str, Permissions]] = {
       6     "readonly": (
       7         "Read-only: ls, grep, git log/status/diff, web search",
       8         Permissions(
       9             allow=[
      10                 "Bash(ls:*)",
     … +158 lines (ctrl+o to expand)

⏺ Write(src/ccprofile/core.py)
  ⎿  Wrote 69 lines to src/ccprofile/core.py
      1 """Core logic: read/write/merge/backup Claude Code settings."""
      2 
      3 import json
      4 import shutil
      5 from datetime import datetime, timezone
      6 from pathlib import Path
      7 
      8 from .constants import BACKUPS_DIR, PROJECT_SETTINGS, USER_SETTIN
        GS
      9 from .models import Permissions
     … +59 lines (ctrl+o to expand)

⏺ Write(src/ccprofile/profiles.py)
  ⎿  Wrote 60 lines to src/ccprofile/profiles.py
       1 """Profile storage layer: CRUD operations on ~/.claude/profiles/
         ."""
       2 
       3 import json
       4 
       5 from .builtins import get_builtin, list_builtins
       6 from .constants import PROFILES_DIR
       7 from .models import Profile
       8 
       9 
      10 def _profile_path(name: str):
     … +50 lines (ctrl+o to expand)

⏺ Write(src/ccprofile/diff.py)
  ⎿  Wrote 26 lines to src/ccprofile/diff.py
       1 """Diff computation between two permission sets."""
       2 
       3 from dataclasses import dataclass
       4 
       5 from .models import Permissions
       6 
       7 
       8 @dataclass
       9 class PermissionDiff:
      10     only_in_first: list[str]
     … +16 lines (ctrl+o to expand)

⏺ Now the CLI — the main file:

⏺ Write(src/ccprofile/cli.py)
  ⎿  Wrote 242 lines to src/ccprofile/cli.py
       1 """Typer CLI commands for ccprofile."""
       2 
       3 from typing import Annotated, Optional
       4 
       5 import typer
       6 from rich.console import Console
       7 from rich.table import Table
       8 
       9 from .core import (
      10     backup_settings,
     … +232 lines (ctrl+o to expand)

⏺ Now let me create the tests and verify everything works:

⏺ Bash(mkdir -p /Users/yihan/LocalYihan/ccprofile/tests)
  ⎿  Done

⏺ Write(tests/__init__.py)
  ⎿  Wrote 1 lines to tests/__init__.py
      1 (No content)

⏺ Write(tests/test_core.py)
  ⎿  Wrote 82 lines to tests/test_core.py
       1 """Tests for core settings read/write/merge/backup."""
       2 
       3 import json
       4 from pathlib import Path
       5 
       6 from ccprofile.core import (
       7     backup_settings,
       8     merge_permissions,
       9     read_permissions,
      10     read_settings,
     … +72 lines (ctrl+o to expand)

⏺ Write(tests/test_profiles.py)
  ⎿  Wrote 51 lines to tests/test_profiles.py
       1 """Tests for profile storage layer."""
       2 
       3 import json
       4 
       5 from ccprofile.models import Permissions, Profile, ProfileMeta
       6 from ccprofile.profiles import delete_profile, list_profiles, lo
         ad_profile, save_profile
       7 
       8 
       9 def test_load_builtin():
      10     profile = load_profile("readonly")
     … +41 lines (ctrl+o to expand)

⏺ Now let me add pytest and run the tests:

⏺ Bash(cd /Users/yihan/LocalYihan/ccprofile && uv add --dev pytest && uv run
      pytest tests/ -v 2>&1)
  ⎿  Error: Exit code 2
     Resolved 19 packages in 465ms
        Building ccprofile @ file:///Users/yihan/LocalYihan/ccprofile
           Built ccprofile @ file:///Users/yihan/LocalYihan/ccprofile
     Prepared 5 packages in 668ms
     Uninstalled 1 package in 0.91ms
     Installed 5 packages in 3ms
      ~ ccprofile==0.1.0 (from file:///Users/yihan/LocalYihan/ccprofile)
      + iniconfig==2.3.0
      + packaging==26.0
     … +84 lines (ctrl+o to see all)

⏺ Pydantic doesn't allow leading underscores in field names. I need to use meta
  as the field name and serialize it as _meta via alias.

⏺ Read 1 file (ctrl+o to expand)

⏺ Write(src/ccprofile/models.py)
  ⎿  Added 1 line, removed 1 line
      20  
      21  
      22  class Profile(BaseModel):
      23 -    _meta: ProfileMeta = Field(alias="_meta")                  
      23 +    meta: ProfileMeta = Field(alias="_meta")                   
      24      permissions: Permissions
      25  
      26      model_config = {"populate_by_name": True}

⏺ Now I need to update all references from ._meta to .meta across the codebase:

⏺ Searched for 1 pattern (ctrl+o to expand)

⏺ Update(src/ccprofile/profiles.py)
  ⎿  Added 1 line, removed 1 line
      23  def save_profile(profile: Profile) -> None:
      24      """Save a profile to disk."""
      25      PROFILES_DIR.mkdir(parents=True, exist_ok=True)
      26 -    path = _profile_path(profile.model_fields_set and profile._
         -meta.name or "unnamed")                                        
      26 +    path = _profile_path(profile.meta.name)                    
      27      # Use model_dump with by_alias to get _meta key
      28      data = profile.model_dump(by_alias=True, mode="json")
      29      path.write_text(json.dumps(data, indent=2) + "\n")

⏺ Update(src/ccprofile/cli.py)
  ⎿  Added 2 lines, removed 2 lines
      64  
      65      for name, (profile, is_builtin) in sorted(profiles.items())
          :
      66          tag = "[dim]built-in[/dim]" if is_builtin else "custom"
      67 -        desc = profile._meta.description                       
      67 +        desc = profile.meta.description                        
      68          count = str(len(profile.permissions.allow))
      69          table.add_row(name, tag, desc, count)
      70  
     ...
      78      if profile is None:
      79          console.print(f"[red]Profile '{name}' not found.[/red]"
          )
      80          raise typer.Exit(1)
      81 -    console.print(f"[bold]{profile._meta.name}[/bold] — {profil
         -e._meta.description}")                                         
      81 +    console.print(f"[bold]{profile.meta.name}[/bold] — {profile
         +.meta.description}")                                           
      82      _print_permissions(profile.permissions)
      83  
      84  

⏺ Also update test references:

⏺ Searched for 1 pattern (ctrl+o to expand)

⏺ Update(tests/test_profiles.py)
  ⎿  Added 1 line, removed 1 line
       9  def test_load_builtin():
      10      profile = load_profile("readonly")
      11      assert profile is not None
      12 -    assert profile._meta.builtin is True                       
      12 +    assert profile.meta.builtin is True                        
      13      assert "Bash(ls:*)" in profile.permissions.allow
      14  
      15  

⏺ Now run the tests again:

⏺ Bash(cd /Users/yihan/LocalYihan/ccprofile && uv run pytest tests/ -v 2>&1)
  ⎿  ============================= test session starts ====================
     ==========
     platform darwin -- Python 3.12.10, pytest-9.0.2, pluggy-1.6.0 -- /User
     … +19 lines (ctrl+o to expand)

⏺ All 11 tests pass. Now let me install it as a tool and verify the CLI:

⏺ Bash(uv tool install --editable . --force 2>&1)
  ⎿  Resolved 14 packages in 323ms
     Installed 14 packages in 15ms
      + annotated-doc==0.0.4
     … +14 lines (ctrl+o to expand)

⏺ Bash(ccprofile list 2>&1)
  ⎿                                      Profiles

     ┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
     … +18 lines (ctrl+o to expand)

⏺ Bash(ccprofile show python-dev 2>&1)
  ⎿  python-dev — Python dev: uv, git basics, web search
                 Permissions
     ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┓
     … +20 lines (ctrl+o to expand)

⏺ Bash(ccprofile current --scope user 2>&1)
  ⎿                    User permissions
     ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
     ┃ Category ┃ Rules                                  ┃
     … +18 lines (ctrl+o to expand)

⏺ Let me verify a few more commands:

⏺ Bash(ccprofile save my-notion --from user -d "My Notion workspace permissions"
       2>&1)
  ⎿  Saved profile 'my-notion' from user settings (17 allow rules).

⏺ Bash(ccprofile diff @user notion-workspace 2>&1)
  ⎿                                       allow

     ┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━
     … +19 lines (ctrl+o to expand)

⏺ Bash(ccprofile use python-dev --scope project --dry-run 2>&1)
  ⎿  Dry run — would apply to project settings:
           Would write to project
     ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┓
     … +21 lines (ctrl+o to expand)

⏺ All commands work. Let me also test create and clean up the saved test
  profile:

⏺ Bash(ccprofile create my-custom --from-template python-dev --allow
      "Bash(docker:*)" -d "Python + Docker" 2>&1)
  ⎿  Created profile 'my-custom' (20 allow rules).

⏺ Bash(ccprofile list 2>&1)
  ⎿                                      Profiles

     ┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
     … +18 lines (ctrl+o to expand)

⏺ Let me clean up the test profiles and create the index.md:

⏺ Bash(ccprofile delete my-custom 2>&1 && ccprofile delete my-notion 2>&1)
  ⎿  Error: Exit code 1
     ╭───────────────────── Traceback (most recent call last) 
     ──────────────────────╮
     │ /Users/yihan/LocalYihan/ccprofile/src/ccprofile/cli.py:184 in delete     
         │
     │                                                                          
         │
     │   181 def delete(name: str):                                             
         │
     │   182 │   """Delete a custom profile."""                                 
         │
     │   183 │   builtin = load_profile(name)                                   
         │
     │ ❱ 184 │   if builtin and builtin._meta.builtin:                          
         │
     │   185 │   │   console.print(f"[red]Cannot delete built-in profile 
     '{name}'.[ │
     │   186 │   │   raise typer.Exit(1)                                        
         │
     … +38 lines (ctrl+o to see all)

⏺ The installed tool is stale — it still has _meta reference in the delete
  function. The editable install should pick up changes, but let me check and
  reinstall:

⏺ Read 1 file (ctrl+o to expand)

⏺ The replace_all missed this one because of the different context. Let me fix
  it:

⏺ Update(src/ccprofile/cli.py)
  ⎿  Added 1 line, removed 1 line
      181  def delete(name: str):
      182      """Delete a custom profile."""
      183      builtin = load_profile(name)
      184 -    if builtin and builtin._meta.builtin:                     
      184 +    if builtin and builtin.meta.builtin:                      
      185          console.print(f"[red]Cannot delete built-in profile '{
           name}'.[/red]")
      186          raise typer.Exit(1)
      187  

⏺ Bash(uv tool install --editable /Users/yihan/LocalYihan/ccprofile --force
      2>&1)
  ⎿  Resolved 14 packages in 765ms
     Uninstalled 1 package in 0.81ms
     Installed 1 package in 2ms
     … +2 lines (ctrl+o to expand)

⏺ Bash(ccprofile delete my-custom 2>&1 && ccprofile delete my-notion 2>&1)
  ⎿  Deleted profile 'my-custom'.
     Deleted profile 'my-notion'.

⏺ Now let me verify tests still pass and do a final sanity check:

⏺ Bash(uv run pytest tests/ -v 2>&1)
  ⎿  ============================= test session starts ====================
     ==========
     platform darwin -- Python 3.12.10, pytest-9.0.2, pluggy-1.6.0 -- /User
     … +19 lines (ctrl+o to expand)

⏺ Bash(ccprofile --help 2>&1)
  ⎿   Usage: ccprofile [OPTIONS] COMMAND [ARGS]...
     … +21 lines (ctrl+o to expand)

⏺ Now let me create the index.md for the project:

⏺ Write(index.md)
  ⎿  Wrote 33 lines to index.md
       1 # ccprofile — Claude Code Permission Profile Manager
       2 
       3 CLI tool to manage named permission profiles for Claude Code set
         tings.
       4 
       5 ## Files
       6 
       7 | File | Description |
       8 |------|-------------|
       9 | `pyproject.toml` | Package config with uv/hatch build, entry p
         oint `ccprofile.cli:app` |
      10 | `src/ccprofile/__init__.py` | Package marker |
     … +23 lines (ctrl+o to expand)

⏺ Done. Here's a summary:

  ccprofile — Implemented and Installed

  8 commands all working:

  ┌────────────────────────────────────┬────────────────────────────────────┐
  │              Command               │               Status               │
  ├────────────────────────────────────┼────────────────────────────────────┤
  │ ccprofile list                     │ Shows 6 built-in + custom profiles │
  ├────────────────────────────────────┼────────────────────────────────────┤
  │ ccprofile show <name>              │ Displays permissions table         │
  ├────────────────────────────────────┼────────────────────────────────────┤
  │ ccprofile save <name> --from       │ Snapshots current permissions      │
  │ user|project                       │                                    │
  ├────────────────────────────────────┼────────────────────────────────────┤
  │ ccprofile use <name> --scope       │ Applies profile (with backup)      │
  │ --merge --dry-run                  │                                    │
  ├────────────────────────────────────┼────────────────────────────────────┤
  │ ccprofile create <name>            │ Creates new profile                │
  │ --from-template --allow            │                                    │
  ├────────────────────────────────────┼────────────────────────────────────┤
  │ ccprofile delete <name>            │ Deletes custom profile (protects   │
  │                                    │ builtins)                          │
  ├────────────────────────────────────┼────────────────────────────────────┤
  │ ccprofile diff <a> <b>             │ Compares two profiles (supports    │
  │                                    │ @user/@project)                    │
  ├────────────────────────────────────┼────────────────────────────────────┤
  │ ccprofile current --scope both     │ Shows active permissions           │
  └────────────────────────────────────┴────────────────────────────────────┘

  Safety features: timestamped backups in ~/.claude/backups/ before writes, only
   permissions key replaced (other settings preserved), --dry-run mode, --merge
  for union instead of replace.

  11 tests passing covering core read/write/merge/backup and profile CRUD.

  Installed via uv tool install --editable — ccprofile is available globally.

✻ Brewed for 4m 6s