
Scope
- 47 installs
- 416 repo stars
- Updated August 5, 2026
- boshu2/agentops
scope is a Claude Code skill that declares frozen directories and hard-blocks agent edits outside them via a PreToolUse hook.
About
This skill lets an agent operator declare which directories are in scope for a work session and hard-blocks any edit outside them. Frozen directories are written to a .agents/scope.lock file, and a PreToolUse hook rejects Edit, Write, or Bash calls that target paths outside every frozen directory. A developer uses it to fence agent swarms during risky changes; the guard fails open when the lock is missing or empty.
- Declares frozen directories that hard-block out-of-scope edits
- Enforces the lock via a PreToolUse hook on Edit, Write, and Bash
- Fails open on missing or malformed lock files
Scope by the numbers
- 47 all-time installs (skills.sh)
- Ranked #7,551 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
scope capabilities & compatibility
- Capabilities
- orchestration
- Use cases
- orchestration
What scope says it does
Hard-block edits outside declared frozen directories and protect paths during risky changes.
Any `Edit`, `Write`, or `Bash` tool call whose target path is **outside** every frozen directory is **rejected**
The hook fails **open** on malformed JSON or missing target-path fields
npx skills add https://github.com/boshu2/agentops --skill scopeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 47 |
|---|---|
| repo stars | ★ 416 |
| Last updated | August 5, 2026 |
| Repository | boshu2/agentops ↗ |
What it does
Fence agent edits to declared frozen directories with a PreToolUse hard-block hook.
Who is it for?
Fencing agent or swarm edits to specific directories during a work session
Skip if: Gating which commands run (rm -rf, DROP DATABASE) rather than where edits land
When should I use this skill?
You need to freeze edit scope to declared directories before a risky or swarm change
What you get
A filesystem gate where edits outside declared frozen directories are rejected before they run.
- filesystem-gate
- .agents/scope.lock
By the numbers
- 3 subcommands (freeze, unfreeze, status)
- schema_version 1 lock file
Files
/scope — Edit Scope Guard
Purpose: Declare which directories are in scope for the current work session. Edits outside the declared scope are hard-blocked by a PreToolUse hook.
YOU MUST EXECUTE THIS WORKFLOW. Do not just describe it.
---
Quick Start
/scope freeze cli/cmd/ao/ # Freeze a single directory
/scope freeze cli/cmd/ao/ skills/scope/ # Freeze multiple (additive)
/scope unfreeze cli/cmd/ao/ # Remove one frozen directory
/scope unfreeze # Clear ALL frozen directories
/scope status # Show current lock state
/scope status --json # JSON output---
Behavior Contract
When .agents/scope.lock declares one or more frozen_dirs:
- Any
Edit,Write, orBashtool call whose target path is outside every frozen directory is rejected byhooks/edit-scope-guard.shwith a structured stderr reason and a non-zero exit code (Claude Code converts that into a tool-use refusal). - Edits to paths under any frozen directory are allowed.
- When the lock file is missing OR
frozen_dirsis empty, the hook short-circuits with exit 0 (no enforcement; allow everything). - The hook fails open on malformed JSON or missing target-path fields — do not block when the input contract is violated. Defensive default protects against harness changes.
The lock file is written via cli/internal/llmwiki/scope_guard.go:SafeAtomicWrite, so concurrent freeze / unfreeze calls converge atomically (last writer wins, never tears).
---
Subcommands
/scope freeze <dir>...
Append one or more directories to the frozen set. Idempotent; re-freezing an already-frozen directory is a no-op. Updates acquired_at (ISO-8601) and acquired_by (session id or PID) on every write.
/scope unfreeze [<dir>]
Without arguments, clears the entire frozen set. With one or more directory arguments, removes just those entries. Removing a directory that is not frozen is a no-op.
/scope status [--json]
Print the current lock state. With --json, emit a single JSON object matching the schema in references/lock-file-format.md. Without flags, print a human-readable summary including each frozen directory, the acquisition timestamp, and the acquiring session.
/scope guard (future combo skill)
Reserved for a follow-up skill that combines freeze + status + spawn-orchestration. Not implemented in this release; documented here for forward reference.
---
Lock File Format
.agents/scope.lock is a single JSON object. Full schema lives in references/lock-file-format.md. Key fields:
schema_version— currently1frozen_dirs— list of repo-relative directory prefixes (trailing slash optional)acquired_at— ISO-8601 UTC timestampacquired_by— string identifying the writer (session id, PID, or label)
---
Examples
Freezing scope before a swarm wave
User says: /scope freeze cli/cmd/ao/ cli/internal/scope/
What happens:
1. ao scope freeze cli/cmd/ao/ cli/internal/scope/ writes .agents/scope.lock via SafeAtomicWrite. 2. hooks/edit-scope-guard.sh (registered as PreToolUse on Edit|Write|Bash) consults the lock on every subsequent tool call. 3. A worker that tries to Write to skills/foo/SKILL.md is rejected; a worker editing cli/cmd/ao/scope.go proceeds.
Releasing scope at the end of a wave
User says: /scope unfreeze
What happens:
1. ao scope unfreeze rewrites .agents/scope.lock with frozen_dirs: []. 2. The hook short-circuits to exit 0 on the next tool call.
---
Notes
- Wave 1 hardcodes the
.agents/scope.lockpath. Wave 2 (issue I5) migrates the path throughlib/ao-paths.sh. - The hook's defensive parse on malformed JSON is intentional. See references/lock-file-format.md for the rationale.
- This skill is purely session-boundary (path-scope freezing within a session). Cron-cadence orchestration lives outside AgentOps on the orchestration substrate (the reference is NTM + MCP + managed-agents), not in an AgentOps-shipped daemon.
- Path-scope freezing handles where edits land. For a complementary lane that gates what commands run (
rm -rf,git reset --hard,DROP DATABASE,kubectl delete,terraform destroy) — including allowlist layering, one-shot override codes, and PreToolUse wiring — see references/destructive-command-guard-patterns.md. Wire it alongside the scope guard when a wave touches infrastructure or shared data. - When a workflow needs human approval, hook parity, or simultaneous command review rather than only path freezing, use references/command-approval-and-hook-guardrails.md.
- When authoring new hook behavior rather than using scope's existing guard, use the hook authoring guidance in
cc-hooks.
References
- references/lock-file-format.md
- references/destructive-command-guard-patterns.md
- references/command-approval-and-hook-guardrails.md
- references/scope.feature — Executable spec: declare in-scope dirs, allow in-scope edits, hard-block out-of-scope edits via PreToolUse hook, report/release scope state (soc-qk4b)
Command Approval And Hook Guardrails
Use this reference when path-scope protection is not enough and a session needs command approval, hook parity, or high-risk operation review.
Guardrail Layers
| Layer | Blocks | Evidence |
|---|---|---|
| Path scope | Edits outside declared directories | .agents/scope.lock and hook stderr. |
| Command risk | Destructive or irreversible commands | Approval record or explicit denial. |
| Hook parity | Runtime-specific hook behavior drift | Hook fixture and schema tests. |
| Peer approval | High-risk command execution | Reviewer identity, command, and expiry. |
Approval Rules
- Approval is per command shape, not a blanket session waiver.
- Expire approvals quickly.
- Record the exact command, working directory, and reason.
- Prefer a safer equivalent command when one exists.
- Refuse approval when rollback is unclear.
Hook Review Checklist
- The hook fails open only for malformed hook input, not for known risky input.
- Output uses the portable subset accepted by all supported runtimes.
- Kill switches are documented and tested.
- Regex matchers have positive and negative examples.
- The hook has a timeout and no shell injection path.
---
Source: Adapted from an external skill corpus / dcg, cc-hooks, and slb. Pattern-only, no verbatim text.
Destructive Command Guard Patterns
A scope guard freezes where edits land. A destructive-command guard adds an orthogonal lane: freezing what commands a worker may execute, regardless of which directory it touches. This reference distills the methodology so a future scope-pack contributor can wire one in without reinventing the contract.
Why a separate guard
Scope-only enforcement leaves a gap. A worker can stay inside the frozen directory and still run something irrecoverable from there — rm -rf ., git reset --hard, DROP DATABASE, kubectl delete -A, terraform destroy. The directory check passes; the blast radius does not.
The destructive-command guard sits in the same PreToolUse position as edit-scope-guard.sh, but its predicate is the command string rather than the target path. The two compose cleanly:
PreToolUse(Bash) → scope-path-check → destructive-command-check → allow/denyA failure in either lane rejects the tool call.
Pattern catalog
The guard ships a base catalog keyed by tool family. Treat each entry as an authoritative pattern, not a regex literal — the implementation should normalize whitespace, quoting, and --flag=value vs --flag value before matching.
| Family | Pattern shape | Why it qualifies |
|---|---|---|
| Filesystem | rm -rf <abs-path-not-under-/tmp>, rm -rf . from outside a known build dir | Recursive deletion of non-scratch content has no general undo |
| Git history | git reset --hard, git checkout -- <file>, git clean -fd, git stash drop, git stash clear | Destroys uncommitted or stashed work that no other tool tracks |
| Git remote | git push --force (without --force-with-lease), git branch -D, git tag -d <pushed-tag> | Rewrites or deletes shared history |
| Database | DROP DATABASE, DROP TABLE, TRUNCATE, DELETE without a WHERE clause | Schema-level or unbounded data destruction |
| Container/k8s | kubectl delete namespace, kubectl delete --all, helm uninstall, docker system prune -a | Sweeps live workloads or shared caches |
| Cloud / IaC | terraform destroy, aws s3 rb --force, gcloud projects delete | Tears down infrastructure that humans co-own |
Pack additional families behind opt-in flags so a CLI-only repo never loads database or k8s rules.
Allowlist and override flow
Every pattern needs an escape hatch that records the override decision; otherwise operators silently disable the guard entirely. Implement three layers, evaluated highest to lowest priority:
1. Project allowlist — a checked-in file (e.g. .agents/destructive-allowlist.toml) listing rule IDs and optional path scopes that this repo permanently accepts. Reviewable in PRs. 2. User allowlist — ~/.config/<guard>/allowlist.toml for per-operator habits (cleaning a personal Docker cache, etc.). 3. One-shot override code — when a block fires, the guard prints a short cryptographic code bound to the exact command + working directory + a short TTL (e.g. 24 h, single use). The human, not the agent, runs <guard> allow-once <code> to grant the next attempt.
The one-shot path is load-bearing. It keeps the agent honest (the code is not predictable from context) and produces an audit log entry per override.
Confirm thresholds
Make the strictness configurable so the same binary can run in interactive, CI, and unattended-swarm contexts:
[thresholds]
mode = "block" # "block" | "warn" | "log-only"
require_override_for = ["filesystem", "git-history", "database"]
auto_allow_for = ["filesystem.rm-under-build-dir"]
warn_for = ["git-remote.force-with-lease"]Defaults: block on the high-blast-radius families, warn on near-equivalents that have a recoverable variant, log-only for purely informational rules. CI pipelines typically tighten to mode = "block" with a smaller allowlist; an interactive operator may relax to warn while pairing.
PreToolUse hook integration
The integration mirrors edit-scope-guard.sh:
- Trigger: PreToolUse on
Bash(Claude) orshell/apply_patch(Codex). - Input: harness-supplied JSON on stdin with
tool.params.command. - Pipeline: quick-reject screen → context sanitization → normalization → allowlist check → pattern match.
- Deny output: non-zero exit with a structured stderr reason — rule ID, family, suggested safer variant, and the one-shot override code. The harness converts that into a tool-use refusal the model can read.
- Allow output: exit 0, no stdout. Side-effect-free for the common case.
Performance budget matters because the hook runs on every Bash call. Target sub-millisecond steady state, with a hard fail-open ceiling (e.g. 200 ms) so a wedged guard never stalls the swarm.
Failure modes the guard must handle
- Fail-closed on a confirmed match. Pattern hits → reject, even if the override file is unreadable.
- Fail-open on infrastructure error. Missing config, malformed JSON, panic in the matcher → exit 0 with a stderr warning. Same defensive default as
edit-scope-guard.sh. - Fail-open on timeout. Anything past the latency ceiling skips the rest of the pipeline.
- Heredoc and inline scripts.
bash -c '...',python -c '...', and<<EOFbodies must be extracted and rescanned; otherwise a one-line wrapper bypasses every rule. - Quoted path normalization.
rm -rf "/var/log/"andrm -rf /var/logshould hit the same rule.
Composing with /scope
Recommended wiring for a swarm wave:
1. /scope freeze <dirs> to bound the edit surface. 2. Enable the destructive-command guard with the families relevant to this repo (filesystem + git-history is a sane minimum). 3. Add project-specific allowlist entries for routine safe deletions (e.g. rm -rf ./build, rm -rf ./.next). 4. Run the wave. Treat any block as a checkpoint, not an error: pick the safer variant from the rule's suggestion field, or escalate to the human for an allow-once. 5. After the wave, /scope unfreeze and let the destructive-command guard stay loaded — its overhead is negligible and the override audit log compounds.
The two guards do not need to share state, but they should share the same fail-open posture so a hook outage never silently disables both lanes at once.
---
Pattern adopted from dcg (ACFS skill corpus). Methodology only — no verbatim text..agents/scope.lock — Format Reference
The scope lock file declares which repo-relative directory prefixes are currently in scope for editing. The PreToolUse hook hooks/edit-scope-guard.sh consults it on every Edit, Write, and Bash tool call.
Schema (v1)
{
"schema_version": 1,
"frozen_dirs": ["cli/cmd/ao/", "skills/scope/"],
"acquired_at": "2026-05-01T19:30:00Z",
"acquired_by": "<session-id-or-pid>"
}| Field | Type | Required | Notes |
|---|---|---|---|
schema_version | integer | yes | Currently 1. Hook treats unknown versions as fail-open. |
frozen_dirs | array of strings | yes | Repo-relative directory prefixes. Trailing slash optional but conventional. Empty array means "no enforcement". |
acquired_at | string (ISO-8601) | yes | UTC, RFC 3339. Updated on every successful freeze / unfreeze. |
acquired_by | string | yes | Session id, PID, or human-supplied label. Used for diagnostic messages only. |
Atomicity guarantee
Writes go through cli/internal/llmwiki/scope_guard.go:SafeAtomicWrite, which writes to a temp file in the same directory and rename(2)s into place. Readers either see the previous JSON or the new JSON, never a torn document. Concurrent writers converge to last-writer-wins.
Hook behavior
hooks/edit-scope-guard.sh reads the file with these rules:
- File missing or empty: exit 0 (allow). The lock is opt-in.
- JSON parse fails: exit 0 (fail-open). Log warning to stderr.
- `frozen_dirs` empty: exit 0 (allow).
- Target path under any `frozen_dirs[i]`: exit 0 (allow).
- Target path outside every `frozen_dirs[i]`: exit 2 with structured stderr reason
edit-scope-guard: <path> outside frozen scope <frozen-dirs>. - Tool input malformed (missing `tool.params.file_path` AND `tool.params.command`): exit 0 (nothing to check).
Path comparison uses prefix match on the repo-relative path. Trailing slashes in frozen_dirs entries are normalized away before comparison.
Forward compatibility
schema_versionfuture bumps will be additive. The hook will continue to honor v1 fields.- New optional fields (e.g.,
expires_at,owner_session) may be added without breaking the contract.
# Executable spec for the /scope skill — edit-scope guardrail (BC5 Runtime).
# /scope declares which directories are in scope for the current work session and
# hard-blocks edits outside them via a PreToolUse hook, so a session cannot drift
# into files it never claimed. Hexagon: driven-adapter; consumes: a declared
# directory set; produces: scope/lock state + blocked-edit reasons on stderr. (soc-qk4b)
Feature: Scope hard-blocks edits outside the declared directories
As an agent working a bounded change
I want edits confined to directories I declared in scope
So that a session cannot silently modify files it never claimed
Background:
Given a work session that can declare an in-scope directory set
Scenario: Declaring scope records the allowed directories
When /scope declares one or more directories
Then those directories become the in-scope set and the lock state reflects them
Scenario: An edit inside scope proceeds
Given a declared in-scope directory
When a file inside it is edited
Then the edit is allowed
Scenario: An edit outside scope is hard-blocked with a reason
Given a declared scope
When a file outside the in-scope set is edited
Then the PreToolUse hook blocks the edit and reports the blocked-edit reason on stderr
Scenario: Scope state is reportable and releasable
When /scope is queried
Then it reports the current scope and lock state
And releasing scope removes the block on out-of-scope edits