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§
- Trust
Surface - 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. Transcribescrate::permissions::default_approval_store, which itself transcribescrate::checkpoint’sdefault_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.