Plugins · CPO
Scope
Confine a policy to areas of a monorepo, and how CPO locates files and shell commands.
scope confines a policy to directories of the project, so the packages of a monorepo keep their own rules.
---
description: The API installs with pnpm
scope: [apps/api]
on: [shell.exec]
when: { builtin: command-ban, with: { commands: [npm] } }
---
`apps/api` uses pnpm.- Each glob names a directory relative to the project:
apps/api,apps/*,packages/**. A trailing/**changes nothing. - A location is in scope when it or one of its parent directories matches. The project root and paths outside the project are in no scope.
scopecombines withpaths/exclude: both must pass.- A whole profile takes a scope too: its policies apply where their own scope and the profile's both hold (Profile sources).
How an event is located
| Event | Located by |
|---|---|
file.*, search and other events with a path | the path |
shell.exec | each command's cwd: the policy only sees the commands running in its scope, and does not apply when none does |
| any other event | Claude's working directory (event.session.cwd) |
In cd apps/api && npm i; cd ../web && pnpm i, a policy scoped to apps/web sees only pnpm i. The raw
command string stays the whole line.
A command's cwd
Every parsed command carries cwd, the absolute directory it runs in. It starts at Claude's working directory
and follows the line:
cd,pushd/popd,command cd; a( … )subshell restores it after);sh -c '…',evaland$( )start where their parent runs and do not move the outer shell;- directory options:
git -C,go -C,cargo -C,make -C,ninja -C,tar -C,pnpm --dir,npm --prefix,yarn --cwd,bun --cwd,turbo --cwd,uv --directory,poetry -C,gradle -p,terraform -chdir=,just -d,env -C,sudo -D.
cwd is null when CPO cannot know it: cd "$DIR", cd "$(…)", cd -, cd apps/*. Such a command is in
every scope: hiding where a command runs does not dodge a gate.
cwd only locates commands for scope. The files a shell reads or writes keep resolving against Claude's
working directory.