agent-callable

Tired of endless prompts from Claude Code?
Do you want to proceed?
❯ 1. Yes
2. Yes, and don't ask again for this risk-free command
3. No
My job has turned into approving Claude in a loop across a bunch of split terminals. Yes. Tab. Yes. Tab. Yes. Oops — no, that one was actually a question it was asking me. You know the drill.
On the other hand, I don't feel lucky enough to drop all permissions and let any command run. I want Claude to stop asking me to approve harmless commands — or commands with harmless side effects (yes, you can create a file in my workspace, that's kind of the point). But when it's about to do something truly stupid ("oh right, if I had run that command it would have wiped all your prod data"), I want the normal Claude prompt back.
Claude Code has a built-in, well-documented mechanism for this: allowlists in the settings. But the granularity is not great. Allowing Bash(kubectl get:*) lacks precision on subcommands and fails to match kubectl -c foobar get pod.
agent-callable grew out of kubectl-readonly, a kubectl wrapper that only allows read-only operations. The kubectl policy engine (kubepolicy) proved useful enough that I generalized the approach to cover every CLI tool an agent might call. agent-callable imports kubepolicy directly for its kubectl filtering — same battle-tested rules, broader scope.
agent-callable is two things:
- A binary that filters shell commands based on TOML config files for simple cases, plus edge cases handled in Go.
- A Claude Code plugin that wraps agent-callable in a transparent PreToolUse hook.
The result: with my agent-callable config, Claude Code no longer prompts me for anything I consider risk-free. Everything else gets the normal prompt. It's 100% transparent.
No security guarantee. This tool filters commands to reduce accidental side effects from LLM agents. It is not a sandbox, does not isolate processes, and a determined or creative agent may find ways around it. Use it as a convenience layer, not as a security boundary.
Quick start
1. Install the binary
go install github.com/evaneos/agent-callable/cmd/agent-callable@latest
Then generate the default config:
agent-callable --init-config # creates ~/.config/agent-callable/
The binary is usable standalone at this point — any LLM agent can call agent-callable <command> to run filtered commands.
2. Install the Claude Code plugin
Add the marketplace and install the plugin:
/plugin marketplace add Evaneos/agent-callable
/plugin install agent-callable@Evaneos/agent-callable
That's it — every Bash command now goes through the filter, no allowlist to maintain, no CLAUDE.md to write.
How it works
As a Claude Code plugin (recommended)
The plugin installs a PreToolUse hook. Every time Claude is about to run a Bash command, the hook quietly calls agent-callable under the hood:
- Claude generates a Bash command — it doesn't know the hook exists
- The hook passes the command to
agent-callable --claude
- Allowed → auto-approve, no prompt
- Not allowed → the hook steps aside, Claude Code shows the normal prompt
The hook never blocks anything itself. It just fast-tracks the boring stuff.
Set AGENT_CALLABLE_HOOK_DEBUG=1 to log hook decisions to /tmp/agent-callable-hook.log.
As a standalone binary
Outside Claude Code — or in any context where an LLM runs shell commands — the agent prefixes its commands with agent-callable:
agent-callable kubectl get pods -A # allowed
agent-callable git push # blocked
agent-callable --sh 'git log | head -5' # compound shell expression
This requires telling the agent to use the prefix (via CLAUDE.md or equivalent — see SAMPLE_CLAUDE.md). The plugin is simpler since it requires no instructions.
What gets filtered
Three categories of side effects:
| Category | Verdict | Examples |
|---|
| Remote effect — modifies an external service | blocked | git push, kubectl apply, gh pr create |
| Persistent config change — durably alters a tool's behavior | blocked | helm repo add, gcloud config set |
| Local cache/artifact write — useful for investigation | allowed | git fetch, docker pull, gh repo clone |
The rule is simple: when in doubt, block. A false positive (unnecessary prompt) is annoying. A false negative (wiped prod database) is not.