Skip to content

RFC: per-package permissions - #36

Draft
zkochan wants to merge 8 commits into
mainfrom
rfc/per-package-permissions
Draft

zkochan wants to merge 8 commits into
mainfrom
rfc/per-package-permissions

Conversation

@zkochan

@zkochan zkochan commented Sep 11, 2026 •

Copy link
Copy Markdown
Member

allowBuilds records which packages may run lifecycle scripts. It is the first of a family: a package can now also ship agent skills, and MCP servers are the obvious next case. Each new capability otherwise means another top-level setting with the same shape, the same lifecycle, its own approval command and its own line of install output.

permissions:
  esbuild:
    build: true
  drizzle-kit:
    build: true
    skills: true

allowBuilds folds in as the build capability, reusing the legacy-clearing write that already handles onlyBuiltDependencies.

Scope rule: permissions holds capability grants, not content modifications. The general test, now that pnpm has two grouping shapes, is which question a setting answers. Package-major, like this field, for facts about a package: "what may esbuild do" is a question about esbuild. Feature-major, like the update: and audit: sections, for parameters of a feature that happen to name packages: "why is @babel/* not being delayed" is a question about the release-age check. That also explains the key shapes — a permission is granted to a package identity somebody reviewed, so keys are exact, while a policy exemption covers a class of packages, so keys are globs.

One pending set, one section, one command. A single install produces one list of packages awaiting approval, keyed by package rather than split per capability, and pnpm permissions approve — aliased to pnpm approve — resolves all of it. pnpm approve-builds and pnpm ignored-builds remain as build-filtered aliases, but as compatibility surface rather than a pattern new capabilities extend. This replaces the Ignored build scripts: wording, which describes the wrong thing for a skill; ERR_PNPM_IGNORED_BUILDS keeps its code.

Why now rather than later: if the skills capability ships as allowSkills first, a consolidation migrates two settings instead of one.

Left open deliberately:

  • minimumReleaseAgeExclude and trustPolicyExclude are deliberately not folded in — they fail the test above — but they have their own consolidation waiting: a feature-major minimumReleaseAge: { minutes, exclude, excludePrune }, which also puts the prune flag next to what it prunes. Separate and smaller than this RFC.
  • Whether strictDepBuilds generalises. A skipped build script can break an install; an unapproved skill only means an agent does not receive it, so the same severity may not be warranted.

Related: the agent skills RFC (pnpm/rfcs PR 35) depends on this and defines the skills capability.


Written by an agent (Claude Code, claude-opus-5).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Bm9EF4jd7FuyxUH7UkCZ3a

Replace allowBuilds and the family of per-capability settings that would
follow it with a single package-keyed permissions field, holding
capability grants but not content modifications.

allowBuilds folds in as the build capability, using the legacy-clearing
write that already handles onlyBuiltDependencies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bm9EF4jd7FuyxUH7UkCZ3a
@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

zkochan and others added 7 commits September 11, 2026 16:10
Denials are the majority of what an approval writes, so a list of
granted capabilities cannot express the common case without an escape
character that collides with YAML tag syntax.

Block style rather than flow so that granting a permission is an added
line in review, not a rewritten entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bm9EF4jd7FuyxUH7UkCZ3a
State that per-capability commands are compatibility surface, not a
pattern new capabilities extend, and that the shared prompt dispatches
per capability afterwards.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bm9EF4jd7FuyxUH7UkCZ3a
One install produces one pending set, so it gets one section keyed by
package. Replaces the Ignored build scripts wording, which describes the
wrong thing for a skill, while ERR_PNPM_IGNORED_BUILDS keeps its code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bm9EF4jd7FuyxUH7UkCZ3a
pnpm already qualifies approval by what is approved, as stage approve
does, so a bare pnpm approve would be the only unqualified one. Keep the
verb and add the namespace.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bm9EF4jd7FuyxUH7UkCZ3a
The namespace keeps listing and approval together, but the approval
prompt is the most-travelled path and should not be longer to type than
the approve-builds it replaces.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bm9EF4jd7FuyxUH7UkCZ3a
Give the scope rule a general test: package-major for facts about a
package, feature-major for parameters of a feature that name packages.
That settles the policy exemptions, which want a minimumReleaseAge
section rather than a place in permissions.

Also state that a grant is written before its action runs, and that a
failing action fails the command without rolling it back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bm9EF4jd7FuyxUH7UkCZ3a
Settles the open question: a pending grant appears in the shared
section without failing the install, and strictDepBuilds stays specific
to build scripts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bm9EF4jd7FuyxUH7UkCZ3a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant