Skip to main content

Module trust

Module trust 

Source
Expand description

BP-10 (COMPOSABLE-HARNESS-DESIGN.md §2 module 14 trust, catalog row “Project/workspace trust gate”): the workspace-trust DECISION — the prompt, its per-project persistence, and the three surfaces it gates.

§What was missing, and what this is

[capabilities.trust] already existed and already bit: config-declared plugin code was refused unless default = "always", and a project-local config file was stripped of the forbidden capability tables. What did not exist was the PROMPT the row is named for — both parity presets ship default = "ask", and with nothing anywhere consuming crate::plugins::TrustDecision::Ask that value resolved exactly like never. This module is that consumer.

§One engine, one door

A trust question is an crate::permissions::ApprovalRequest on the SAME crate::permissions::PermissionsApprovalHandler every other Ask in this crate is answered on — tool "trust", subject the project root, raw_args naming what is about to be loaded. There is no second prompt type, no second handler trait, and no second cache.

The door is installed on crate::Config::trust_handler rather than on Agent (where crate::Agent::set_permissions_approval_handler puts the tool-dispatch door), for one structural reason: every surface trust gates — the system prompt’s project instruction tier, plugin registration, the CLI’s [hooks] wiring — is decided BEFORE or DURING Agent construction, so a handler installed after construction would always arrive too late to be asked. Config is the artifact that exists first.

§Persisted, per project, and reversible

An answer of “yes, and don’t ask again” is written to $SUPERCODE_HOME/trust/<project_tag>.json — the same $SUPERCODE_HOME-derived, crate::checkpoint::project_tag-keyed layout crate::checkpoint’s shadow store and crate::permissions::default_approval_store both use, so a project’s records sit together. Deleting that file (or calling revoke) forgets the decision and the next load asks again. The file IS the state; there is no second copy.

§What happens with NO door installed, stated per surface

Fail-closed means different things for code and for text, and this module does not pretend otherwise:

The rule is one sentence: with no door, every surface resolves to its PRE-BP-10 outcome. Plugin code is refused (crate::plugins::is_trusted has always demanded an explicit always); lifecycle hooks are installed and project instruction files are loaded (neither was ever gated). A new gate must not change what an existing configuration does when there is nobody to ask — it must change what happens when there IS. An explicit default = "never" refuses all three regardless.

That per-surface answer is the point of TrustSurface: the gate is one decision, but each surface declares what “nobody answered” means for it, instead of one blanket answer quietly being wrong for two thirds of the callers.

Enums§

TrustSurface
What is being loaded, and therefore what an unanswerable trust question means for it — see this module’s doc comment.

Functions§

default_trust_store
The default per-project trust store for cwd$SUPERCODE_HOME/trust/<project_tag>.json. Transcribes crate::permissions::default_approval_store, which itself transcribes crate::checkpoint’s default_shadow_root: one layout for a project’s records, not three.
is_trusted
BP-10: is this workspace trusted to load surface?
revoke
BP-10: forget this project’s recorded trust decision — the reversibility half. The next load asks again.