A Claude Code plugin that restricts the top-level (orchestrator) thread to a small allowlist of orchestration tools. Everything else (file edits, shell, web fetches, MCP tools, etc.) is blocked at the top level and must run inside a subagent. Subagents themselves are never restricted.
The point is context hygiene: the main thread stays an orchestrator that plans and delegates, while heavy, context-polluting work happens in subagents whose output is summarized back rather than dumped into the main transcript.
It registers a single PreToolUse hook (scripts/gate.sh) on all tools.
PreToolUse payloads include an agent_id field only when the call fires
inside a subagent. The gate uses that:
agent_idpresent (subagent) -> allow everything.agent_idabsent (top-level thread) -> allow only tools on the allowlist; block the rest.
Reference: Claude Code hooks reference, "Common input fields" (https://code.claude.com/docs/en/hooks).
claude plugin marketplace add cloudripper/ctxctl
claude plugin install ctxctl@ctxctlThe plugin works out of the box with no configuration required — the defaults below are applied automatically on install.
To customise, run this in Claude Code:
/plugin configure ctxctl@ctxctl
You'll be prompted for each option. Leave any field blank to keep the default.
| Option | Default | Meaning |
|---|---|---|
allowlist |
Agent,Skill,TodoWrite,AskUserQuestion,ExitPlanMode,ScheduleWakeup,SendMessage |
Comma-separated tool names the top-level thread may still call (no spaces). |
mode |
deny |
deny blocks outright; ask prompts you to confirm each blocked top-level call. |
If a tool you want at the top level gets blocked, the denial message prints its
exact name — add it to allowlist and re-run the configure command. Tool names
can vary slightly between Claude Code versions, so treat the default list as a
starting point.
This is the common worry, and the answer is that they keep working:
- The top-level thread spawns a named agent (for example
code-review) by calling theAgenttool, which is on the allowlist. The spawn is allowed. - Inside that subagent, every tool call carries
agent_id, so the gate allows all of them. The agent does its work normally. - Skills that Claude triggers via the
Skilltool also work, becauseSkillis on the allowlist. (Typing/skillnamedirectly bypassesPreToolUseentirely, so that path is unaffected regardless.)
The only thing blocked is the orchestrator calling work tools directly.
bashandjqonPATH. On Windows, the hook runs under Git Bash (Claude Code's default shell-form shell); install Git Bash andjq.- If
jqis missing or the payload cannot be parsed, the gate fails open (allows the call) so it can never lock you out of every tool.
--agentsessions: launching withclaude --agent <name>makes the whole session an agent, soagent_idis set throughout and nothing is blocked.- MCP tools (
mcp__server__tool) are treated as work tools and are blocked at the top level by default. Add specific ones toallowlistif you want them available to the orchestrator. WebSearch/WebFetchare blocked at the top level by default on the same context-hygiene grounds. Add them toallowlistif you prefer quick top-level lookups.- This is a convenience guardrail, not a security boundary. For hard security controls use the permission system (deny rules) instead. See https://code.claude.com/docs/en/permissions.
ctxctl/
.claude-plugin/marketplace.json # marketplace catalog
plugins/ctxctl/
.claude-plugin/plugin.json # plugin manifest + userConfig
hooks/hooks.json # registers the PreToolUse gate
scripts/gate.sh # the gate logic
README.md
LICENSE
MIT. See LICENSE.