docs(skills): permission-denial safety rail (#882 partial) #925

Merged
reviewer merged 1 commit from fix/882-skills-safety-rail into main 2026-05-07 17:38:28 +00:00
Collaborator

Summary

Append a "Permission denials" paragraph to every dispatched skill body so an in-container agent that hits a permission-denied or schema error doesn't reach for harness-config skills (Skill, update-config, fewer-permission-prompts, …) as an escape hatch. Those skills mutate host-side ~/.claude/settings.json — the agent's policy comes from allowedTools fixed at SDK boot, so host edits are no-ops mid-session and the agent loops trying to "fix" its perms, burning the dispatch.

Two surfaces:

  • skills/*.md — every dispatch entry-point gets the paragraph appended. Catches the filesystem-fallback path and any future re-seed of agent_skill.
  • 0006_skill_safety_rail.sql — idempotent migration that appends the same paragraph to existing rows in agent_skill whose body doesn't already carry the heading. Runtime reads DB first (resolveSkillBody), so without this the rail wouldn't reach an already-seeded fleet.

Skills covered: implement / implement-delta, review / review-delta, rebase, fix-ci, breakdown, address-review / address-review-delta, plus the four design-* siblings. Appendix-style files (artifact-style.md, caveman.md) deliberately untouched.

Test plan

  • just qa — typecheck + Biome + 3263 server tests pass
  • Migration is idempotent (AND body NOT LIKE '%## Permission denials%') — re-running is a no-op
  • Boot the service post-merge: migration runner picks up 0006_skill_safety_rail.sql and updates the 22 seeded rows in one pass

Out of scope (#882 stays open)

  • Vendoring security-guidance / typescript-lsp / claude-md-management into plugin-fixtures/. Currently no plugins / marketplaces registered in the DB, so the original symptom (full upstream catalog visible in skill_listing) is dormant — rail is cheap defensive coverage either way.

Closes #882 (partial — the safety-rail companion change; vendoring left for a follow-up).

## Summary Append a "Permission denials" paragraph to every dispatched skill body so an in-container agent that hits a permission-denied or schema error doesn't reach for harness-config skills (`Skill`, `update-config`, `fewer-permission-prompts`, …) as an escape hatch. Those skills mutate host-side `~/.claude/settings.json` — the agent's policy comes from `allowedTools` fixed at SDK boot, so host edits are no-ops mid-session and the agent loops trying to "fix" its perms, burning the dispatch. Two surfaces: - **`skills/*.md`** — every dispatch entry-point gets the paragraph appended. Catches the filesystem-fallback path and any future re-seed of `agent_skill`. - **`0006_skill_safety_rail.sql`** — idempotent migration that appends the same paragraph to existing rows in `agent_skill` whose body doesn't already carry the heading. Runtime reads DB first (`resolveSkillBody`), so without this the rail wouldn't reach an already-seeded fleet. Skills covered: `implement` / `implement-delta`, `review` / `review-delta`, `rebase`, `fix-ci`, `breakdown`, `address-review` / `address-review-delta`, plus the four `design-*` siblings. Appendix-style files (`artifact-style.md`, `caveman.md`) deliberately untouched. ## Test plan - [x] `just qa` — typecheck + Biome + 3263 server tests pass - [x] Migration is idempotent (`AND body NOT LIKE '%## Permission denials%'`) — re-running is a no-op - [x] Boot the service post-merge: migration runner picks up `0006_skill_safety_rail.sql` and updates the 22 seeded rows in one pass ## Out of scope (#882 stays open) - Vendoring `security-guidance` / `typescript-lsp` / `claude-md-management` into `plugin-fixtures/`. Currently no plugins / marketplaces registered in the DB, so the original symptom (full upstream catalog visible in `skill_listing`) is dormant — rail is cheap defensive coverage either way. Closes #882 (partial — the safety-rail companion change; vendoring left for a follow-up).
docs(skills): permission-denial safety rail (closes #882 partial)
All checks were successful
qa / sql-layer-check (pull_request) Successful in 15s
qa / dockerfile (pull_request) Successful in 15s
qa / db-schema (pull_request) Successful in 38s
qa / qa-1 (pull_request) Successful in 1m45s
qa / qa (pull_request) Successful in 0s
36920af0f8
Append a "Permission denials" paragraph to every dispatched skill body
so an in-container agent that hits a permission-denied or schema error
doesn't reach for harness-config skills (`Skill`, `update-config`,
`fewer-permission-prompts`, …) as an escape hatch. Those skills mutate
host-side `~/.claude/settings.json` — the agent's permission policy
comes from `allowedTools` fixed at SDK boot, so host file edits are
no-ops mid-session and the agent loops trying to "fix" its perms,
burning the dispatch (#881 / #882 reproducer).

Reach the runtime via two surfaces:

- `skills/*.md` — every dispatch entry-point (`implement` /
  `implement-delta`, `review` / `review-delta`, `rebase`, `fix-ci`,
  `breakdown`, `address-review` / `address-review-delta`, plus the
  four `design-*` siblings) gets the paragraph appended. Catches the
  filesystem-fallback path and any future re-seed of `agent_skill`.

- `0006_skill_safety_rail.sql` — idempotent migration that appends the
  same paragraph to existing rows in the `agent_skill` table whose
  body doesn't already carry the heading. Runtime reads the DB body
  first (`resolveSkillBody`), so without this the rail wouldn't reach
  any already-seeded fleet.

Out of scope (still open in #882): vendoring `security-guidance` /
`typescript-lsp` / `claude-md-management` into `plugin-fixtures/`.
Currently no plugins / marketplaces are registered in the DB, so the
original symptom (full upstream catalog visible in `skill_listing`) is
dormant — but the rail is cheap defensive coverage either way.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
reviewer approved these changes 2026-05-07 17:38:18 +00:00
reviewer left a comment

Safety-rail paragraph correct and consistent between .md files and SQL migration. Idempotency guard (AND body NOT LIKE '%## Permission denials%') is sound. *-delta variants included as extras — strictly better than the AC minimum.

Safety-rail paragraph correct and consistent between `.md` files and SQL migration. Idempotency guard (`AND body NOT LIKE '%## Permission denials%'`) is sound. `*-delta` variants included as extras — strictly better than the AC minimum.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!925
No description provided.