> For the complete documentation index, see [llms.txt](https://hub.bsvblockchain.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hub.bsvblockchain.org/brc/wallet/0179.md).

# Signed Capability Manifest for Wallet and Tool-Server Method Exposure

RexStarBSV (<RexStarBSV@protonmail.com>)

## Abstract

This BRC defines a **capability manifest**: a declarative, risk-tiered, operator-gated document that enumerates *exactly which* SDK methods and tool-server (MCP) methods a wallet or wallet-adjacent product exposes, together with a runtime **enforcer** that refuses any method not affirmatively declared and enabled. Each exposed method is a **Capability** with a globally-unique id of the form `product.surface.method`, a **risk tier** drawn from an ordered taxonomy (`READ`, `VERIFY`, `OPS`, `CRYPTO`, `IDENTITY`, `NETWORK`, `SPEND`, `ADMIN`), and an optional operator **allow-overlay**. Read/verify tiers are exposed by default; every tier that mutates state, uses a key, moves value, asserts identity, or reaches the network is withheld by default until an operator affirmatively allows it. The set of `(id, tier, effective-enabled)` triples is reduced to a domain-separated SHA-256 **fingerprint** that is stable under documentation edits but changes the instant a capability is added, re-tiered, or toggled. That fingerprint is baked into the build as a **pin**: at construction the enforcer refuses to run if the loaded manifest does not fingerprint to the pin, so a swapped or edited manifest file cannot widen the exposed surface at runtime; Section 9 states precisely what that does and does not cover. Decisions are **fail-closed**: an undeclared method is denied, never silently allowed. Where BRC-100 governs *per-session* application requests and BRC-103/104 govern *who is calling*, this specification governs the orthogonal supply-side axis (*which methods are callable at all*) and it is designed to be sealed by a content-anchor code-provenance ordinal.

## Motivation

The BSV wallet-interface stack answers three questions well and one question not at all.

* **BRC-100** (Wallet-to-Application Interface) standardizes the *request/permission* surface: an application asks the wallet to `createAction`, `createSignature`, `getPublicKey`, etc., and the wallet may prompt the user per session/basket/protocol. This governs what a *given counterparty* is permitted to ask *at request time*.
* **BRC-103 / BRC-104** (Peer-to-Peer Mutual Authentication and Certificate Exchange, and its HTTP transport) govern *identity of the caller*, mutual authentication and certificate presentation so the wallet knows *who* is on the other end of the connection.

None of these answer the **supply-side** question: *of the entire method surface a wallet SDK or an agent/MCP tool-server compiles in, which methods are exposed at all, and how does an operator see, scrutinize, and withhold individual methods before shipping?* In practice an MCP server or SDK ships with a large method table; a new method added to the server is live the moment it is registered. BRC-100 will still prompt for it, and BRC-103 will still authenticate the caller, but neither the operator nor a downstream auditor has a signed, machine-checkable statement of the exact exposed set, nor a mechanism that makes *"this build exposes exactly these methods and no others"* tamper-evident. This is acute for **autonomous agent wallets and tool-servers**, where the caller is software, spend authority is delegated under policy, and "which tools the agent can even reach" is a primary containment boundary.

This BRC fills that gap. It is deliberately *complementary*, not competing: the manifest is consulted **before** BRC-100 permissioning and BRC-103 authentication run, if a method is not in the manifest and enabled, the call is refused before any session or identity logic executes. The fingerprint is designed to be the value a build's code-provenance seal commits to, so that widening the surface necessarily changes the build's published fingerprint. It pairs with a content-anchor code-provenance ordinal (the running-code-fingerprint-as-ordinal principle): a build's seal is minted over `build_identity || manifest_fingerprint`, making surface-widening publicly evident.

## Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as in RFC 2119.

### 1. Terminology

* **Capability**: one exposed SDK method or tool-server method, described by a record (Section 3).
* **Manifest**: the complete declared set of Capabilities for a build, plus header fields (Section 6).
* **Effective-enabled**: the resolved boolean exposure state of a Capability after applying the operator overlay to the tier default (Section 5).
* **Fingerprint**: the domain-separated SHA-256 over the trust-bearing projection of the manifest (Section 7).
* **Pin**: a fingerprint value fixed into a build against which the loaded manifest is checked (Section 9).
* **Enforcer**: the runtime object that renders and enforces per-Capability decisions (Sections 10-11).

### 2. Domain constant

Implementations MUST use the exact domain-separation string:

```
bsv-capability-manifest/v1
```

This value is denoted `DOMAIN` below. It appears both as the manifest `schema` field (Section 6) and inside the fingerprint preimage (Section 7). A manifest whose `schema` is not byte-equal to `DOMAIN` MUST be rejected at load.

### 3. Capability record

A Capability is the tuple of fields in the table below. Fields are marked *trust-bearing* if they participate in the fingerprint (Section 7); the rest are documentation.

| Field         | Type            | Required            | Trust-bearing                | Meaning                                                                                                  |
| ------------- | --------------- | ------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------- |
| `id`          | string          | yes                 | **yes**                      | Globally-unique id, MUST equal `product.surface.method` (Section 4).                                     |
| `product`     | string          | yes                 | no (bound via `id`)          | Owning product, e.g. `wallet`, `marketplace`, `messaging`, `content-anchor`, `signer`, `media`.          |
| `surface`     | string          | yes                 | no (bound via `id`)          | The SDK or tool-server surface, e.g. `agent-mcp`, `wallet-connect`, `marketplace-mcp`, `messaging-core`. |
| `method`      | string          | yes                 | no (bound via `id`)          | The exposed method / tool name.                                                                          |
| `tier`        | enum            | yes                 | **yes**                      | One of the risk tiers in Section 5.                                                                      |
| `description` | string          | no (default `""`)   | **no**                       | Plain-language description. Documentation only.                                                          |
| `grounded_in` | string          | no (default `""`)   | **no**                       | Repo-relative file(s) proving the method exists. Documentation only.                                     |
| `allow`       | boolean or null | no (default `null`) | indirectly (via `effective`) | Operator override: `true` = expose, `false` = withhold, `null` = use tier default.                       |

Note the deliberate design: `product`, `surface`, and `method` are individually non-trust-bearing because their concatenation `id` is trust-bearing and is checked to equal them (Section 4); `description` and `grounded_in` are **never** trust-bearing (Section 7.3); and `allow` influences the fingerprint only through the derived **effective** boolean (Section 5), so two manifests that resolve to the same effective exposure fingerprint identically regardless of whether exposure came from an explicit `allow:true` or a tier default.

### 4. Capability id grammar

The `id` MUST be exactly the three dot-joined components:

```
id = product "." surface "." method
```

An implementation constructing or loading a Capability MUST reject it (with a structural error) if `id` is not byte-equal to the string formed by joining `product`, `surface`, and `method` with `.`. This makes the id self-describing and prevents a manifest from labeling a capability with a misleading id. Components SHOULD be treated as opaque tokens, but their character set is constrained: every component MUST consist solely of printable ASCII (U+0020 to U+007E), and an implementation MUST reject an `id` containing any other character. Implementers SHOULD additionally avoid embedding `.` inside a component to keep the id parseable back into its three parts. The ASCII restriction is not decoration, and it is what makes two statements elsewhere in this document true. Section 7.2 escapes non-ASCII as `\uXXXX` and emits ASCII bytes while RFC 8785 JCS emits raw UTF-8, so the two canonicalizations agree on every id this grammar admits and cannot disagree on one it does not. And because §7.2 specifies no Unicode normalization, a non-ASCII id would let NFC and NFD variants of one visually identical name be two distinct ids under the uniqueness rule below, declared with different `allow` values and producing two fingerprints that no reviewer could tell apart by eye. Restricting the character set removes both hazards rather than adding two more rules to §7.2. Within a single manifest every `id` MUST be unique; a duplicate id MUST be rejected at construction.

### 5. Risk-tier taxonomy and default-exposure rule

There are exactly eight tiers, in this canonical order from least to most sensitive:

```
READ, VERIFY, OPS, CRYPTO, IDENTITY, NETWORK, SPEND, ADMIN
```

| Tier       | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | Default exposure |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
| `READ`     | Read-only data (balances, listings, history, chain tip).                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | **on**           |
| `VERIFY`   | Pure verification, no keys, no state mutation, no network.                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | **on**           |
| `OPS`      | Mutates persistent state without creating or broadcasting an outgoing value-moving action. Membership is heterogeneous and MUST be reviewed per capability, not inferred from the tier name: in the reference inventory four of the five members write local management state (triage items, status advancement, checklist sign-offs), while the fifth is the money-in path, which derives a wallet private key and credits the spendable default basket. Implementers MUST NOT assume this tier is free of keys or of value. | **off**          |
| `CRYPTO`   | Uses a key to sign / HMAC / encrypt / decrypt.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | **off**          |
| `IDENTITY` | Issue / prove / relinquish certificates, reveal key linkage.                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | **off**          |
| `NETWORK`  | Triggers outbound network (broadcast, relay, fetch-by-id, onion connect).                                                                                                                                                                                                                                                                                                                                                                                                                                                     | **off**          |
| `SPEND`    | Creates or broadcasts a value-moving action.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | **off**          |
| `ADMIN`    | Configuration / operator / webhook-registration surfaces.                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | **off**          |

The **default-exposure rule** is: a tier is on-by-default **iff** it is in the set `{READ, VERIFY}`. All other tiers are off-by-default. Formally:

```
default_enabled(tier) = tier ∈ {READ, VERIFY}
```

An implementation MUST reject a Capability whose `tier` is not one of the eight listed values. The tier ordering is normative and is used by tooling for grouping and for tier-scoped overlay selectors (Section 12); it does not by itself imply that a higher tier is "more denied", every off-by-default tier is equally off until the operator allows it.

### 6. Manifest document format

A serialized manifest is a JSON object with these fields:

| Field              | Type   | Required               | Meaning                                                                                                                                                   |
| ------------------ | ------ | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `schema`           | string | yes                    | MUST equal `DOMAIN` (Section 2); else reject.                                                                                                             |
| `manifest_version` | string | no (default `"0.0.0"`) | Human version of the inventory. Not fingerprinted.                                                                                                        |
| `note`             | string | no (default `""`)      | Free-text note. Not fingerprinted.                                                                                                                        |
| `fingerprint`      | string | no                     | If present, MUST equal the recomputed fingerprint (Section 8); else reject as tampering.                                                                  |
| `capabilities`     | array  | yes                    | Array of Capability records (Section 3), each serialized with fields `id`, `product`, `surface`, `method`, `tier`, `allow`, `description`, `grounded_in`. |

A Capability row missing any of the required fields `id`, `product`, `surface`, `method`, `tier` MUST cause a load error. `description`, `grounded_in`, and `allow` MAY be omitted and default to `""`, `""`, and `null` respectively. The `manifest_version` and `note` fields are metadata and MUST NOT influence the fingerprint.

### 7. Canonical fingerprint

The fingerprint is the single value that certifies "this build exposes exactly these capabilities." It is computed over a **trust-bearing projection** only.

#### 7.1 Per-capability projection

For each Capability, form the object with exactly these three keys:

```
{ "id": <id>, "tier": <tier>, "enabled": <effective-enabled> }
```

where `effective-enabled` is resolved per Section 5:

```
effective(cap) = default_enabled(cap.tier) if cap.allow is null
 = bool(cap.allow) otherwise
```

`enabled` is a JSON boolean. No other field of the Capability appears.

The Required column of Section 3 describes the **record**, which always carries every field once constructed. Section 6 governs the **document**, where `description`, `grounded_in` and `allow` MAY be omitted and default to `""`, `""` and `null`. The two are not in tension: a document may leave them out, and the record that results still has them. An implementation whose record type makes them mandatory arguments is conformant, provided its document parser supplies the defaults.

`allow` is a JSON boolean or `null`, and an implementation MUST reject any other value as a structural error (Section 13) rather than coercing it. The effective-state rule resolves a non-null `allow` by truthiness, so a value such as the JSON string `"false"` would resolve to **enabled**, exposing the capability that whoever wrote it plainly meant to withhold. The fingerprint would then record `enabled: true` faithfully, so the mistake is invisible to an auditor comparing fingerprints and survives every downstream check. Reject at load.

#### 7.2 Assembly and canonicalization

1. Sort the Capabilities by `id` in ascending **Unicode code point** order. Code point order and UTF-8 byte order agree, so either may be used to implement it. UTF-16 code unit order does NOT agree and MUST NOT be used: it places characters above U+FFFF before those in U+E000 to U+FFFF, which a language whose default string comparison is over UTF-16 code units will do silently.
2. Build the list `body` of per-capability projection objects, in that sorted order.
3. Build the preimage object:

```
{ "domain": DOMAIN, "capabilities": body }
```

4. **Canonicalize** the preimage to a string by serializing as JSON with: keys sorted ascending at every object level, no insignificant whitespace (item separator `","`, key/value separator `":"`), and all non-ASCII characters `\uXXXX`-escaped (ASCII-only output). Three further rules are REQUIRED, because each is a degree of freedom that changes the digest and each has a common serializer that chooses the other way:
   * The solidus `/` is **NOT** escaped. `DOMAIN` contains one, so it appears in every preimage ever computed, and a serializer that escapes it by default produces a different fingerprint for every manifest in existence rather than only for unusual inputs.
   * Hexadecimal digits in a `\uXXXX` escape are **lowercase**.
   * A character above U+FFFF is escaped as the **UTF-16 surrogate pair**, two `\uXXXX` escapes. A six-digit or `\U`-style escape is not this format. Under this canonicalization the outer object serializes with keys in the order `capabilities`, `domain`, and each projection object serializes with keys in the order `enabled`, `id`, `tier`.
5. Encode the canonical string as ASCII bytes and compute `SHA-256`. The fingerprint is the lowercase hex digest.

Only JSON strings and booleans appear in the preimage, so the canonicalization is unambiguous without a number-formatting rule; implementations that use a different canonical-JSON library MUST reproduce the exact byte sequence described here (this is the specific form emitted by a sorted-keys, tight-separator, ASCII-escaped JSON serializer, it is *not* required to be RFC 8785 JCS. The two agree on any preimage whose capability ids are ASCII, which is every id in the reference inventory, and they **disagree** when an id contains non-ASCII: JCS emits raw UTF-8 and does not escape, while this canonicalization is ASCII-only. Section 4 permits non-ASCII ids, so an implementation MUST follow the rules above rather than delegate to a JCS library.)

#### 7.3 What the fingerprint covers and deliberately excludes

* **Covered (any change re-fingerprints):** adding a capability, removing a capability, changing a capability's `id`, changing a capability's `tier`, and any change to a capability's `effective-enabled` (whether caused by an `allow` toggle or, indirectly, by a tier default).
* **Deliberately excluded (changes do NOT re-fingerprint):** `description`, `grounded_in`, `manifest_version`, `note`, and the distinction between "enabled by tier default" vs "enabled by explicit `allow:true`". Descriptions and file references are documentation and are **not trust-bearing**; an implementation MUST NOT let them influence the fingerprint. This is a security property: an auditor comparing two builds by fingerprint is comparing *exposed behavior*, and cannot be misled by prose, nor forced to re-mint a provenance seal for a wording fix.

The consequence, called **update coupling**: a build's SDK/tool-server contract version is a function of the capability fingerprint, not of the application version. An app update forces a manifest + provenance-seal re-mint **iff** it moves the fingerprint. The fingerprint is the machine test for "did the exposed contract change."

### 8. Load-time integrity

When loading a serialized manifest:

1. Reject if `schema` != `DOMAIN`.
2. Parse every Capability row, enforcing the id-grammar (Section 4), the tier check (Section 5), and uniqueness of ids.
3. Recompute the fingerprint (Section 7).
4. If the document carries a `fingerprint` field, it MUST byte-equal the recomputed value; otherwise the load MUST fail (a stored fingerprint disagreeing with its own body is tampering and MUST be caught at load).

### 9. Build-pin enforcement

The runtime enforcer is constructed with a `pinned_fingerprint` value fixed by the build rather than derived from the manifest it is handed. An implementation MUST embed it in the build artifact and MUST NOT read it from any runtime-mutable source in a production build. A build MAY permit it to be overridden at run time **only** for a review or testing harness, on the same terms as the null pin below, and such an override MUST be reported on startup, because a pin nobody can see changing is not a pin. The two cases are stated with the same force deliberately: a runtime-supplied pin and a null pin defeat the check identically, since an enforcer that recomputes the fingerprint of the manifest it was handed and compares it to a value supplied beside that manifest is verifying nothing.

* At construction the enforcer MUST recompute the fingerprint of the manifest handed to it and, if `pinned_fingerprint` is non-null and does not byte-equal the recomputed fingerprint, MUST refuse to construct (raise a pin error). **The guarantee this provides, stated precisely.** The only manifest an enforcer will run is one that fingerprints to the pinned value, so a swapped or edited manifest file cannot widen the exposed surface. That is the whole of it, and the threat it answers is a caller of the exposed surface, which controls neither the host nor the build.

It is **not** a guarantee against an attacker who already controls the host. Whoever can set the environment or edit the source that carries the pin can re-pin to a widened manifest, and no check inside the process can prevent that: the process would be verifying itself with a value the attacker chose. An implementation MUST NOT describe this mechanism as protection against host compromise. Against that threat the anchor has to be outside the build, an independently published fingerprint of the running artifact that a third party can compare, which Section 14 describes and this section deliberately does not claim to be.

* A `pinned_fingerprint` of null disables the check. Implementations MUST support this **only** for review/testing harnesses and MUST NOT ship a production build with a null pin.

**A pin covers the surface whose enforcer holds it, and no other.** A manifest may declare capabilities for many surfaces, and declaring them is documentation. Enforcement happens only where a process constructs an enforcer over that manifest and routes its calls through it. In a deployment where one of several declared surfaces does so, the pin protects that surface's capabilities and the rest are described but unguarded.

**Such a deployment is not conformant, and this paragraph must not be read as blessing one.** Section 11 requires every exposed method to call the gate before performing any work, so a declared surface whose methods are reachable without an enforcer violates that MUST however completely the manifest describes it. Two readings are conformant and no third is: either a declared surface constructs an enforcer and routes its calls through it, or the methods of that surface are not exposed in this build at all, in which case Section 15 applies and they should not be in the manifest. An implementation MUST state which declared surfaces construct an enforcer, because a reader counting declared capabilities would otherwise overcount what is enforced, and a deployment that cannot make that statement for every surface it declares MUST NOT claim conformance.

This mirrors the issuer-key build-pin discipline used elsewhere in the suite (reachability and update-channel pins): the build pin is authoritative over anything supplied at runtime.

### 10. Decision semantics (fail-closed)

For a requested capability id, the enforcer renders exactly one of four decisions:

| Decision            | Condition                                                                                                  |
| ------------------- | ---------------------------------------------------------------------------------------------------------- |
| `ALLOW`             | The id is declared **and** its `effective-enabled` is true.                                                |
| `DENY_UNKNOWN`      | The id is **not declared** in the manifest.                                                                |
| `DENY_TIER_DEFAULT` | The id is declared, not enabled, and `allow` is `null` (off by tier default; operator has not enabled it). |
| `DENY_OPERATOR`     | The id is declared, not enabled, and `allow` is `false` (operator explicitly disabled it).                 |

The decision algorithm MUST be:

```
decide(id):
 cap = manifest.get(id)
 if cap is None: return DENY_UNKNOWN # fail-closed
 if effective(cap): return ALLOW
 if cap.allow is False: return DENY_OPERATOR
 else: return DENY_TIER_DEFAULT
```

There MUST be no "unknown = allow" path. An undeclared id is **never** allowed. A method added to a server without a corresponding manifest entry is therefore dead until it is declared and reviewed.

### 11. Enforcement boundary

Every exposed SDK method and tool-server method MUST call the enforcer's fail-loud gate with its own capability id **before performing any work** (before argument-dependent side effects, before BRC-100 permissioning, before BRC-103 authentication). The gate MUST:

* return normally (permit execution) iff `decide(id) == ALLOW`;
* otherwise raise/return a loud error carrying the id and a human-readable reason. Reason strings SHOULD be:
* `DENY_UNKNOWN` → `not declared in the capability manifest (fail-closed)`
* `DENY_TIER_DEFAULT` → `disabled by default for its risk tier, operator has not enabled it`
* `DENY_OPERATOR` → `explicitly disabled by the operator`

The gate MUST NOT fall through to execution on any denied decision.

### 12. Operator allow-overlay

The operator review surface is an **overlay**: a mapping from capability id to `true` / `false` / `null`. Applying an overlay to a manifest yields a *new* manifest in which each referenced capability's `allow` is replaced by the overlay value (and unreferenced capabilities keep their prior `allow`). Overlay application MUST fail loud if it references any id **not declared** in the manifest, an operator cannot toggle a capability that does not exist. Because the resulting manifest's fingerprint reflects the new effective states, the operator's decisions are load-bearing (they change the fingerprint the build's provenance seal must commit to), not advisory. Tooling MAY expose selectors that expand an id-prefix (a product or `product.surface`) or a tier name to the set of matching ids, so that "withhold everything that spends" is a single `deny SPEND` action; such expansion is a tooling convenience and MUST resolve to explicit per-id overlay entries before application.

### 13. Error taxonomy

Implementations MUST distinguish at least:

* **Structural / manifest error**: unknown tier, id-grammar violation, duplicate id, missing required field, schema mismatch, or an overlay referencing an undeclared id.
* **Pin / tamper error**: a stored `fingerprint` that disagrees with the recomputed body (Section 8), or a manifest whose fingerprint does not match the build pin (Section 9). These are distinct from generic structural errors because they signal a *possible swap*, not merely malformed input.
* **Decision error**: the fail-loud result of gating a denied capability (Section 11).

### 14. Relationship to BRC-100 / BRC-103 / BRC-104, the reserved namespaces, and provenance sealing

* The manifest gate runs **first**. A capability that is `DENY_*` never reaches BRC-100 permission prompts or BRC-103 authentication, it is refused at the supply boundary.
* BRC-100 continues to govern *per-session, per-counterparty* requests for capabilities that the manifest exposes; the manifest does not replace user consent, it bounds the menu consent can be asked about.
* BRC-103/104 continue to authenticate the caller; the manifest is caller-independent (it constrains the server's own surface).
* The fingerprint (Section 7) is the value a code-provenance ordinal seals: mint over `build_identity || manifest_fingerprint`. This makes "this build exposes exactly these capabilities and no others" a publicly verifiable, tamper-evident claim, and forces any surface-widening to change the published seal.
* **BRC-98 modules and this manifest act on different axes, and they compose.** BRC-98 reserves protocol identifiers beginning with `p` and lets a supported scheme define behaviour at that dispatch point. BRC-229 is the worked example: it defines the `ecpm` scheme and, in its own words, "uses that reserved dispatch point to specialize the meaning of an existing BRC-100 method". A BRC-98 module therefore changes what an already-exposed method *means* for a caller who names the reserved identifier. This specification governs whether that method is exposed at all, evaluated before any caller is consulted and independently of what any caller asks for. A wallet implementing both evaluates the manifest first: if the underlying method is `DENY_*`, the module's dispatch point is unreachable, and the module's presence does not widen the surface. Implementers SHOULD give a BRC-98 module's underlying method its own capability id, so the exposure decision is recorded explicitly rather than inherited.
* **BRC-111 labels are likewise orthogonal.** A label describes or permissions an individual action; a capability id names a method on a server's surface. Neither namespace is claimed here, and a manifest MUST NOT be read as reserving any identifier under `p` .

### 15. What is deliberately absent from a manifest

A manifest lists **exposed** capabilities only. Air-gap co-signer internals (key generation, cosigning, seed handling), raw key material, egress choke points, deniability containers, subscription/issuer keys, and admin/issuer operations MUST NOT be listed merely to document them: appearing in the manifest is what makes a method eligible to be enabled and executed. Anything that must remain non-exposed is simply absent, and if it ever needs exposure it MUST be *added and reviewed*, never assumed.

## Test Vectors

All fingerprints below are lowercase SHA-256 hex digests reproduced from the reference implementation. `DOMAIN = bsv-capability-manifest/v1`.

### Vector 1, tier defaults, no operator overlay

Two declared capabilities, both with `allow = null`:

| id                               | tier    | allow  |
| -------------------------------- | ------- | ------ |
| `example.agent-mcp.getBalance`   | `READ`  | `null` |
| `example.agent-mcp.createAction` | `SPEND` | `null` |

Effective states (Section 5): `getBalance` → **true** (READ default-on); `createAction` → **false** (SPEND default-off).

Canonical fingerprint preimage (Section 7.2), exact bytes:

```
{"capabilities":[{"enabled":false,"id":"example.agent-mcp.createAction","tier":"SPEND"},{"enabled":true,"id":"example.agent-mcp.getBalance","tier":"READ"}],"domain":"bsv-capability-manifest/v1"}
```

Fingerprint:

```
f99054c516d0a079194338004f5cb7439331374fa2c219f15c4691d4904f85fc
```

Decisions (Section 10): `decide("example.agent-mcp.getBalance")` → `ALLOW`; `decide("example.agent-mcp.createAction")` → `DENY_TIER_DEFAULT`; `decide("example.agent-mcp.sweepBsv")` (undeclared) → `DENY_UNKNOWN`.

### Vector 2, operator allows the SPEND capability

Same two capabilities, but the operator sets `allow = true` on `createAction`:

| id                               | tier    | allow  |
| -------------------------------- | ------- | ------ |
| `example.agent-mcp.getBalance`   | `READ`  | `null` |
| `example.agent-mcp.createAction` | `SPEND` | `true` |

Now `createAction` → **true**. Preimage:

```
{"capabilities":[{"enabled":true,"id":"example.agent-mcp.createAction","tier":"SPEND"},{"enabled":true,"id":"example.agent-mcp.getBalance","tier":"READ"}],"domain":"bsv-capability-manifest/v1"}
```

Fingerprint:

```
5f1cbe881b0df89e4c7f37f5e6d0b9cfe0156e1a8f7e7776e318e615e35a3d4e
```

The fingerprint differs from Vector 1, the single overlay toggle re-fingerprints the build, which would force a provenance-seal re-mint. `decide("example.agent-mcp.createAction")` is now `ALLOW`.

### Vector 3, operator explicitly disables a default-on capability

The operator sets `allow = false` on the READ capability (`createAction` back to `null`):

| id                               | tier    | allow   |
| -------------------------------- | ------- | ------- |
| `example.agent-mcp.getBalance`   | `READ`  | `false` |
| `example.agent-mcp.createAction` | `SPEND` | `null`  |

Both effective states are **false**. Preimage:

```
{"capabilities":[{"enabled":false,"id":"example.agent-mcp.createAction","tier":"SPEND"},{"enabled":false,"id":"example.agent-mcp.getBalance","tier":"READ"}],"domain":"bsv-capability-manifest/v1"}
```

Fingerprint:

```
058a0c229fbd0a3830a45dfefecd0343e282f7200406ef58c62586c3679cdffa
```

`decide("example.agent-mcp.getBalance")` → `DENY_OPERATOR` (distinct from Vector 1's `DENY_TIER_DEFAULT` for the same effective-off state, the reason preserves *why* it is off).

### Vector 4, descriptions are not trust-bearing

Take the Vector 1 manifest and change the `description` and `grounded_in` of `getBalance` to arbitrary different strings, leaving `id`, `tier`, and `allow` unchanged. The per-capability projection (Section 7.1) is unchanged, so the fingerprint is **identical** to Vector 1:

```
f99054c516d0a079194338004f5cb7439331374fa2c219f15c4691d4904f85fc
```

This demonstrates Section 7.3: documentation edits do not move the fingerprint and do not require a provenance re-mint.

### Vector 5, build-pin swap refusal

Construct an enforcer with `pinned_fingerprint = f99054c516d0a079194338004f5cb7439331374fa2c219f15c4691d4904f85fc` (the Vector 1 pin) but hand it the **Vector 2** manifest (fingerprint `5f1c…`). Because `5f1c…` != the pin, the enforcer MUST refuse to construct with a pin/tamper error and MUST NOT enter service. Handing the same enforcer the Vector 1 manifest constructs normally. This is the runtime guarantee that a swapped manifest cannot widen the surface.

## Implementations

A reference implementation exists (not a public path):

* A stdlib-only manifest module (Python) implementing the `Capability` record with id-grammar and tier validation, the `CapabilityManifest` container (dedup, canonical fingerprint, overlay, load-time integrity check, JSON round-trip), the four-valued `Decision` enum with fail-closed semantics, and the `CapabilityEnforcer` with build-pin refusal and a fail-loud `enforce()` boundary gate.
* A populated suite-wide JSON inventory carrying the `schema`, `manifest_version`, `note`, `fingerprint`, and `capabilities` fields described in Section 6, spanning the suite's products and surfaces (wallet agent-MCP, onion connect, marketplace client/MCP, messaging core, seal cores, air-gap signer verify surfaces).
* A review/toggle/check/diff CLI implementing the operator overlay (Section 12), including product/surface/tier selector expansion, an integrity/CI check mode, and a build-to-build fingerprint diff.
* A conformance test module covering fail-closed denial, tier defaults, fingerprint stability under documentation edits, build-pin swap refusal, overlay-of-undeclared-id refusal, and stored-fingerprint tamper detection.

Repo-relative `grounded_in` references inside each capability row point at the concrete file that proves the corresponding method exists, so the inventory is auditable against the real code.

## Mathematical and cryptographic basis

The fingerprint is a binding commitment to one exposed surface. It is SHA-256 over a canonical preimage that contains the domain string and the sorted list of (id, tier, enabled) projections and nothing else (Section 7). Canonicalization is injective on that projection: capabilities sorted by id, keys sorted, tight separators, and only strings and booleans present, so a given exposed surface maps to exactly one preimage and one digest. Any change to a trust-bearing element (adding or removing a capability, re-tiering it, or flipping its effective-enabled bit) changes the preimage and therefore the digest. Presenting a different exposed surface under an unchanged fingerprint would require a SHA-256 collision, which is infeasible.

Two properties follow from what the preimage includes and excludes. Documentation fields are outside the preimage, so a wording fix cannot move the fingerprint, and an auditor comparing two builds by fingerprint is comparing exposed behavior rather than prose. The domain string is folded in as the first element, so a manifest digest cannot coincide with a digest any other protocol computes over similar JSON, which closes cross-protocol confusion. The build pin supplies enforcement: at load the enforcer recomputes the fingerprint and refuses to run unless it equals the pinned value, so the commitment is checked against tampering before a single method is exposed, and the decision is fail-closed.

## Security Considerations

* **Fail-closed is the whole point.** The only path to execution is an id that is both declared and effective-enabled. An undeclared id (a newly registered tool, a typo, an injected id) is denied. Implementers MUST NOT add any default-allow or wildcard path.
* **Build-pin authority.** The pin must be embedded in the build artifact, not read from any runtime-mutable source. If an attacker can supply the pin (env/config/file) they can defeat the check; the pin's value is precisely that it is *not* runtime-suppliable. A production build with a null pin (review mode) silently disables the protection and MUST be prevented by release tooling.
* **Trust-bearing projection.** Because only `(id, tier, effective)` are fingerprinted, an attacker cannot smuggle behavior through `description`/`grounded_in`. Conversely, implementers MUST NOT be tempted to "help" by folding descriptions into the fingerprint, doing so would make every prose edit re-mint the provenance seal and erode the auditor's ability to diff behavior.
* **id ≡ product.surface.method.** The self-consistency check prevents a manifest from mislabeling a spend method with a read-looking id. Enforcement callers MUST pass the *method's own* id; a shared or hard-coded id at multiple call sites would let one enabled capability gate an unrelated method.
* **Overlay integrity.** Overlay application refuses undeclared ids, so an operator config cannot pre-authorize a not-yet-declared capability. The overlay changes the fingerprint, which is the feature: silent scope creep is impossible without a visible fingerprint change.
* **Canonicalization determinism.** Two independent implementations MUST produce byte-identical preimages or their fingerprints (and therefore their pins and seals) will disagree. The preimage contains only strings and booleans; implementers MUST use sorted keys, tight separators, and ASCII escaping, and MUST NOT emit trailing whitespace, BOMs, or reordered keys.
* **Scope boundary vs. authorization.** This BRC bounds *which methods are exposed*; it does not by itself authenticate callers (see BRC-103/104) or capture per-request user consent (see BRC-100). It is a necessary lower bound, run first, and MUST be composed with those layers, never used as a substitute for them.
* **Absence is protection.** Sensitive internals (air-gap key handling, issuer keys, egress choke points, deniability containers) are protected by being *absent* from the manifest. Listing such a method (even disabled) makes it eligible to be toggled on; implementers MUST keep permanently-non-exposed surfaces out of the manifest entirely.

## References

* BRC-100: Unified, Vendor-Neutral, Unchanging, and Open BSV Blockchain Standard Wallet-to-Application Interface, the per-session request/permission surface this specification is consulted ahead of.
* BRC-103: Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol, caller authentication, complementary to this supply-side control.
* BRC-104: HTTP Transport for BRC-103 Mutual Authentication.
* BRC-2: Data Encryption and Decryption; BRC-3: Digital Signature Creation and Verification, example CRYPTO/VERIFY-tier methods referenced by manifest rows.
* BRC-42: BSV Key Derivation Scheme (BKDS); BRC-43: Security Levels, Protocol IDs, Key IDs and Counterparties, example key-derivation methods behind READ/CRYPTO rows.
* BRC-52: Identity Certificates / BRC-53: Certificate Creation and Revelation, example IDENTITY-tier methods.
* BRC-65: Transaction Labels and List Actions, example READ-tier history method.
* BRC-98: P Protocols: Allowing Future Wallet Protocol Permission Schemes, the reserved protocol-identifier dispatch point; orthogonal axis, see Section 14.
* BRC-111: P Labels: Allowing Future Wallet Action Label Permission Schemes, reserved label namespace; not claimed by this specification.
* BRC-229: Wallet-Native Elliptic Curve Point Multiplication as a BRC-98 Module, worked example of a module specializing an existing method.
* FIPS 180-4: Secure Hash Standard (SHA-256), the fingerprint hash.
* RFC 8785: JSON Canonicalization Scheme (JCS), referenced for comparison; this BRC's preimage form agrees with JCS on the string/boolean-only preimage but is defined independently in Section 7.2.
* RFC 2119: Key words for use in RFCs to indicate requirement levels.
* BRC-145, Registry-Free Typed Content Anchor with On-Chain Code Provenance (merged 2026-08-02): its code-provenance seal is the running-code-fingerprint-as-ordinal mechanism this manifest's fingerprint is minted into.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://hub.bsvblockchain.org/brc/wallet/0179.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
