This describes how clients discover canonical disclosure, contribution links, and dependency metadata published on ATProto (fund.at.disclosure, optional fund.at.contribute, optional fund.at.dependencies).
Discovery works from either a DID (query directly) or a hostname (resolve the hostname’s DID via ATProto’s _atproto TXT).
- DID:
did:plc:…ordid:web:… - Hostname:
example.com,pds.example.com
- Primary: DNS TXT
_atproto.<hostname> - Fallback:
https://<hostname>/.well-known/atproto-did - DNS value is commonly
did=did:plc:…, but clients should also accept a bare DID.
_atproto.pds.example.com TXT "did=did:plc:xxxxxxxxxxxxxxxxxxxx"
GET https://example.com/.well-known/atproto-did
did:plc:xxxxxxxxxxxxxxxxxxxx
- Start with an identifier (DID or hostname).
- If it’s a hostname, resolve it to DID via DNS
_atprotoand/or HTTPS well-known. - Resolve the DID to its PDS, then
com.atproto.repo.listRecordson:- required:
fund.at.disclosure - optional:
fund.at.contribute - optional:
fund.at.dependencies
- required:
restrictToDomains(fund.at.contribute,fund.at.disclosure,fund.at.dependencies) — optional allowlist of hostnames for which a record should be considered applicable. When omitted or empty, the record is open.appliesToNsidPrefix(fund.at.dependenciesonly) — optional NSID prefix for tool-scoped dependency lists. Host-only clients (e.g. PDS hostname lookup) may ignore records that set this field.
This app uses the lookup hostname (currently: the user’s home PDS hostname from DID document service discovery) when evaluating allowlists.
When multiple records match, this app picks the fund.at.disclosure row with the newest effectiveDate that still has usable meta, and the newest fund.at.contribute row that has usable links (if any). It merges dependency URIs from all matching host-scoped fund.at.dependencies records (deduplicated).
After sign-in, the app resolves the user DID to a DID document, extracts the home PDS URL, then walks the catalog chain (physical hostname → entryway → operator) to identify the PDS operator. The operator appears as a pinned card in My Stack with a "personal data server" capability showing the entryway hostname (e.g. bsky.social).
This section proposes how fund.at could model contribution acknowledgement when actual payment or transfer happens outside ATProto.
fund.at.contribute currently publishes contribution entry points (links and metadata), not contribution events.
For event-like interactions, fund.at can use an ATProto-native edge-record pattern (similar to likes/replies): one record references another subject, records carry timestamp plus optional context, and indexers can build participant activity/state without controlling payment rails.
- Preserve the out-of-band funding model (no settlement logic in protocol)
- Enable useful social and coordination signals: interest, activity, acknowledgement, status
- Support both donor-participatory and recipient-only automation workflows
- Keep privacy and abuse resistance as first-class concerns
Contributor indicates intent or a claim of contribution.
Possible fields:
recipient(DID)kind(interest | pledge | sent)channel(optional processor/provider label)createdAt- optional
evidence(URL or hashed external identifier) - optional
amountBand(coarse buckets only)
Recipient acknowledges a contribution signal or external contribution event.
Possible fields:
ackType(in-response | recipient-initiated)createdAtstatus(acknowledged | verified | needs-info | declined | corrected | revoked | spam)- optional
note - optional
impactRef/fulfillmentRef(release note, changelog, sponsor page)
Mode A: signal-linked acknowledgement
- includes
subject(com.atproto.repo.strongRef) pointing tofund.at.contribute.signal - strongest evidence class (donor-participatory)
Mode B: recipient-initiated acknowledgement
- no
subject - includes
externalRefmetadata (provider + hashed provider event identifier + optional occurred window) - supports automated acknowledgement when donor never used
fund.at - weaker evidence class; should be rendered distinctly in clients
Some contributors will give through external channels and never publish any ATProto signal. A recipient may still want to publish transparent acknowledgement events (manually or via automation).
Allowing recipient-initiated ack:
- avoids excluding non-ATProto donor workflows
- enables aggregate transparency and activity feeds
- preserves utility even with partial donor participation
Clients/indexers should distinguish:
ackwithsubject-> donor-participatory edgeackwithoutsubjectbut withexternalRef-> recipient claim with external traceabilityackwithout either -> weak claim; de-emphasize in UI
For recipient-initiated acks, benefactor identity may be partial or uncertain.
Consider:
- optional
benefactorobject (DID/handle/hash/anonymous marker) - optional
identityConfidence(high | medium | low | unknown)
Do not require exact amount or raw payment IDs.
Prefer:
- coarse amount bands
- hashed external identifiers
- optional visibility policy and recognition opt-out semantics
Recipient-initiated acks can be abused for self-promotion or false attribution.
Mitigations:
- explicit semantics in lexicon/docs: recipient-initiated ack is a recipient claim, not donor confirmation
- optional
verificationMethodandevidenceUri - lifecycle statuses (
corrected,revoked) for post-hoc fixes
Automations may emit duplicate acknowledgements for the same external event.
Include a stable dedup signal (for example, hashed provider event key) and define indexer/client dedup behavior.
Separate:
createdAt: when ATProto record is createdoccurredAt(optional): when contribution happened externally
Current steward discovery (fund.at.disclosure, fund.at.contribute, fund.at.dependencies) is steward-centric.
Contribution acknowledgement records are relationship/event-centric and likely require indexer support for robust cross-repo discovery.
- processing payments
- enforcing transfer settlement
- certifying legal/tax validity of contributions
- replacing external provider receipts