[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71J5YH3PQY5DKMKGP776V97":3,"skill-same:01M71J5YH3PQY5DKMKGP776V97":80},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":13,"repositoryHtmlUrl":47,"repositoryHomepageUrl":6,"ownerHtmlUrl":48,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":49,"install":50,"resources":63},"01M71J5YH3PQY5DKMKGP776V97","policy",null,"Defines the contract (policy.schema.json) and read substrate (policy-read.mjs) for the central autonomy policy. The SSOT for the 3 action classes, gate vocabulary, policy.yaml hierarchy, and zero-config defaults. Referenced by other skills and hooks.","ozzy-labs\u002Fskills","ozzy-labs","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F246109093?v=4","01M6H0M2K2PZXHWNHJJTWY20FY","01M71J2B6FZ5KPEXPR5VS1TX7Z",0,"MIT","https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fpolicy\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[5,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"hierarchy","vocabulary","autonomy","action","gate","yaml","config","read","json","substrate","false","schema","contract","hooks","for","ZeRO","2026-11-10 10:12:30",false,"---\nname: policy\ndescription: Defines the contract (policy.schema.json) and read substrate (policy-read.mjs) for the central autonomy policy. The SSOT for the 3 action classes, gate vocabulary, policy.yaml hierarchy, and zero-config defaults. Referenced by other skills and hooks.\nuser-invocable: false\n---\n\n# policy - Central autonomy policy contract and read substrate\n\nA referenced companion (ADR-0028 R3) that consolidates HITL gates — previously scattered across each skill's prose — into a **single-file declaration**. Provides the **SSOT for the contract governing action classification and gate decisions (policy.schema.json), and the all-adapter CLI that reads its effective values (policy-read.mjs)**. Aggregation and application (on the side of each skill \u002F hook) are built separately on top of this contract.\n\n## Principles\n\n- **Unify the contract**: Declare \"which actions require approval\" in a single policy file rather than in each skill's prose. Each skill simply classifies its own actions into one of the 3 classes and looks up the policy.\n- **fail-safe (not fail-open)**: A broken or adversarial policy must **never loosen** the level of autonomy. `policy-read.mjs` does not throw, but always falls back to the **stricter side (`ask`)** for values it cannot trust. This is the opposite direction of safe-side fallback from observability's fail-open (pass through even on failure).\n- **Zero-config = equivalent to current behavior**: When policy.yaml is absent, the default is equivalent to current behavior (acceptance criterion). Adding configuration doesn't break things via \"configure and forget.\"\n\n## The 3 action classes\n\nEach skill classifies its own actions into one of the following fixed vocabulary terms:\n\n| Class | Examples | Zero-config default |\n| --- | --- | --- |\n| `reversible-local` (reversible\u002Flocal) | Edits on a branch, safe branch delete, worktree prune | `proceed` (+ audit trail) |\n| `externally-visible` (externally visible) | Filing an issue, creating a PR, applying topics, PR comments | `batch-confirm` (one batch confirmation) |\n| `irreversible` (irreversible\u002Fdestructive) | merge, publish, stash drop, force operations | `ask` (always an Approval Gate) |\n\n## Gate vocabulary\n\nOnly the following 3 values can be assigned to each class \u002F action:\n\n| gate | Meaning |\n| --- | --- |\n| `proceed` | Execute as-is and leave an audit trail (no confirmation) |\n| `batch-confirm` | Confirm once, in a batch, before execution |\n| `ask` | Pass through an Approval Gate (explicit approval) for every single operation |\n\n## policy file hierarchy\n\n```text\n~\u002F.agents\u002Fpolicy.yaml          # user default (HOME-anchored)\n\u003Crepo>\u002F.agents\u002Fpolicy.yaml     # repo override (overrides user)\n```\n\nrepo overrides user, and user overrides the zero-config default. File format (`policy.schema.json` is the SSOT):\n\n```yaml\nschema_version: 1\nclasses:\n  reversible-local: proceed\n  externally-visible: batch-confirm\n  irreversible: ask\nactions:\n  merge: ask            # per-action override (takes precedence over the class default)\n  issue-create: proceed\n```\n\n`classes` declares the gate for the 3 classes, and `actions` overrides the gate per kebab-case action name (takes precedence over the class default). Unknown **top-level keys** are mechanically rejected by `additionalProperties: false`. Action names are open, since each skill declares its own; only the value (gate vocabulary) and key shape are validated.\n\n## Contract (policy.schema.json is the SSOT)\n\n`policy.schema.json` (a sibling of this skill) is the sole SSOT. Both `policy-read.mjs` and the tests validate by **reading this file**, so doc and code never drift apart. Following the same approach as skill-observability's `event.schema.json`, `additionalProperties: false` (at the top level) mechanically prevents \"unintended loosening of autonomy\" caused by typos or unknown keys. `schema_version` is fixed at `1`.\n\n## Read substrate (policy-read.mjs)\n\n`policy-read.mjs` (sibling, a CLI that runs on all adapters) reads and merges the user + repo policy.yaml, and **returns the merged effective values as JSON to stdout**. To avoid a new runtime dependency, YAML is parsed with a hand-rolled parser covering only the minimal subset policy.yaml requires (nested mappings + `key: value` + comments).\n\n```bash\n# Return the merged effective policy (classes \u002F actions \u002F sources \u002F degraded) as JSON\nnode policy-read.mjs\n\n# Resolve the effective gate for a single action (per-action override → class default → stricter side)\nnode policy-read.mjs --action=merge          # => resolved.gate (default ask)\nnode policy-read.mjs --action=issue-create   # => resolved.gate (default batch-confirm)\nnode policy-read.mjs --class=reversible-local\n\n# Specify the repo root explicitly (default is cwd)\nnode policy-read.mjs --repo-root=\u002Fpath\u002Fto\u002Frepo\n```\n\nOutput (example, under zero-config):\n\n```json\n{\n  \"schema_version\": 1,\n  \"classes\": { \"reversible-local\": \"proceed\", \"externally-visible\": \"batch-confirm\", \"irreversible\": \"ask\" },\n  \"actions\": {},\n  \"sources\": { \"user\": false, \"repo\": false },\n  \"degraded\": false\n}\n```\n\nfail-safe conventions:\n\n- **File absent** → zero-config default (equivalent to current behavior). `degraded: false`.\n- **Invalid gate value** (schema mismatch) → the effective value for that class \u002F action falls back to `ask`. It never falls through to a looser, lower-priority value.\n- **Unparseable file** → ignore that file and set `degraded: true`. Resolve using the other file + defaults (the default for the dangerous class is already `ask`).\n- Never throws on any failure; always exits 0. Does not break callers chained with `&&`.\n\n## PreToolUse enforcement hook (Claude Code \u002F `policy-hook.mjs`)\n\nThe prose layer (each skill \"classifying its own action and looking up the policy\") is ultimately a **request**, which the model could ignore or bypass. `policy-hook.mjs` (a sibling PreToolUse hook of the same shape as `usage-guard-hook.mjs`) is **gate enforcement on the execution-engine side**, and physically closes off that gap. It fires before every tool call (including inside subagents), and only looks up the policy to decide deny\u002Fallow when it detects a **specific irreversible command**.\n\n| Detected command | Action looked up (class) | Zero-config default gate | Hook behavior |\n| --- | --- | --- | --- |\n| `gh pr merge …` | `merge` (`irreversible`) | `ask` | deny (exit 2) |\n| `gh release create …` | `release-create` (`irreversible`) | `ask` | deny |\n| `git push --force` \u002F `-f` \u002F `--force-with-lease` | `force-push` (`irreversible`) | `ask` | deny |\n| `npm` \u002F `pnpm` \u002F `yarn publish` | `publish` (`irreversible`) | `ask` | deny |\n\n- **gate → decision:** If the resolved gate is `ask`, deny (exit 2 + reason to stderr); if `proceed` \u002F `batch-confirm`, allow. The hook only hard-blocks on `ask` (batch confirmation is the responsibility of the caller \u002F prose layer).\n- **Narrow gating (preventing an all-tool-deny accident):** The policy is looked up **only when it matches an irreversible command in the table above**. Everything else (reads, edits, safe git\u002Fgh\u002Fnpm, non-Bash tools) passes through untouched. Even if the matcher has a bug, it can only fail in the direction of \"missing a dangerous command\" — it never denies every tool and wedges the session.\n- **Doesn't hard-stop on a transient blip (carried over from `usage-guard-hook.mjs`):**\n  - **(a) file kill-switch:** If `~\u002F.claude\u002Fpolicy-guard\u002FDISABLE` exists, it's an immediate no-op allow at the very start. Running `touch` from a `!` shell releases it instantly within the session, with no config edit needed.\n  - **(b) Policy unreadable \u002F unparseable → allow + stderr warning:** When `policy-read.mjs` returns `degraded`, or the resolver throws, etc. — i.e., whenever **the gate cannot be trusted** — allow rather than deny. Even if the gated command can be detected, if the gate value can't be trusted, let it through. Since the **resumable prose-layer checkpoint (drive \u002F health \u002F lessons-triage) is the primary gate that looks up the same `policy-read.mjs` (fail-safe to `ask`)**, and the hook is a secondary net, it falls to the side of not stopping the session over a broken policy.\n  - **(c) proceed override (equivalent to `--merge`):** A caller that has already resolved the gate and been delegated autonomy (e.g., `drive --merge` overrides merge to `proceed` in prose) exports `POLICY_GUARD_PROCEED=\u003Caction>[,\u003Caction>…]` (`all` \u002F `*` also work). The hook allows that action without re-gating it. This ensures legitimate opt-in merges aren't blocked by the enforcement net.\n- **subagent:** Appends the payload's `agent_id` to the deny message as `[origin: subagent \u003Cid>]` (functions as a mid-unit ceiling for a running worker).\n\n### Wiring (recommended: `hooks add policy`)\n\nThe hook script is bundled in every adapter's payload. Wiring into settings is handled by the CLI ([#174](https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fissues\u002F174) PR 3 added support for `hooks add policy`; same shape as `usage-guard` \u002F `observability`):\n\n```bash\n# Wire the PreToolUse policy gate into ~\u002F.claude\u002Fsettings.local.json (absolute path resolved automatically)\nnpx @ozzylabs\u002Fskills hooks add policy\n\n# Check wiring status\nnpx @ozzylabs\u002Fskills hooks status\n\n# Unwire (removes only the entry it wrote)\nnpx @ozzylabs\u002Fskills hooks remove policy\n```\n\nThe CLI resolves the absolute path of `policy-hook.mjs` from the installed skill dir, shows a diff, and writes it after confirmation (`--yes` for non-interactive, `--dry-run` for plan-only, `--scope=user` for `settings.json`). It is idempotent (re-running `add` is a no-op) and never touches entries other than the one it wrote. The policy that **the repo does not distribute settings \u002F hooks** remains unchanged — the CLI merely writes to local settings with the user's consent.\n\nA policy.yaml template can be generated with `npx @ozzylabs\u002Fskills policy init` (`--scope=repo` for `\u003Crepo>\u002F.agents\u002Fpolicy.yaml`); an existing file is skipped, not overwritten.\n\n**Fallback (manual wiring):** If not using the CLI, manually add one entry to `~\u002F.claude\u002Fsettings.local.json` (settings reload mid-session, so no restart is needed):\n\n```json\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Bash\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"node \u002Fhome\u002F\u003Cyou>\u002F.claude\u002Fskills\u002Fpolicy\u002Fpolicy-hook.mjs\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n> **Fill in the hook script path as an absolute path by hand** (skill-dir-relative references don't work inside settings). The path varies by environment:\n>\n> - **user-scope** (`npx @ozzylabs\u002Fskills install`): `~\u002F.claude\u002Fskills\u002Fpolicy\u002Fpolicy-hook.mjs` (`~` is not expanded, so write it out in full as `\u002Fhome\u002F\u003Cyou>\u002F.claude\u002F…`)\n> - **dogfood** (inside the skills\u002Fcommons repo): `\u003Crepo>\u002F.claude\u002Fskills\u002Fpolicy\u002Fpolicy-hook.mjs`\n>\n> Both point to \"the `policy-hook.mjs` at the same level as `policy-read.mjs`.\" Since irreversible commands go through Bash, `\"Bash\"` is sufficient as the matcher (`\"*\"` also works — non-Bash tools have no command and pass through).\n\n**Disabling:** `touch ~\u002F.claude\u002Fpolicy-guard\u002FDISABLE` (instant, no config edit needed), or remove the above entry from settings (permanent).\n\n## Scope of application\n\nThis skill provides the **contract (schema) + read substrate + PreToolUse enforcement hook**. The following are built in separate PRs on top of this contract (not included in this PR):\n\n- **Application by each skill** (replacing the gate descriptions in implement \u002F lessons-triage \u002F topics etc. with \"classify your own action and look up the policy.\" Already implemented in R3 PR2\u002FPR3).\n- **Automatic hook wiring** (`hooks add policy`. Already implemented in [#174](https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fissues\u002F174) PR 3. See \"Wiring\" above).\n\n## Notes\n\n- Does not read `.env` files.\n- This skill is read-only. It does not generate or rewrite policy.yaml (that is handled by `policy init` in a separate PR).\n- fail-safe means \"fall back to the stricter side,\" the opposite direction from observability's fail-open (pass through). Do not confuse the two.\n","# policy - Central autonomy policy contract and read substrate\n\nA referenced companion (ADR-0028 R3) that consolidates HITL gates — previously scattered across each skill's prose — into a **single-file declaration**. Provides the **SSOT for the contract governing action classification and gate decisions (policy.schema.json), and the all-adapter CLI that reads its effective values (policy-read.mjs)**. Aggregation and application (on the side of each skill \u002F hook) are built separately on top of this contract.\n\n## Principles\n\n- **Unify the contract**: Declare \"which actions require approval\" in a single policy file rather than in each skill's prose. Each skill simply classifies its own actions into one of the 3 classes and looks up the policy.\n- **fail-safe (not fail-open)**: A broken or adversarial policy must **never loosen** the level of autonomy. `policy-read.mjs` does not throw, but always falls back to the **stricter side (`ask`)** for values it cannot trust. This is the opposite direction of safe-side fallback from observability's fail-open (pass through even on failure).\n- **Zero-config = equivalent to current behavior**: When policy.yaml is absent, the default is equivalent to current behavior (acceptance criterion). Adding configuration doesn't break things via \"configure and forget.\"\n\n## The 3 action classes\n\nEach skill classifies its own actions into one of the following fixed vocabulary terms:\n\n| Class | Examples | Zero-config default |\n| --- | --- | --- |\n| `reversible-local` (reversible\u002Flocal) | Edits on a branch, safe branch delete, worktree prune | `proceed` (+ audit trail) |\n| `externally-visible` (externally visible) | Filing an issue, creating a PR, applying topics, PR comments | `batch-confirm` (one batch confirmation) |\n| `irreversible` (irreversible\u002Fdestructive) | merge, publish, stash drop, force operations | `ask` (always an Approval Gate) |\n\n## Gate vocabulary\n\nOnly the following 3 values can be assigned to each class \u002F action:\n\n| gate | Meaning |\n| --- | --- |\n| `proceed` | Execute as-is and leave an audit trail (no confirmation) |\n| `batch-confirm` | Confirm once, in a batch, before execution |\n| `ask` | Pass through an Approval Gate (explicit approval) for every single operation |\n\n## policy file hierarchy\n\n```text\n~\u002F.agents\u002Fpolicy.yaml          # user default (HOME-anchored)\n\u003Crepo>\u002F.agents\u002Fpolicy.yaml     # repo override (overrides user)\n```\n\nrepo overrides user, and user overrides the zero-config default. File format (`policy.schema.json` is the SSOT):\n\n```yaml\nschema_version: 1\nclasses:\n  reversible-local: proceed\n  externally-visible: batch-confirm\n  irreversible: ask\nactions:\n  merge: ask            # per-action override (takes precedence over the class default)\n  issue-create: proceed\n```\n\n`classes` declares the gate for the 3 classes, and `actions` overrides the gate per kebab-case action name (takes precedence over the class default). Unknown **top-level keys** are mechanically rejected by `additionalProperties: false`. Action names are open, since each skill declares its own; only the value (gate vocabulary) and key shape are validated.\n\n## Contract (policy.schema.json is the SSOT)\n\n`policy.schema.json` (a sibling of this skill) is the sole SSOT. Both `policy-read.mjs` and the tests validate by **reading this file**, so doc and code never drift apart. Following the same approach as skill-observability's `event.schema.json`, `additionalProperties: false` (at the top level) mechanically prevents \"unintended loosening of autonomy\" caused by typos or unknown keys. `schema_version` is fixed at `1`.\n\n## Read substrate (policy-read.mjs)\n\n`policy-read.mjs` (sibling, a CLI that runs on all adapters) reads and merges the user + repo policy.yaml, and **returns the merged effective values as JSON to stdout**. To avoid a new runtime dependency, YAML is parsed with a hand-rolled parser covering only the minimal subset policy.yaml requires (nested mappings + `key: value` + comments).\n\n```bash\n# Return the merged effective policy (classes \u002F actions \u002F sources \u002F degraded) as JSON\nnode policy-read.mjs\n\n# Resolve the effective gate for a single action (per-action override → class default → stricter side)\nnode policy-read.mjs --action=merge          # => resolved.gate (default ask)\nnode policy-read.mjs --action=issue-create   # => resolved.gate (default batch-confirm)\nnode policy-read.mjs --class=reversible-local\n\n# Specify the repo root explicitly (default is cwd)\nnode policy-read.mjs --repo-root=\u002Fpath\u002Fto\u002Frepo\n```\n\nOutput (example, under zero-config):\n\n```json\n{\n  \"schema_version\": 1,\n  \"classes\": { \"reversible-local\": \"proceed\", \"externally-visible\": \"batch-confirm\", \"irreversible\": \"ask\" },\n  \"actions\": {},\n  \"sources\": { \"user\": false, \"repo\": false },\n  \"degraded\": false\n}\n```\n\nfail-safe conventions:\n\n- **File absent** → zero-config default (equivalent to current behavior). `degraded: false`.\n- **Invalid gate value** (schema mismatch) → the effective value for that class \u002F action falls back to `ask`. It never falls through to a looser, lower-priority value.\n- **Unparseable file** → ignore that file and set `degraded: true`. Resolve using the other file + defaults (the default for the dangerous class is already `ask`).\n- Never throws on any failure; always exits 0. Does not break callers chained with `&&`.\n\n## PreToolUse enforcement hook (Claude Code \u002F `policy-hook.mjs`)\n\nThe prose layer (each skill \"classifying its own action and looking up the policy\") is ultimately a **request**, which the model could ignore or bypass. `policy-hook.mjs` (a sibling PreToolUse hook of the same shape as `usage-guard-hook.mjs`) is **gate enforcement on the execution-engine side**, and physically closes off that gap. It fires before every tool call (including inside subagents), and only looks up the policy to decide deny\u002Fallow when it detects a **specific irreversible command**.\n\n| Detected command | Action looked up (class) | Zero-config default gate | Hook behavior |\n| --- | --- | --- | --- |\n| `gh pr merge …` | `merge` (`irreversible`) | `ask` | deny (exit 2) |\n| `gh release create …` | `release-create` (`irreversible`) | `ask` | deny |\n| `git push --force` \u002F `-f` \u002F `--force-with-lease` | `force-push` (`irreversible`) | `ask` | deny |\n| `npm` \u002F `pnpm` \u002F `yarn publish` | `publish` (`irreversible`) | `ask` | deny |\n\n- **gate → decision:** If the resolved gate is `ask`, deny (exit 2 + reason to stderr); if `proceed` \u002F `batch-confirm`, allow. The hook only hard-blocks on `ask` (batch confirmation is the responsibility of the caller \u002F prose layer).\n- **Narrow gating (preventing an all-tool-deny accident):** The policy is looked up **only when it matches an irreversible command in the table above**. Everything else (reads, edits, safe git\u002Fgh\u002Fnpm, non-Bash tools) passes through untouched. Even if the matcher has a bug, it can only fail in the direction of \"missing a dangerous command\" — it never denies every tool and wedges the session.\n- **Doesn't hard-stop on a transient blip (carried over from `usage-guard-hook.mjs`):**\n  - **(a) file kill-switch:** If `~\u002F.claude\u002Fpolicy-guard\u002FDISABLE` exists, it's an immediate no-op allow at the very start. Running `touch` from a `!` shell releases it instantly within the session, with no config edit needed.\n  - **(b) Policy unreadable \u002F unparseable → allow + stderr warning:** When `policy-read.mjs` returns `degraded`, or the resolver throws, etc. — i.e., whenever **the gate cannot be trusted** — allow rather than deny. Even if the gated command can be detected, if the gate value can't be trusted, let it through. Since the **resumable prose-layer checkpoint (drive \u002F health \u002F lessons-triage) is the primary gate that looks up the same `policy-read.mjs` (fail-safe to `ask`)**, and the hook is a secondary net, it falls to the side of not stopping the session over a broken policy.\n  - **(c) proceed override (equivalent to `--merge`):** A caller that has already resolved the gate and been delegated autonomy (e.g., `drive --merge` overrides merge to `proceed` in prose) exports `POLICY_GUARD_PROCEED=\u003Caction>[,\u003Caction>…]` (`all` \u002F `*` also work). The hook allows that action without re-gating it. This ensures legitimate opt-in merges aren't blocked by the enforcement net.\n- **subagent:** Appends the payload's `agent_id` to the deny message as `[origin: subagent \u003Cid>]` (functions as a mid-unit ceiling for a running worker).\n\n### Wiring (recommended: `hooks add policy`)\n\nThe hook script is bundled in every adapter's payload. Wiring into settings is handled by the CLI ([#174](https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fissues\u002F174) PR 3 added support for `hooks add policy`; same shape as `usage-guard` \u002F `observability`):\n\n```bash\n# Wire the PreToolUse policy gate into ~\u002F.claude\u002Fsettings.local.json (absolute path resolved automatically)\nnpx @ozzylabs\u002Fskills hooks add policy\n\n# Check wiring status\nnpx @ozzylabs\u002Fskills hooks status\n\n# Unwire (removes only the entry it wrote)\nnpx @ozzylabs\u002Fskills hooks remove policy\n```\n\nThe CLI resolves the absolute path of `policy-hook.mjs` from the installed skill dir, shows a diff, and writes it after confirmation (`--yes` for non-interactive, `--dry-run` for plan-only, `--scope=user` for `settings.json`). It is idempotent (re-running `add` is a no-op) and never touches entries other than the one it wrote. The policy that **the repo does not distribute settings \u002F hooks** remains unchanged — the CLI merely writes to local settings with the user's consent.\n\nA policy.yaml template can be generated with `npx @ozzylabs\u002Fskills policy init` (`--scope=repo` for `\u003Crepo>\u002F.agents\u002Fpolicy.yaml`); an existing file is skipped, not overwritten.\n\n**Fallback (manual wiring):** If not using the CLI, manually add one entry to `~\u002F.claude\u002Fsettings.local.json` (settings reload mid-session, so no restart is needed):\n\n```json\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Bash\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"node \u002Fhome\u002F\u003Cyou>\u002F.claude\u002Fskills\u002Fpolicy\u002Fpolicy-hook.mjs\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n> **Fill in the hook script path as an absolute path by hand** (skill-dir-relative references don't work inside settings). The path varies by environment:\n>\n> - **user-scope** (`npx @ozzylabs\u002Fskills install`): `~\u002F.claude\u002Fskills\u002Fpolicy\u002Fpolicy-hook.mjs` (`~` is not expanded, so write it out in full as `\u002Fhome\u002F\u003Cyou>\u002F.claude\u002F…`)\n> - **dogfood** (inside the skills\u002Fcommons repo): `\u003Crepo>\u002F.claude\u002Fskills\u002Fpolicy\u002Fpolicy-hook.mjs`\n>\n> Both point to \"the `policy-hook.mjs` at the same level as `policy-read.mjs`.\" Since irreversible commands go through Bash, `\"Bash\"` is sufficient as the matcher (`\"*\"` also works — non-Bash tools have no command and pass through).\n\n**Disabling:** `touch ~\u002F.claude\u002Fpolicy-guard\u002FDISABLE` (instant, no config edit needed), or remove the above entry from settings (permanent).\n\n## Scope of application\n\nThis skill provides the **contract (schema) + read substrate + PreToolUse enforcement hook**. The following are built in separate PRs on top of this contract (not included in this PR):\n\n- **Application by each skill** (replacing the gate descriptions in implement \u002F lessons-triage \u002F topics etc. with \"classify your own action and look up the policy.\" Already implemented in R3 PR2\u002FPR3).\n- **Automatic hook wiring** (`hooks add policy`. Already implemented in [#174](https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fissues\u002F174) PR 3. See \"Wiring\" above).\n\n## Notes\n\n- Does not read `.env` files.\n- This skill is read-only. It does not generate or rewrite policy.yaml (that is handled by `policy init` in a separate PR).\n- fail-safe means \"fall back to the stricter side,\" the opposite direction from observability's fail-open (pass through). Do not confuse the two.\n",{"name":5,"description":7,"user-invocable":40},"main","db212a47efe751fa1c42bd76e61dbfd8328e5b10",".claude\u002Fskills\u002Fpolicy","https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills","https:\u002F\u002Fgithub.com\u002Fozzy-labs","2026-07-13 06:49:42",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add ozzy-labs\u002Fskills --skill policy",{"tool":56,"command":57},"bunx","bunx skills add ozzy-labs\u002Fskills --skill policy",{"tool":59,"command":60},"pnpm","pnpm dlx skills add ozzy-labs\u002Fskills --skill policy","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fpolicy\u002FSKILL.md",true,[64,70,74],{"path":65,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":68,"sourceHtmlUrl":69},"policy-hook.mjs","SCRIPT","脚本",15254,"https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fpolicy\u002Fpolicy-hook.mjs",{"path":71,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":72,"sourceHtmlUrl":73},"policy-read.mjs",16771,"https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fpolicy\u002Fpolicy-read.mjs",{"path":75,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":78,"sourceHtmlUrl":79},"policy.schema.json","REFERENCE","参考文档",2684,"https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fpolicy\u002Fpolicy.schema.json",[81,107,133,154,175,197],{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":39},"01M71J6R63H4E6ZE6KMDM4CT85","verify","An integrated skill that runs the combined validation of build \u002F typecheck \u002F test \u002F lint in one shot. The `verify.mjs` engine auto-discovers validation commands via a discovery chain (AGENTS.md's 「検証」 section → package.json scripts → justfile\u002FMakefile\u002Flefthook → language heuristics), executes them serially with their source attached, and returns a result summary. If a higher-priority stage produces a hit, only that stage is executed (no crossing stages).","https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fverify\u002FSKILL.md",[],[83,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106],"combined","heuristics","chain","repo","discovery","section","lefthook","only","auto","package","stage","Bash","one","lint","dry","engine","with","test","typecheck",{"skillNo":108,"name":109,"nameZh":6,"description":110,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":113,"publishedAt":39},"01M71J6JW7SAY9PDKAWHG3SJCR","usage-guard","Monitors Claude Code's Usage Limit (5-hour = Current \u002F weekly = Weekly), pauses work when it exceeds 95%, and automatically resumes once the reset restores headroom. Bundles an engine form that a caller such as drive Reads at a checkpoint, and a standalone form, `\u002Fusage-guard \"\u003Ccontinuation command>\"`, that guards arbitrary work. Claude-only (depends on the OAuth usage-rate endpoint + ScheduleWakeup).","https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fusage-guard\u002FSKILL.md",[],[114,115,116,117,118,95,119,120,121,122,123,124,125,126,127,128,129,130,131,132],"usage","usage guard","guard","weekly","standalone","guards","when","code","reset","work","command","at","rate","status","endpoint","as","continuation","form","limit",{"skillNo":134,"name":135,"nameZh":6,"description":136,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":139,"publishedAt":39},"01M71J6FRG119REA1G0S99Q4GZ","topics","Selects GitHub topic candidates by having the `topics.mjs` engine perform constraint validation, popularity measurement, broad+narrow \u002F singular-plural comparison, and hardcoded ozzy-labs conventions, then applies them via `gh repo edit --add-topic` following the policy's `externally-visible` gate (default batch-confirm). Scope is limited to use within ozzy-labs.","https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ftopics\u002FSKILL.md",[],[135,140,141,91,5,142,143,144,145,146,147,99,148,149,150,102,103,151,152,153],"measurement","scope","default","true","gh","plural","use","comparison","apply","candidate","batch","candidates","github","via",{"skillNo":155,"name":156,"nameZh":6,"description":157,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":158,"categories":159,"keywords":166,"publishedAt":39},"01M71J6DC27P4FDSP10SDT2PSN","skill-observability","Defines the skill observability event contract (event.schema.json) and emit substrate (obs-emit.mjs). The SSOT for the measurement layer of the skill improvement loop. Referenced by other skills and hooks.","https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fskill-observability\u002FSKILL.md",[160,165],{"categoryNo":161,"categoryName":162,"taxonomyType":163,"taxonomyTypeDesc":164},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[167,168,140,169,170,37,171,36,35,34,172,33,32,31,173,174],"observability","skill observability","improvement","skill improvement","event","loop","improvement loop","layer",{"skillNo":176,"name":177,"nameZh":6,"description":178,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":179,"categories":180,"keywords":182,"publishedAt":39},"01M71J6AYECH1J94RAZ49QZ19Y","skill-metrics","Aggregates the local observability event log (~\u002F.agents\u002Fobservability\u002Fevents.jsonl) and presents, read-only, per-skill invocation counts and notable events (fallback \u002F HITL rejection \u002F loop cap reached \u002F abort). Fires on \"show me the skill metrics,\" \"aggregate the observability results,\" \"which skills get used the most?\" Does not send anything.","https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fskill-metrics\u002FSKILL.md",[181],{"categoryNo":161,"categoryName":162,"taxonomyType":163,"taxonomyTypeDesc":164},[183,184,167,185,186,187,188,189,171,190,191,192,193,143,95,172,194,99,195,196],"skill metrics","metrics","event log","which","show","get","read-only","iso","aggregates","send","local","show me","log","jsonl",{"skillNo":198,"name":199,"nameZh":6,"description":200,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":201,"categories":202,"keywords":203,"publishedAt":39},"01M71J68TD0QFATGW3BBZVCWA2","ship","Runs verification, commit, and PR creation all at once. An integrated pipeline that runs verify (build + type + test + lint) → commit → PR creation in sequence against the changes.","https:\u002F\u002Fgithub.com\u002Fozzy-labs\u002Fskills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fship\u002FSKILL.md",[],[199,204,205,105,206,207,83,208,209,210,125,30,211,212,143,213,99,214,101],"type","verification","changes","pr","creation","build","pipeline","sequence","grep","pr creation","commit"]