Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Set Posture

FSecurity

Translate `.ravenclaude/comfort-posture.yaml` into `.claude/settings.json` permission rules. Owns the (category, level) → permission-rule emission table that the `/set-posture` slash command applies. Read this skill when authoring or reviewing the translation logic, when a category is missing rules, or when a level's behavior surprises you.

7 stars
0 votes
0 copies
0 views
Added 9/23/2026
ai-agentspythonrustgorubyshellbashnodegitapifrontend

Works with

claude codecliapimcp

Security Analysis

F35/100
criticalPipes output to a shell interpreter
highPerforms destructive filesystem operations
criticalDownloads and executes remote scripts — classic supply chain attack

Pro shows the line behind each finding and how to fix it

Scanned 9/23/2026

$npx -y skills add mcorbett51090/RavenClaude --skill set-posture --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Set Posture?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Set Posture
[![Security: F — Skills Directory](https://www.skillsdirectory.com/api/skills/mcorbett51090-set-posture/badge)](https://www.skillsdirectory.com/skills/mcorbett51090-set-posture)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: set-posture
description: Translate `.ravenclaude/comfort-posture.yaml` into `.claude/settings.json` permission rules. Owns the (category, level) → permission-rule emission table that the `/set-posture` slash command applies. Read this skill when authoring or reviewing the translation logic, when a category is missing rules, or when a level's behavior surprises you.
---

# Skill: set-posture

This skill is the canonical reference for **how comfort-posture YAML maps to Claude Code permission rules**. The slash command `/set-posture` invokes a Python script that implements this mapping; this file documents the design and is the place to extend it (new categories, new buckets, time-boxed elevations, MCP per-server trust).

## The translation pipeline

```mermaid
flowchart LR
  DASH[Dashboard Settings tab] -->|Save to repo| YAML[.ravenclaude/comfort-posture.yaml]
  YAML -->|/set-posture| TR[apply-comfort-posture.py]
  TR -->|overwrite| RULES[.claude/settings.json allow/ask/deny]
  RULES --> ENGINE[Claude Code engine]
  LOCAL[.claude/settings.local.json] -->|merged on top| ENGINE
```

The skill owns the translation step. The dashboard owns the input. The script owns the file I/O. v0.17.0 switched from snapshot-merge to clean overwrite: the posture YAML is the single source of truth for `permissions.{allow,ask,deny}`. Personal overrides belong in `.claude/settings.local.json`, which Claude Code merges on top.

## Level → bucket (v0.19.0)

The vocabulary is three levels, one per bucket:

| YAML level | settings.json bucket |
|---|---|
| `deny` | `permissions.deny` |
| `ask` | `permissions.ask` |
| `allow` | `permissions.allow` |

Earlier releases exposed five levels (`always-ask`, `mostly-ask`, `mostly-allow`, `autopilot` alongside `deny`) that already collapsed to these same three buckets — `always-ask` ≡ `mostly-ask` and `mostly-allow` ≡ `autopilot`. The planned v0.2.0 split that would have made those pairs behave differently (a per-category `safe_patterns` / `risky_patterns` shape) was never shipped, so the extra levels were always cosmetic. v0.19.0 retires them from the dashboard. The translator still **accepts** the old names so a consumer's pre-0.19.0 `comfort-posture.yaml` keeps translating unchanged after a `/plugin marketplace update`; see `level_to_bucket()` in `apply-comfort-posture.py`.

## Category → patterns (v0.1.0)

Each category emits a flat list of narrow Bash patterns plus the relevant file/network/MCP shapes. The full list lives in `apply-comfort-posture.py` `EMISSIONS` constant. The patterns chosen for v0.1.0 are reproduced below for review.

### File categories

| Category | Patterns |
|---|---|
| `file_read_project` | `Read(**)` |
| `file_edit_project` | `Edit(**)`, `Write(**)`, `MultiEdit(**)` |
| `file_read_global` | `Read(~/**)`, `Read(//**)` † |
| `file_edit_global` | `Edit(~/**)`, `Write(~/**)`, `Edit(//**)` †, `Write(//**)` † |

The path anchors follow Claude Code's documented gitignore-style anchors (see `knowledge/claude-code-permissions.md` §"Read/Edit path anchors"). `/path` anchors at project root, `~/path` at home, `//abs/path` at filesystem root, bare paths default to cwd.

**† Filesystem-root catch-alls are suppressed in the `ask` bucket.** `//**` is anchored at the filesystem root, so it also matches *project-internal* paths. Because Claude Code resolves overlaps as deny > ask > allow, an `ask`-bucket `Read(//**)` would beat the project category's `Read(**)` allow rule and prompt on **every in-project read** (and likewise for edits) — silently defeating `file_read_project: allow`. So when `file_read_global` / `file_edit_global` resolve to the `ask` level, the generator drops the `//**` patterns and lets Claude Code's built-in "ask on any unmatched path" handle genuinely-external reads. The `//**` patterns are still emitted for `allow` levels (where you *want* to auto-approve the whole tree) and `deny` levels. The home anchor `~/**` is kept in all buckets — it doesn't overlap the project. Implemented as `FS_ROOT_CATCHALLS` in `apply-comfort-posture.py`'s `compute_emission()`.

### Shell categories

Each shell category is a curated list of narrow command-prefix patterns. Narrow is essential — broad patterns like `Bash(*)` get silently dropped by auto-mode. See `apply-comfort-posture.py` for the exhaustive lists.

Highlights:
- `shell_readonly` — 30+ patterns covering ls/cat/head/tail/grep/find/git-read/gh-read
- `shell_local_mutate` — mkdir/touch/cp/mv/rm/chmod plus git-local (commit, checkout, stash, restore, reset, merge, rebase)
- `shell_remote_mutate` — git push/fetch/pull + gh pr/issue mutations + npm publish
- `shell_code_exec` — interpreter commands (python, python3, node, deno, bash -c, sh -c, eval, ruby, perl)
- `shell_package_install` — npm/pnpm/yarn/pip/uv/brew/apt/cargo/go install variants

### Network categories

| Category | Patterns |
|---|---|
| `network_read` | `WebFetch`, `Bash(curl:*)`, `Bash(wget:*)` |
| `network_write` | `Bash(curl -X POST:*)`, `Bash(curl -X PUT:*)`, `Bash(curl -X DELETE:*)`, `Bash(curl -X PATCH:*)`, `Bash(gh api PATCH:*)`, `Bash(gh api POST:*)`, `Bash(gh api DELETE:*)`, `Bash(gh api PUT:*)` |

### MCP tools (deferred)

`mcp_tools` is intentionally empty in v0.1.0's `EMISSIONS`. Per-MCP-server trust is configured in Claude Code's user settings (`~/.claude/settings.json`); comfort-posture's `mcp_tools` is a global default that doesn't have a direct one-to-one rule mapping. v0.2.0 should map this to per-server rules once the marketplace has a stable list of MCP servers consumers connect.

### Subagent dispatch (v0.321.4)

| Category | Patterns |
|---|---|
| `subagent_dispatch` | `Agent` (bare — matches every subagent/Task dispatch) |

`allow` emits `"Agent"` into the allow array; `deny` emits `"Agent"` into deny (that disables ALL subagents); `ask` emits `"Agent"` into ask (same prompt Claude Code already uses for an unmatched Agent). A missing key is backward compatible: v3/v4 falls back to `global_default`; v5 treats it as inherit and emits nothing (same as every other category). Per-subagent overrides use `Agent(SubagentName)` via the existing `overrides:` map. Recommended preset is `allow`.

## Overwrite semantics (v0.17.0+)

The script **overwrites** `permissions.allow`, `permissions.ask`, and `permissions.deny` in `.claude/settings.json` with the resolved emission. Non-posture fields (`$schema`, `model`, `env`, `hooks`, `permissions.additionalDirectories`) are untouched.

Why overwrite instead of merge: v0.16.0 used a snapshot-based merge that preserved hand-added rules. In practice that produced **bucket collisions** — the same pattern landing in both `allow` (hand-added) and `ask` (posture). Per Claude Code's precedence (deny > ask > allow), the rule effectively becomes `ask`, silently downgrading the user's intended workflow. Overwrite removes that footgun: the YAML is authoritative; you see what you set.

Implications:
- **Personal overrides go in `.claude/settings.local.json`.** Claude Code merges that file on top of `settings.json`, so anything you put there survives every `/set-posture` run.
- **Hand-edits to `settings.json`'s `permissions.{allow,ask,deny}` are wiped.** If you find yourself wanting to add a rule there, ask whether it belongs in the posture YAML (so the dashboard reflects it) or in `settings.local.json` (personal-only).
- **Stale snapshot files are cleaned up.** If a v0.16.0 `.claude/_comfort-posture-snapshot.json` is present, the script deletes it on first v0.17.0 run.

## Schema v5 — per-layer authoring (v0.18.0+)

v5 lets each category carry **separate levels for the three settings layers** Claude Code merges at runtime. The dashboard's expandable per-layer cards author this; `apply-comfort-posture.py`'s `run_v5()` emits one settings file per active layer.

```yaml
schema_version: 5
security_deny: [ ... ] # floor (unchanged)
categories:
  shell_local_mutate:
    user: allow # one of: allow | ask | deny | inherit
    local: ask
    project: inherit # inherit = emit nothing at this layer
```

| Layer | Settings file | Audience |
|---|---|---|
| `user` | `~/.claude/settings.json` | this machine, all projects (ephemeral in a Codespace) |
| `local` | `.claude/settings.local.json` | this project, just me (gitignored; auto-added to `.gitignore`) |
| `project` | `.claude/settings.json` | the whole team (committed); **always carries the `security_deny` floor** |

Resolution: **deny > ask > allow** across the merged set — the strictest layer wins, so a personal `allow` cannot loosen a team `ask`/`deny` (this is also why putting personal preferences at `project` scope is a footgun the dashboard warns about). The per-layer value vocabulary is the 4-value `allow | ask | deny | inherit`; the `//**`-in-ask suppression (above) applies per layer.

Mechanics:

- **`--scope {user,local,project,all}`** (default `all`) chooses which layer(s) to write; the dashboard's "Save & apply all layers" uses `all`.
- **`--preview-merge`** reads the three files, computes the merged effective posture, and prints it (deny/ask/allow) — the CLI counterpart to the dashboard's effective badges.
- **Per-scope side-cars** (`.claude/.comfort-posture-applied.{local,project}.json`, `~/.claude/.comfort-posture-applied.user.json`) record what we wrote, so emptying a layer in the YAML clears that layer's posture rules on the next apply instead of orphaning them.
- The `security_deny` floor is emitted into the **project** layer only — deny is absolute under the merge, so one copy protects every layer and keeps the shared safety baseline in the shared file.
- **Back-compat:** v3/v4 single-layer postures still run the original single-file `compute_emission` path (project layer only). Only `schema_version: 5` triggers `run_v5()`.
- **Migration note:** there is intentionally NO blocking migration banner — it would halt the dashboard's auto-apply flow. The dashboard handles v4→v5 migration on load (existing levels land on the Local layer).

## Always-on security deny

`security_deny:` is a top-level list in the posture YAML carrying patterns that are **always denied regardless of category levels**. The default list covers `.env` / `.pem` / `credentials*` reads and the most common destructive shell commands (`rm -rf`, `git push --force`, `git reset --hard`, `curl | sh`, `sudo`). Under schema v5 it is emitted into the **project** layer (the committed, always-present floor).

- Add patterns to tighten your security floor.
- Remove patterns only if you have a specific reason — these are the marketplace's recommended security baseline.
- The patterns survive every preset (Recommended, Deny, Ask, Allow) because they live outside `categories:`.

## Hook trust flags (read directly by hooks, NOT translated to settings.json)

Two top-level posture keys carry **trust flags** that hooks read at runtime — they do not become Claude Code permission rules. They control whether the corresponding hook surfaces a first-run / first-use confirmation prompt, or skips straight to its trusting behavior. Both default to `false` (confirm) so an untrusted repo can't auto-execute or auto-allow on the first touch.

| Key | Read by | When `false` (default) | When `true` |
|---|---|---|---|
| `definition_of_done.trusted` | `dod-gate.sh` | First run per session per cmd-hash: deny + stderr `touch <confirm-path>` to authorize | Skip first-run confirm; `bash -c $cmd` runs as before |
| `web_access.trusted` | `guard-web-access.sh` | First WebFetch per domain per session to a YAML-whitelisted host: `permissionDecision: ask` | Skip first-use ask; whitelisted hosts auto-allow as before |

These flags address Codex desktop trust review Findings 1 + 5 (an untrusted YAML edit auto-executing on `Stop` / auto-allowing on `WebFetch`). They are tool-layer trust signals — `security_deny` is still the layer-independent floor.

**Authoring:** in the dashboard, both flags will surface as a single "Trust this repo's YAML for…" toggle per trust surface (UI TBD). For now, hand-edit `comfort-posture.yaml` or copy the documented examples from `templates/comfort-posture-balanced.yaml`.

## Skill-wiring exclusions (v0.319.0+)

`ravenclaude setup --with-plugin <name>` symlinks a plugin's *entire* `skills/` directory into
`.claude/skills/` (`wire_plugin_skills()` in `scripts/ravenclaude`) — every skill's name+description
then gets read by VS Code's native Agent Skills feature and injected into every Copilot Chat/CLI
turn. For a project that only uses part of a wired plugin's skill set, that's fixed overhead with no
opt-out — and it re-materializes on every `setup`/`update`, so a one-off local pruning pass (moving
symlinks out of `.claude/skills/` by hand) is silently undone the next time you update.

`skills.deny_plugins` makes an exclusion **durable across re-wires**, because the wiring step itself
checks it before symlinking a plugin, instead of a separate pass fixing it up afterward:

```yaml
skills:
  deny_plugins:
    - finance
    - web-design
    - frontend-engineering
```

- **Plugin-level only** (not per-skill) — deliberately the smallest scope that solves the observed
  problem; a plugin whose skills are only partially wanted is a case for a narrower `--with-plugin`
  install, not this key.
- **Purely additive.** No `skills:` key, no posture file at all, no `python3`, or a malformed YAML —
  every one of those resolves to "not denied," i.e. today's unchanged full-roster behavior. This can
  only ever narrow what gets wired; it cannot break an install that predates it.
- `ravenclaude-core` itself is never denied by this mechanism regardless of what's listed — it's
  always wired first, unconditionally, before any `--with-plugin` entry is processed.
- To see what a plugin's skills actually cost before deciding to deny it, count/measure
  `.claude/skills/*/SKILL.md` for that plugin's symlinks directly — there's no built-in reporting
  command for this yet (a natural follow-up: a `ravenclaude skills-report` or similar).

## Per-pattern overrides (v0.17.0+)

Each `categories.<name>` value can be either a plain string (level applied to every pattern in the category) or an object with per-pattern overrides:

```yaml
categories:
  shell_readonly: allow             # all patterns: allow
  shell_local_mutate:               # mixed
    default: allow
    overrides:
      "Bash(rm:*)": ask
      "Bash(git reset:*)": ask
```

Resolution precedence (highest wins): per-pattern override > category default > top-level `global_default`. Use overrides to tighten or relax specific patterns within a category without splitting the category itself.

### Per-permission, per-layer overrides (v0.19.0)

Under schema v5 the `overrides:` map keys a permission to a **per-layer object**, so a single permission can be set independently at User / Local / Project — the same `allow | ask | deny | inherit` vocabulary as the category layers, where `inherit` defers to the category-wide layer value:

```yaml
categories:
  shell_remote_mutate:
    user: inherit
    local: ask # the category asks before any remote mutation at my layer …
    project: inherit
    overrides:
      "Bash(git push:*)":
        user: inherit
        local: deny # … but git push is hard-blocked just for me
        project: inherit
```

The dashboard authors this via the per-permission controls inside each category card. Resolution at each layer: per-permission override (non-`inherit`) wins over the category-wide layer value; layers then merge `deny > ask > allow` as usual. See `category_overrides_map()` / `pattern_layer_value()` in `apply-comfort-posture.py`.

The pattern strings must match exactly what `EMISSIONS` in `apply-comfort-posture.py` declares — copy them from the dashboard's per-category list rather than typing freehand.

## Session-mode interactions

Critical context to communicate to users in every run. The script prints this footer:

> Note: comfort-posture works best with session mode at 'default'.
>   - Plan mode and Accept-edits compose fine.
>   - Auto-mode silently drops broad allow rules by design. The rules
>     this script emits are narrow, so most categories survive auto-mode —
>     but expect shell_code_exec and shell_package_install to be partially
>     overridden when auto-mode is on.
>   - bypassPermissions bypasses these rules entirely (use sparingly).

See `knowledge/claude-code-permissions.md` "Permission modes" for the full table.

## When to extend this skill

- **New category** in `dashboard-schema.json` → add an entry to `EMISSIONS` in the Python script AND a row in this skill's category-patterns section.
- **New level** in the YAML schema → update `level_to_bucket()` in the Python script.
- **Time-boxed elevations** (proposal 002 §6.2) → add an `elevations:` block parser to the Python script; remember to expire.
- **Per-MCP-server trust** → add a new section to `EMISSIONS` and to the dashboard schema; emit `mcp__<server>__*` rules.

Each extension should:
1. Update the Python script's `EMISSIONS` table.
2. Update this skill's tables to match.
3. Add a row to the dashboard's category list if user-visible.
4. Test by hand (`--dry-run` on a sample YAML).

## See also

- `commands/set-posture.md` — the slash-command entry that invokes the script.
- `scripts/apply-comfort-posture.py` — the implementation.
- `dashboard-schema.json` — the YAML shape this consumes.
- `knowledge/claude-code-permissions.md` — the permission model these rules feed into.
- `docs/proposals/2026-05-22-002-comfort-posture-mechanism.md` — the design proposal that motivated this skill.

Attribution

mcorbett51090mcorbett51090
View sourceSee grades on GitHubMore from mcorbett51090 →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698461 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →