Beersy
BRC-205

Extensible Wallet Version Strings and Account Labels

When someone uses the same wallet account across different apps, the wallet's internal software name or vendor branding often means nothing to the user, so apps have no good way to say "this is your account" in words the user actually recognizes. Over time a person might think of their account by a totally different name than it started with, and there was no way for a wallet to communicate that current, human name to an app asking about it. This makes it possible for a wallet to hand over a friendly, current account name without adding new API surface or breaking anything that already .

Ty Everettchanged 12 Oct 202616 min read

Reference for an AI

Everything an assistant needs to answer questions about BRC-205 accurately, including what it depends on.

Summary

Why
Applications need a way to show users a current, human-recognized account name without inventing new wallet methods or exposing identity or permission data.
What
BRC-205 defines an extensible, bounded attribute syntax for the wallet `` string, including one attribute, ``, that names an account the way its user currently knows it.
How
A wallet encodes attributes as `key=value;` pairs (UTF-8, percent-encoded) appended to its existing BRC-100 version string, and an application calls the unchanged `getVersion({})` method, parses the whole string at once, and reads the `account-label` attribute if present to show the user a name they recognize.

What this lets you do

  • Return a wallet account-label alongside the version string
  • Show users a friendly, changeable account name like "Pocket Photos Account"
  • Parse an extended getVersion string without breaking existing BRC-100 clients
  • Reject a malformed version string safely, falling back to software-version metadata only
  • Avoid extra wallet prompts or unlocks just to fetch a

Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.

version stringbase vendor-veaccount-label

The specification

Abstract

This proposal defines a bounded vendor-major.minor.patch; key=value; format for the string returned by getVersion, a process for future BRCs to define attributes, and one initial attribute: account-label. The lets an application describe an existing account using the name its user currently recognizes. A wallet might initially return Pocket Photos Account and later return Metanet Account, without changing the account or the wallet's software version.

This proposal extends BRC-100's version-string format and raises the complete-string limit from 30 to 2048 bytes. It preserves the getVersion({}) call and { version: string } result shape. The string is optional metadata, not an authentication result, provider identifier, core-method negotiation mechanism, or permission grant. Future BRCs may define advertisements for additive reserved permission schemes while preserving the complete BRC-100 core contract.

Motivation

A person may first encounter their account through one application. When another application uses the same wallet, “Continue with your Pocket Photos Account” can explain continuity more clearly than introducing an unfamiliar wallet product or ecosystem name. Later, the person may understand it as their “Metanet Account”. The application needs the current term from the wallet serving that person, rather than inferring it from a software vendor or maintaining its own history of other applications.

The wallet decides when a label changes. Renaming after a second, third, or fourth application is an illustrative policy, not an interoperability requirement. A vendor-neutral syntax also allows later specifications to add independently documented metadata without adding fields to the wallet API.

Scope

The uppercase terms MUST, MUST NOT, SHOULD, SHOULD NOT and MAY have the meanings in RFC 2119 and RFC 8174. The Specification and Compatibility sections define requirements for implementations adopting this proposal. Examples and implementation are informative.

This proposal defines string syntax, parsing, display-label semantics and extension naming. It does not define a new BRC-100 method, argument, result field, call code, transport, account identifier, authentication mechanism, renaming API, provider-discovery mechanism, or method negotiation. It does not standardize how wallets count applications, choose branding, synchronize labels between devices, or translate account names.

Specification

1. Result and wire grammar

An adopting wallet returns its string in the existing version field:

{"version":"example-1.2.3; account-label=Pocket%20Photos%20Account;"}

The schematic form is vendor-<major>.<minor>.<patch>; key=value; key2=value2;. Angle brackets denote placeholders, not wire characters. The semicolon separates attributes; it is not part of the patch number. This resembles a product identifier with parameters, but does not import HTTP User-Agent grammar or HTTP header semantics.

The following ABNF operates on the ASCII bytes of the decoded result string, after the existing transport has delivered it. Numeric terminals specify case exactly. DIGIT and SP come from RFC 5234.

version-string = base [ ";" [ SP attribute *( ";" SP attribute ) [ ";" ] ] ]
base           = vendor "-" core-version
vendor         = alnum *( alnum / "." / "_" / "-" )
core-version   = number "." number "." number
number         = "0" / ( %x31-39 *DIGIT )
attribute      = key "=" value
key            = lower *( lower / DIGIT / "-" )
value          = 1*( unreserved / pct-encoded )
unreserved     = alnum / "-" / "." / "_" / "~"
pct-encoded    = "%" HEXUP HEXUP
HEXUP          = DIGIT / %x41-46
alnum          = %x41-5A / lower / DIGIT
lower          = %x61-7A

Additional requirements:

  • base MUST be 7–30 ASCII bytes. The vendor is a case-sensitive software/product token, not the user-facing account label. Hyphens are permitted within the vendor: the last hyphen in base separates it from the three-part version.
  • The version uses the three nonnegative integers of a SemVer 2.0.0 release core, without leading zeroes. Prerelease and build suffixes are outside this grammar. It describes the wallet software, not the version or account state. Implementations MUST NOT infer method support, permissions or security properties from it.
  • The complete string MUST be at most 2048 ASCII bytes, with at most 24 attributes. Each key MUST be 1–64 bytes. Each decoded value MUST be 1–256 UTF-8 bytes. These limits include unknown attributes. A sender MUST omit optional attributes as necessary to stay within the limits, never cut through an encoded value.
  • Keys are case-sensitive and lowercase only. Values are case-sensitive unless their defining BRC specifies otherwise. A key MUST appear at most once; repeated keys invalidate the attribute section, even when their values are identical. Attribute order has no meaning.
  • There MUST be exactly one ASCII space after every nonterminal semicolon and no spaces around =. There is no leading or trailing whitespace, tab, newline, folding, quoted-string form or backslash escape. A final semicolon is optional for readers. Senders MUST include it when attributes are present and MUST emit just base when none are present.
  • Readers MUST also accept base; as an empty attribute section. Consecutive semicolons are invalid.

2. Attribute value encoding

All attribute values are Unicode text encoded as UTF-8 under RFC 3629. Encode each byte outside the ASCII unreserved set as %HH, using uppercase hexadecimal. Unreserved bytes MUST appear literally, not percent-encoded. Thus a space is %20, a semicolon %3B, an equals sign %3D, a percent sign %25, and a literal plus sign %2B. Plus does not represent a space. For example, Café Account becomes Caf%C3%A9%20Account.

Readers MUST split the ASCII string into its base and attribute pairs before decoding values, then percent-decode each value exactly once. Readers MUST reject malformed escapes, lowercase hex escapes, percent-encoded unreserved bytes, and invalid UTF-8, including overlong sequences and surrogate code points. JSON, HTML, URI, or backslash unescaping MUST NOT be applied to the decoded value. %2520 therefore represents the three-character text %20, not a space. Each attribute's specification MAY further constrain decoded text but MUST NOT change this encoding.

3. Parsing, unknown attributes and failure

A consumer adopting this proposal MUST apply the full-string bound before parsing, validate the base, then validate the complete attribute section and every value's encoding and bounds. It MUST NOT use a partially parsed attribute map. Any syntax, encoding, duplicate-key or generic bound failure makes all attributes unavailable; an independently valid base MAY still be used as software-version metadata. A string over 2048 bytes, an invalid base, or a non-string result supplies no metadata under this proposal. Parsing failure MUST NOT be converted into an authentication failure or evidence of missing wallet methods.

After generic validation, unknown keys MUST be ignored without changing the meaning of known keys. A known attribute whose decoded text fails its own semantic constraints is treated as absent; other valid attributes remain usable. Consumers MUST NOT display the raw string or unknown values as an account label. Implementations SHOULD use a map with no inherited keys, or equivalent storage that treats every key as data.

Legacy strings that do not match this profile remain opaque legacy version results: consumers MUST NOT guess an account label from them. Failure of this metadata parser alone MUST NOT cause a connected wallet to be rejected, switched, or asked to authenticate. A wallet call or transport failure retains its ordinary error semantics; this parser does not suppress those errors.

4. The account-label attribute

PropertyDefinition
Keyaccount-label
MeaningThe current user-recognized name for the account served by the responding wallet in the current application context.
PresenceOptional; at most one current label. Omission means no label is supplied.
Decoded formA complete display noun phrase, such as Pocket Photos Account or Metanet Account, not a sentence or a command.
Size1–128 UTF-8 bytes after decoding and NFC normalization.
AuthorityThe responding wallet's current presentation policy, including any user preferences it honors.

A sender MUST normalize the label to Unicode NFC before UTF-8 encoding. A consumer MUST treat a non-NFC label as absent. It MUST also treat a label as absent if it contains a Unicode control character (General Category Cc), a separator other than U+0020 SPACE (categories Zs, Zl, Zp), any of U+061C, U+200E–U+200F, U+202A–U+202E or U+2066–U+2069 (bidirectional controls), or a leading or trailing U+0020 SPACE. A label MUST contain at least one character outside General Categories C, M and Z that does not have the Default_Ignorable_Code_Point property. These property tests use the Unicode 17.0.0 Character Database; , whitespace and default-ignorable characters alone are insufficient. Ordinary right-to-left text, combining characters and emoji sequences remain permitted when accompanied by such a character. Consumers MUST validate rather than trim, truncate or repair invalid incoming labels into a different name.

The label identifies an account concept, not the person's legal name, username, public key, , unique account ID, balance, installed-app list or wallet product. Wallets MUST NOT include those personal identifiers, secrets or usage histories in this attribute. Different people and different wallets MAY return the same label. A wallet MAY omit the attribute to avoid disclosure, when no account is selected, when locked, or when it cannot determine an appropriate label. Omission or presence MUST NOT be treated as proof that an account exists, is unlocked, or is authenticated.

The wallet MUST supply only the current label, never a history or alias list. It MAY change that label without changing base. The wallet SHOULD show a new label in its own account UI so that the user can recognize it. An application MUST NOT write a label back to the wallet, migrate an account, or infer account replacement merely because this string changes. Conversely, an unchanged label does not prove that the account stayed the same.

Labels MAY reflect the wallet's existing language preference. This proposal adds no locale argument, locale attribute or translation negotiation. Consumers SHOULD preserve the supplied phrase and localize their surrounding UI. Applications MUST NOT translate or append Account on the assumption that the phrase omits it.

5. Consumption, freshness and privacy

An application SHOULD request the label through getVersion({}) on the wallet connection it will actually use, when it presents an account-continuation surface. It MUST NOT query every discoverable wallet for account labels to build an account inventory. A discovery readiness probe MUST NOT cause a wallet to unlock, prompt for new permissions, retrieve an , or establish an account merely to produce metadata. Wallets MUST omit context-sensitive labels when disclosure would require such interaction. Existing originator and permission boundaries remain in force.

The label is a snapshot, not a durable identifier. A consumer MAY retain it in memory for the current connected account context. It MUST discard it on known disconnection, account change, sign-out, or provider switch, and MUST ignore a late response from a retired context. It SHOULD refresh before presenting a new continuation flow; it MUST fall back to generic copy when that refresh fails or supplies no valid label, rather than displaying a label from a previous context. This proposal defines no subscription, polling interval or persistent cross-device cache. Legacy transports might not report account changes: consumers cannot promise immediate freshness in that case.

Suitable copy is Continue with your followed by the inert label. If unavailable, use neutral copy such as Continue with your account. The fallback MUST NOT assume a particular vendor, application or “Metanet” branding. A consumer MUST NOT require a label to use the wallet or silently choose a provider on its basis.

Consumers MUST render labels as untrusted plain text, with bidirectional isolation from surrounding text, never as HTML, Markdown, a URL, executable code or an instruction. They MAY visually elide a valid long label without changing its stored value. They MUST keep application-owned action text and wallet/connection provenance distinguishable; a label is not verified branding. Unicode normalization and character restrictions do not prevent confusable names or misleading claims.

The label can disclose an earlier application relationship; changing labels or combining multiple attributes can also fingerprint users. Wallets SHOULD choose common, nonunique labels and disclose only the minimum appropriate to the requesting context. Applications MUST NOT send labels or complete version strings to analytics, unrelated servers or logs by default, and MUST NOT use them for cross-application correlation. Encoding is not encryption. Ordinary transport protections and user sharing decisions still apply.

6. Future attribute specifications

account-label is the sole attribute defined here. Future shared attributes MUST be proposed as new BRCs through the repository's ordinary contribution process. No separate registry service or approval authority is introduced.

To avoid collisions, a future attribute key MUST be brc followed by its assigned positive BRC number in decimal without leading zeroes, a hyphen, and a descriptive lowercase suffix; for example, the schematic brc<number>-<name>. The entire key still obeys section 1. account-label is the exception reserved by this proposal. A BRC may define several distinct keys under its number. Authors MUST check existing proposals and assigned keys, and update provisional keys if their BRC number changes before adoption. Unprefixed names and another BRC's prefix MUST NOT be claimed by an extension.

Each extension MUST specify its exact key, purpose, decoded syntax and semantics, bounds within this profile's limits, optionality and absence behavior, case/normalization rules, update/cache behavior, privacy and display implications, and valid and invalid examples. It MUST reference this base encoding, single-occurrence rule and unknown-key behavior. Incompatible semantics require a new key; an extension MUST NOT reinterpret an existing key or change the outer grammar. Experimental proposals can be reviewed before adoption, but their provisional keys are not stable interoperability .

An attribute MUST remain optional descriptive metadata: consumers unaware of it must remain able to use the wallet normally. Extensions MUST NOT turn these strings into BRC-100 method-support negotiation, , spending authority, permission grants or mandatory security checks. A proposal needing such behavior needs an appropriate separate protocol, not an attribute that old consumers silently ignore.

Future BRCs MAY define attributes advertising support for additive permission schemes under BRC-98 (), BRC-99 (), or BRC-111 (action labels). These standards reserve identifiers beginning with p followed by a space-free scheme/ and the scheme-defined remainder. Their syntax, dispatch rules and identifier bounds remain authoritative. An advertisement's specification MUST distinguish the namespace and exact scheme/module ID, identify the defining specification, and define freshness and omission behavior. A scheme ID is not necessarily a BRC number; the BRC-number prefix on an attribute key identifies the attribute specification, not the advertised scheme's identifier.

Such advertisements are optional hints about an additive extension, not negotiation of the core interface. All 28 BRC-100 methods remain mandatory, with their existing argument/result shapes, ordinary non-scheme semantics and security/authorization guarantees, subject only to this proposal's explicit getVersion string-content extension. Advertising a scheme MUST NOT make an ordinary operation depend on that scheme or authorize an operation. When an application explicitly invokes a reserved identifier, the wallet MUST still determine actual scheme support, reject unsupported reserved schemes, and apply the governing BRC and that scheme's defined permission/operation rules. For example, BRC-111 permits module-specific label permission checks and query handling; an advertisement neither performs those checks nor overrides their outcome.

Absence of an advertisement MUST NOT be treated as proof of non-support, since metadata is optional and bounded; presence MUST NOT be treated as proof of current authorization, successful execution or safe code. Consumers MUST still normal wallet results and errors and MUST NOT silently substitute different operation semantics when an advertised scheme is unavailable. Scheme-support inventories can fingerprint wallets: an extension MUST specify its disclosure/privacy policy and MUST NOT require publishing user-specific grants or usage history. No scheme-advertisement key, list encoding or particular scheme is defined by this proposal; those require future BRCs under the process above.

BRC-100

BRC-100 defines a 7–30-character [vendor]-[major].[minor].[patch] version string. This proposal extends that string with optional attributes and replaces its complete-string maximum with 2048 ASCII bytes. The base remains 7–30 bytes. No other result field, method, request argument, call code or transport framing changes.

New consumers MUST accept base-only results without requiring attributes. Wallets MAY return the extended format without a separate opt-in or support-discovery exchange. Consumers adopting this proposal MUST accept strings within the new limit and handle attributes as specified above.

In practice, applications and wallets have generally treated the old 30-character limit loosely, and applications rarely depend on it. These early days are a good time to lift that limit and make room for useful metadata. Older applications, SDKs or wallets that enforce the original length or base-only format may throw when given an extended string; their validators need to accept the new format and limit. This is a compatibility caveat, not a requirement for coordinated adoption or a new negotiation protocol.

Draft BRC-185

Draft BRC-185, PR #272, section 1, explicitly permits separately adopted additive getVersion string-content profiles, including this proposal, while retaining the complete mandatory BRC-100 core interface. That exception reconciles its unchanged-result wording with this proposal's syntax and length extension; it does not authorize changes to other method behavior, result shapes or transport framing. Future BRC-defined advertisements for additive BRC-98/99/111 schemes are permitted, but negotiation of a reduced core method set and metadata-based permission grants remain prohibited. BRC-185 support alone does not imply that an implementation's version-string validator has been updated.

Its descriptor's name is a product name, instanceLabel distinguishes provider instances, and instanceId/continuityKey support application-scoped provider continuity. None is account-label. Consumers MUST NOT replace those fields with this label, merge candidates on matching labels, or use labels as remembered-choice keys. Account labeling belongs to the selected wallet context, not public provider discovery. If BRC-185 is used, its connection and account-change invalidation remain authoritative: a mere display rename is not a change of the bound account, and a real account switch cannot be hidden by retaining the same label.

Identity and historical versioning

BRC-56 identifies its old 0.3.x version convention as historical and directs new implementations to BRC-100. This proposal does not restore that convention. BRC-189 addresses identity keys, certificates, public discovery and contacts; this label is not an identity attribute published by that protocol. BRC-116 continues to govern wallet permissions. No label or future metadata attribute bypasses those boundaries.

Examples and conformance cases

The following strings are complete version values, without JSON quoting. example is illustrative vendor text.

InputRequired result
example-1.2.3Valid base; no label.
wallet-brc100-1.0.0Valid base with vendor wallet-brc100; no label.
example-1.2.3;Accepted empty attribute section; senders omit this semicolon.
example-1.2.3; account-label=Pocket%20Photos%20Account;Label Pocket Photos Account.
example-1.2.3; account-label=Metanet%20AccountLabel Metanet Account; reader accepts missing final semicolon.
example-1.2.3; account-label=Caf%C3%A9%20Account;Label Café Account, in NFC.
example-1.2.3; account-label=Photos%3B%20Family%3DShared;Label Photos; Family=Shared; decoded delimiters stay inside the value.
example-1.2.3; account-label=Photos%2520Account;Label Photos%20Account; no second decoding.
example-1.2.3; future-key=value; account-label=Metanet%20Account;Ignore the syntactically valid unknown key; use label. future-key tests reader behavior, not an allocated extension key.
example-1.2.3; account-label=A; account-label=B;Duplicate key: all attributes unavailable.
example-1.2.3;account-label=A;Missing separator space: all attributes unavailable.
example-1.2.3; Account-Label=A;Uppercase key: all attributes unavailable.
example-1.2.3; account-label=A;;Consecutive semicolons: all attributes unavailable.
example-1.2.3; account-label=;Empty encoded value: all attributes unavailable.
example-1.2.3; account-label=%41;Encoded unreserved byte: all attributes unavailable.
example-1.2.3; account-label=Caf%c3%a9;Lowercase escape hex: all attributes unavailable.
example-1.2.3; account-label=%FF;Invalid UTF-8: all attributes unavailable.
example-1.2.3; account-label=A%0AB;Generic value parses; label is absent because it contains a control character.
example-1.2.3; account-label=%20Account;Label is absent because it starts with a space.
example-1.2.3; account-label=Cafe%CC%81;Label is absent because it is not NFC.
example-1.2.3; account-label=%EF%B8%8F;Label is absent because a variation selector alone is insufficient.
example-01.2.3; account-label=A;Invalid base: no metadata under this profile.
0.3.80Opaque legacy result, no inference.

Readers must also cover the stated size limits: exactly 2048 bytes is permitted if all other constraints hold; 2049 is not. Exactly 24 unique attributes and a 256-byte decoded unknown value are permitted; 25 attributes or 257 decoded bytes invalidate the attribute section. A 128-byte valid label is permitted; 129 bytes makes that label absent. A generic failure in an unknown attribute invalidates the whole attribute section just as it would for a known attribute.

Implementations should also check base-only fallback, a label change with unchanged software version, provider/account switching with a delayed old response, omission while locked, localized labels, inert rendering of markup-like text and right-to-left text, and continued operation when metadata parsing fails. These are interoperability cases, not claims that existing wallets already pass.

Implementation notes

The existing toolbox Wallet returns wallet-brc100-1.0.0. The base grammar preserves that form, including hyphens in the vendor.

Some SDK versions enforce the old 7–30-byte bound in result validation and the binary transceiver. Implementations adopting this proposal should update those checks wherever they occur. This PR specifies the format; it does not include SDK or wallet implementation changes.

References

Was this helpful?

Search Beersy

Search standards by number, title, author or topic