Permission evaluation agent for Claude Code
Project description
Tower CLI
Claude Code's permission system is there for a good reason. It makes sure AI can't run tools on your machine without your say-so. But in practice, you end up clicking "allow" dozens of times per session for things you'd always approve (file reads, grep, git status). The alternative, --dangerously-skip-permissions, removes the safety net entirely.
Tower gives you a middle ground. It sits between Claude Code and tool execution as a PreToolUse hook and lets you define rules for what gets auto-allowed, what gets blocked, and what still asks. You keep the protection where it matters and skip the prompts where it doesn't.
Install
pip install cc-tower
tower init
That's it. This creates ~/.claude/tower-rules.yml and wires up the hook in ~/.claude/settings.json. Works globally across all your projects.
If you want rules scoped to a single project:
cd your-project
tower init --local
If you skip tower init entirely and just start using Claude Code, Tower auto-creates a default config at ~/.claude/tower-rules.yml the first time it evaluates a tool call.
What the config looks like
version: 1
default: ask # what happens when no rule matches: allow | deny | ask
rules:
# Reads and searches are safe, let them through
- tool: Read
action: allow
- tool: Glob
action: allow
- tool: Grep
action: allow
# Allow harmless bash commands
- tool: Bash
command_pattern: "^(ls|cat|git status|git diff|npm test|pytest).*"
action: allow
# Block destructive bash commands outright
- tool: Bash
command_pattern: "rm -rf|git push --force|DROP TABLE"
action: deny
reason: "Destructive command blocked by Tower"
# Allow writes only to code files
- tool: Write
path_pattern: "**/*.{py,js,ts,json,yml,yaml,md}"
action: allow
Rules are evaluated top-to-bottom, first match wins. If nothing matches, the default action kicks in.
Tower looks for tower-rules.yml in this order:
./tower-rules.yml(project root)./.claude/tower-rules.yml(project-local)~/.claude/tower-rules.yml(global)
Rule fields
| Field | Required | Description |
|---|---|---|
tool |
Yes | Tool name (Bash, Read, Write, Edit, Glob, etc) |
action |
Yes | allow, deny, or ask |
command_pattern |
No | Regex pattern for Bash commands |
path_pattern |
No | Glob pattern for file paths |
reason |
No | Message shown when a rule triggers |
Commands
| Command | What it does |
|---|---|
tower init |
Set up global config + hook in ~/.claude/ |
tower init --local |
Set up project-local config + hook in ./.claude/ |
tower status |
Show loaded rules and whether the hook is wired up |
tower config |
Interactive TUI for editing rules |
tower evaluate |
Evaluate a tool call from stdin (called by hook) |
Interactive config
Don't want to edit YAML by hand? tower config gives you a TUI.
You get a main menu, your current config info, and arrow-key navigation:
All your rules in a color-coded table. Green for allow, red for deny, yellow for ask:
Adding a rule. Pick a tool from the fuzzy-searchable list, choose an action, done:
Deleting a rule asks for confirmation so you don't accidentally remove something:
How it works under the hood
- Claude Code is about to run a tool (say,
Bashwithrm -rf /tmp/stuff) - The PreToolUse hook pipes the tool call to
tower evaluatevia stdin - Tower loads your rules, checks them top-to-bottom
- First matching rule decides:
allow,deny, orask - If no rule matches, the
defaultaction is used - Tower sends the decision back to Claude Code
Development
pip install -e ".[dev]"
pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cc_tower-0.1.0.tar.gz.
File metadata
- Download URL: cc_tower-0.1.0.tar.gz
- Upload date:
- Size: 11.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70fcf35b5e8e42e5087ebbc3f8a3daa363d4d30324ac021f7e3da1e63de429d5
|
|
| MD5 |
206cd637b8140857fbf0a9804bc292b7
|
|
| BLAKE2b-256 |
ff594489b8ae4e6362a99b123dd191ab8dc0ecb0c320de4d065c0d417876b37a
|
Provenance
The following attestation bundles were made for cc_tower-0.1.0.tar.gz:
Publisher:
publish.yml on thedhanawada/cc-tower
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cc_tower-0.1.0.tar.gz -
Subject digest:
70fcf35b5e8e42e5087ebbc3f8a3daa363d4d30324ac021f7e3da1e63de429d5 - Sigstore transparency entry: 975812807
- Sigstore integration time:
-
Permalink:
thedhanawada/cc-tower@b33a16dfa1b8a014da978478fb71b7c74099924b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/thedhanawada
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b33a16dfa1b8a014da978478fb71b7c74099924b -
Trigger Event:
release
-
Statement type:
File details
Details for the file cc_tower-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cc_tower-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f5cb80f089cb2a66589be776f3a93f05ccc41be938fcbcf50a69f7876a5abd8
|
|
| MD5 |
0e0cffe40a32d9fb69b02efcc64b087a
|
|
| BLAKE2b-256 |
2fde97c57e17311088c68766ccaaf03112cb0319fd5935cd0481d292f766fe15
|
Provenance
The following attestation bundles were made for cc_tower-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on thedhanawada/cc-tower
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cc_tower-0.1.0-py3-none-any.whl -
Subject digest:
0f5cb80f089cb2a66589be776f3a93f05ccc41be938fcbcf50a69f7876a5abd8 - Sigstore transparency entry: 975812810
- Sigstore integration time:
-
Permalink:
thedhanawada/cc-tower@b33a16dfa1b8a014da978478fb71b7c74099924b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/thedhanawada
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b33a16dfa1b8a014da978478fb71b7c74099924b -
Trigger Event:
release
-
Statement type: