/** * The reviewable project record (`settings.json` since ADR-0076 PR 3c) — and what `init` refuses to put in it. * * Split out of `init.ts` when ADR-0029's grant-width rule pushed that file past the 400-line ceiling and * `test/file-size.test.ts` refused it. The seam is the natural one: `init.ts` decides *what is true about * the installed packages*, this file decides *how that is presented to a human for review*. * * **ADR-0029.** `init` used to emit the union of every declared ceiling as a live grant. A critic's reading * killed it in one sentence: the handoff's safety argument for a third party authoring `allowed-tools` is * that *"the operator's `PI_DADDY_GRANT` still bounds it"* — and a generated union makes the bound and the * bounded have the same author, who is not the operator. So capabilities that can change a machine are * emitted **commented**, with the definitions that need them named. `init` + `source` yields a working * read-only setup; the wide ones cost one deliberate uncomment. * * That is a decision about the **starting grant**, which is a stronger act than choosing a ceiling and is * why it needed its own ADR rather than a paragraph in ADR-0028. */ import { type Capability } from "./resolve.ts"; /** * Capabilities `init` will never put LIVE in a generated grant. * * **This list is a judgement, and it is written down in one place so it can be argued with** — which is the * whole reason ADR-0029 exists. The rule behind it: a capability that can *change the machine* or *execute* * does not become live because a package asked for it. Everything else (reading, searching, listing) does. * * - `DEFAULT_GATED` — whatever a governed session already asks a human about. Today `tool:bash`, and taking * it from there rather than restating it means the two cannot drift apart. * - `tool:write`, `tool:edit`, `tool:edit-diff` — mutate the working tree. They used to be named here because * they were NOT gated, so a source-and-go operator handed them to a child with no dialog at all, which is * what made "the union is mitigated by gating" untrue (R-76). They joined `DEFAULT_GATED` on 2026-09-23, * so that gap is closed and this entry is now redundant with the line above rather than load-bearing. It * is kept because the set must not silently follow a future change to the gate list: what `init` withholds * and what a session asks a human about are two decisions that happen to agree today. * - `UNIVERSAL_CAPABILITIES` — confer the whole catalog by measurement (probe `pi-fabric-eval`). * `assertNarrowing` refuses a grant containing one anyway; leaving it out of the file keeps the operator * from ever holding it by accident. */ export declare const WITHHELD_BY_DEFAULT: readonly Capability[]; /** Would `init` put this capability in the live grant? */ export declare function isLiveByDefault(capability: Capability): boolean; export declare class UnsafeGrantError extends Error { } /** Throw rather than write a grant string that could mean something to a shell. */ export declare function assertGrantIsWritable(grant: Capability[]): void; /** One definition's declared ceiling, as far as the grant file is concerned. */ export interface GrantEnvSkill { name: string; ceiling: Capability[]; /** Present when the definition cannot be spawned at all; the string is why, for the reader. */ unspawnable?: string; } export interface GrantEnvInput { skills: GrantEnvSkill[]; /** Capabilities emitted live. */ live: Capability[]; /** Withheld capability → the definitions that declared it. Emitted commented, for a deliberate uncomment. */ withheld: Map; /** Definitions whose `agent:` id is withheld because they need a withheld capability. */ withheldDefinitions: string[]; /** `workspace:` ids this project could route to (ADR-0035). Rendered commented, never granted. */ routableWorkspaces?: Capability[]; /** `agent:` ids a ceiling names that `init` did not write here. Reported, never granted. */ crossReferences: { from: string; capability: Capability; }[]; cautions: string[]; } /** * Render the file. * * Every capability is annotated with the definition it came from, because the whole claim of this feature is * that the capability decision is visible and diffable. A grant nobody can read is a grant nobody reviews. */ /** * Render `.pi/pi-daddy/settings.json`, the reviewable, committable record of a project's ceiling (ADR-0076 PR 3c). * * It replaced `.pi/grants.env`, which was never machine-read: the root grant comes from the user-level grant * store (ADR-0037), and the shell file existed so a human could read and diff the capability decision. That * purpose is kept as data: every capability is annotated with the definition it came from, withheld * capabilities and definitions are listed with their reasons, and nothing here is advice dressed as a value. * `/grants` renders it; PR 6 adds the advisor toggles beside it. */ export interface ProjectSettings { version: 1; writtenBy: "pi-daddy init"; /** How to read this file, for the human who opens it in a diff. */ review: string; /** The live grant: what `pi-daddy init` found declared and did not withhold. Delete an id to withhold it. */ grant: Capability[]; definitions: { name: string; declares: Capability[]; spawnable: boolean; reason?: string; }[]; /** Withheld by default (ADR-0029) → the definitions that declared each. Never granted by init. */ withheld: { capability: Capability; declaredBy: string[]; }[]; /** Definitions whose `agent:` id is withheld because they need a withheld capability. */ withheldDefinitions: string[]; /** `workspace:` ids this project could route to (ADR-0035). Listed, never granted. */ routableWorkspaces: Capability[]; /** `agent:` ids a ceiling names that init did not write here. Reported, never granted. */ crossReferences: { from: string; capability: Capability; }[]; cautions: string[]; /** The project ledger file name under `.pi/pi-daddy/`; init enables it (ADR-0037). */ ledger: string; /** Gated by default (ADR-0012): closed under subsumption, so gating tool:write also gates tool:bash. */ gatedByDefault: Capability[]; } export declare function buildProjectSettings(input: GrantEnvInput): ProjectSettings; export declare function renderProjectSettings(input: GrantEnvInput): string; /** The capability that must always be live, or the generated file is inert (S-5). */ export declare const ALWAYS_LIVE: Capability; //# sourceMappingURL=grant-env.d.ts.map