Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/hypercerts-api/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Read the relevant reference, then inspect the exact operation in the [bundled Op

## Bundled API contract

- [`references/openapi.json`](references/openapi.json) is a self-contained snapshot of all 61 query operations, including parameters, response schemas, declared XRPC errors, and their referenced schema definitions. The included contract makes the skill self-contained when installed separately.
- [`references/openapi.json`](references/openapi.json) is a self-contained snapshot of all 62 query operations, including parameters, response schemas, declared XRPC errors, and their referenced schema definitions. The included contract makes the skill self-contained when installed separately.
- To inspect an exact contract, find `/xrpc/<full NSID>` in the snapshot, read its operation, and follow any `#/components/schemas/...` references by schema name. Each operation and schema is stored on its own line for focused lookup.
- The snapshot describes declared behavior, not endpoint availability or data freshness on a particular host. Its OpenAPI `info.version` is not the deployed server's version.
- Use the API directly when a task needs live indexed results. Do not send extra diagnostic probes just to validate deployment; a deployment-specific availability check requires explicit approval for the target.
9 changes: 5 additions & 4 deletions .agents/skills/hypercerts-api/references/endpoint-map.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Endpoint map: choose by consumer task

This task index lists the 61 public query NSIDs in the bundled [OpenAPI contract](openapi.json). It helps choose an operation but does not replace its exact contract: inspect that operation and its referenced schemas for required parameters, types, defaults, limits, filter semantics, response fields, and declared errors. The static snapshot describes the contract, not availability or freshness on a selected deployment.
This task index lists the 62 public query NSIDs in the bundled [OpenAPI contract](openapi.json). It helps choose an operation but does not replace its exact contract: inspect that operation and its referenced schemas for required parameters, types, defaults, limits, filter semantics, response fields, and declared errors. The static snapshot describes the contract, not availability or freshness on a selected deployment.

## Fast selection rules

Expand All @@ -9,7 +9,7 @@ This task index lists the 61 public query NSIDs in the bundled [OpenAPI contract
- **Browse or filter without free text:** choose `list...` in the relevant domain.
- **Text discovery:** use `search...` only where listed below. A search query is not interchangeable with a list filter, and search semantics vary by endpoint.
- **Relationship checks:** use `get...Follow` for a single pair, or `getFollows` / `getEntityFollows` to check repeated target values for one actor. List queries answer who follows whom or which entities an actor follows.
- **Feed reactions:** use `getLikes` or `getReposts` for distinct actors reacting to a subject URI, or `getActorLikes` / `getActorReposts` for an actor's own raw representative reactions.
- **Feed reactions:** use `getLikes` or `getReposts` for distinct actors reacting to one subject URI, `getActorLikes` / `getActorReposts` for one actor's raw representative reactions, or `getActorReactions` to check one actor across a bounded set of known subject URIs.

Inspect the exact operation in the bundled OpenAPI contract before constructing a request: names such as `authors`, `actors`, `uri`, and `collection` have endpoint-specific meanings. Do not infer that a filter, search operation, output array name, or error exists just because a related endpoint has one.

Expand Down Expand Up @@ -85,16 +85,17 @@ An `unanswered` award is a successful indexed award result, not a not-found resp

Do not confuse actor follows with entity follows; their identifiers and list outputs differ. Recent raw follows preserve duplicates and are not a snapshot; consult that endpoint's description before using cursors.

## Feed reactions (4)
## Feed reactions (5)

| User task | Query NSID | Practical choice |
|---|---|---|
| List actors who liked a record | `app.certified.feed.getLikes` | `subject` is a full record AT-URI; matching ignores CID. The response includes a total distinct-actor count, paginated actor sidecars, and each actor's raw representative like. |
| List actors who reposted a record | `app.certified.feed.getReposts` | `subject` is a full record AT-URI; matching ignores CID. The response includes a total distinct-actor count, paginated actor sidecars, and each actor's raw representative repost. |
| List an actor's likes | `app.certified.feed.getActorLikes` | `actor` is a repository-owner DID. Returns raw like records, one per subject URI; subjects need not be indexed. |
| List an actor's reposts | `app.certified.feed.getActorReposts` | `actor` is a repository-owner DID. Returns raw repost records, one per subject URI; subjects need not be indexed. |
| Check an actor's reactions for known subjects | `app.certified.feed.getActorReactions` | Supply `actor` as a DID and `subjects` as 1–100 repeated full record AT-URIs. Returns one result per input occurrence in order, including duplicates; matching ignores CID, and missing indexed likes/reposts are null. Raw views retain reaction URIs. |

Reaction queries use the earliest record per author/subject URI, with URI ascending as the tie-breaker. They sort pages by the representative record's `createdAt` and URI; check each operation for exact cursor and response details.
Paginated reaction-list queries use the earliest record per author/subject URI, with reaction URI ascending on ties, and sort pages by the representative's `createdAt` and URI. `getActorReactions` uses the same representative selection but preserves request order and has no pagination. Check each operation for exact cursor and response details.

## Context and supporting records (8)

Expand Down
3 changes: 3 additions & 0 deletions .agents/skills/hypercerts-api/references/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"servers": [{"url":"https://api.test.hypercerts.dev","description":"API test server (default)"}],
"tags": [{"name":"app.certified.actor"},{"name":"app.certified.badge"},{"name":"app.certified.feed"},{"name":"app.certified.graph"},{"name":"app.certified.link"},{"name":"app.certified.location"},{"name":"org.hypercerts.claim"},{"name":"org.hypercerts.collection"},{"name":"org.hypercerts.context"},{"name":"org.hypercerts.entity"},{"name":"org.hypercerts.funding"},{"name":"org.hypercerts.vocab"},{"name":"org.hypercerts.workscope"}],
"paths": {
"/xrpc/app.certified.feed.getActorReactions": {"get":{"operationId":"app_certified_feed_getActorReactions","tags":["app.certified.feed"],"description":"Returns the indexed like and repost for each supplied subject occurrence by one actor. Authentication is not required. Subject matching ignores CID; duplicate inputs and request order are preserved. For each reaction collection, duplicate actor and subject URI pairs use the earliest valid createdAt; when it is absent or invalid, ordering falls back to indexedAt and then the database row's created_at timestamp, with reaction URI ascending on ties. A missing indexed reaction is null; query failures return an error.","parameters":[{"name":"actor","in":"query","required":true,"description":"Repository-owner DID of the actor whose reactions to look up.","schema":{"type":"string","format":"did"}},{"name":"subjects","in":"query","required":true,"description":"One or more full record AT-URIs with DID authorities, not handle authorities, supplied as repeated unbracketed query values. Results preserve each occurrence and its input order.","schema":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","format":"at-uri"}},"style":"form","explode":true}],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app.certified.feed.getActorReactions.output"}}}}},"x-lexicon-id":"app.certified.feed.getActorReactions","x-lexicon-errors":[{"name":"InvalidRequest","description":"The actor DID, subjects array, subject AT-URI, or another query parameter is invalid."},{"name":"ActorReactionsQueryFailed","description":"The indexed actor reactions could not be queried or returned a malformed result; retry the request."}]}},
"/xrpc/app.certified.actor.getOrganization": {"get":{"operationId":"app_certified_actor_getOrganization","tags":["app.certified.actor"],"description":"Gets an actor's indexed organization sidecar and associated profile by DID. Authentication is not required.","parameters":[{"name":"actor","in":"query","required":true,"description":"DID of the actor to look up.","schema":{"type":"string","format":"did"}}],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app.certified.actor.getOrganization.output"}}}}},"x-lexicon-id":"app.certified.actor.getOrganization","x-hypercerts-coverage":"manifest-registered","x-hypercerts-source":{"module":"modules/organization/manifest.json"},"x-lexicon-errors":[{"name":"InvalidRequest","description":"The actor DID is invalid or an unsupported parameter was supplied."},{"name":"RecordNotFound","description":"No indexed organization sidecar exists for this DID."},{"name":"OrganizationQueryFailed","description":"The indexed organization sidecar or associated profile could not be queried."}]}},
"/xrpc/app.certified.actor.getOrganizations": {"get":{"operationId":"app_certified_actor_getOrganizations","tags":["app.certified.actor"],"description":"Returns an indexed organization sidecar and associated profile for each supplied actor DID. Authentication is not required.","parameters":[{"name":"actors","in":"query","required":true,"description":"Actor DIDs to look up, supplied as repeated unbracketed query values.","schema":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","format":"did"}},"style":"form","explode":true}],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app.certified.actor.getOrganizations.output"}}}}},"x-lexicon-id":"app.certified.actor.getOrganizations","x-hypercerts-coverage":"manifest-registered","x-hypercerts-source":{"module":"modules/organization/manifest.json"},"x-lexicon-errors":[{"name":"InvalidRequest","description":"An actor DID or query parameter is invalid."},{"name":"OrganizationQueryFailed","description":"The indexed organization sidecars or associated profiles could not be queried."}]}},
"/xrpc/app.certified.actor.getProfile": {"get":{"operationId":"app_certified_actor_getProfile","tags":["app.certified.actor"],"description":"Gets an indexed Certified profile by DID or handle. Handles resolve through the configured resolver's com.atproto.identity.resolveHandle endpoint; no DID document is fetched for independent verification. Authentication is not required.","parameters":[{"name":"actor","in":"query","required":true,"description":"DID or handle of the profile actor.","schema":{"type":"string","format":"at-identifier"}}],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app.certified.actor.getProfile.output"}}}}},"x-lexicon-id":"app.certified.actor.getProfile","x-hypercerts-coverage":"manifest-registered","x-hypercerts-source":{"module":"modules/profile/manifest.json"},"x-lexicon-errors":[{"name":"InvalidRequest","description":"The actor is not a valid DID or handle, or an unsupported parameter was supplied."},{"name":"HandleResolverConfigError","description":"HYPERCERTS_HANDLE_RESOLVER_URL is missing or invalid."},{"name":"HandleResolutionFailed","description":"The handle could not be resolved to a valid DID."},{"name":"RecordNotFound","description":"The actor was identified, but no indexed Certified profile exists."},{"name":"ProfileQueryFailed","description":"The indexed profile could not be queried."}]}},
Expand Down Expand Up @@ -69,6 +70,8 @@
"components": {
"schemas": {
"app.certified.actor.profile.main": {"type":"record","description":"A declaration of a Certified account profile."},
"app.certified.feed.getActorReactions.actorReactionResult": {"type":"object","required":["subject","like","repost"],"properties":{"subject":{"type":"string","description":"The subject AT-URI from this request occurrence; matching ignores CID.","format":"at-uri"},"like":{"anyOf":[{"$ref":"#/components/schemas/app.certified.feed.getLikes.likeRecordView"},{"type":"null"}]},"repost":{"anyOf":[{"$ref":"#/components/schemas/app.certified.feed.getReposts.repostRecordView"},{"type":"null"}]}}},
"app.certified.feed.getActorReactions.output": {"type":"object","required":["results"],"properties":{"results":{"type":"array","description":"One result for each supplied subject occurrence, in request order, including duplicates.","items":{"$ref":"#/components/schemas/app.certified.feed.getActorReactions.actorReactionResult"}}}},
"org.hypercerts.api.defs.profileView": {"type":"object","description":"Profile record view preserving the full indexed record; indexedAt may be null when the index has no timestamp.","required":["uri","cid","indexedAt","did","record"],"properties":{"uri":{"type":"string","format":"at-uri"},"cid":{"type":"string","format":"cid"},"indexedAt":{"anyOf":[{"type":"string","format":"datetime"},{"type":"null"}]},"did":{"type":"string","format":"did"},"record":{"$ref":"#/components/schemas/app.certified.actor.profile.main"}}},
"app.certified.actor.organization.main": {"type":"record","description":"Extended metadata for an organization actor. Complements the base actor profile (app.certified.actor.profile), which holds the display name, description, website, avatar, and banner, with organization-specific fields such as legal name, full logo, public contact email, legal structure, reference links, and locations."},
"org.hypercerts.api.defs.organizationView": {"type":"object","description":"Raw organization sidecar record view preserving the full indexed record; indexedAt may be null when the index has no timestamp.","required":["uri","cid","indexedAt","did","record"],"properties":{"uri":{"type":"string","format":"at-uri"},"cid":{"type":"string","format":"cid"},"indexedAt":{"anyOf":[{"type":"string","format":"datetime"},{"type":"null"}]},"did":{"type":"string","format":"did"},"record":{"$ref":"#/components/schemas/app.certified.actor.organization.main"}}},
Expand Down
9 changes: 9 additions & 0 deletions .agents/skills/hypercerts-api/references/recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ These recipes show endpoint choice and the data to carry between calls. For exac

**Likely failure modes:** passing a record URI where the required collection URI belongs; discarding CID and accidentally displaying a different version; assuming nested collections are expanded; or assuming pages represent one immutable collection snapshot. Inspect `org.hypercerts.collection.listCollectionItems` and `org.hypercerts.collection.getCollection` in the [bundled OpenAPI contract](openapi.json) before relying on resolution details.

## Check one actor's reactions for known subjects

1. Call `app.certified.feed.getActorReactions` with `actor` as the repository-owner DID and `subjects` as 1–100 full record AT-URIs. Send each URI as a repeated unbracketed `subjects` query parameter; do not comma-join or bracket the key.
2. Keep the input order and duplicates when the caller needs one result per occurrence. The response's `results` array preserves both and repeats the requested AT-URI in each item's `subject` field.
3. Each result contains the actor's earliest indexed raw `like` and `repost` for that subject URI, or null for either reaction when none is indexed. Subject matching ignores CID. A non-null view preserves its reaction record `uri` and `cid`; retain them when the application needs to identify that record through a separate write-capable API.
4. A null is a successful indexed absence, not proof that no source record exists. Query failures are errors, not null reactions. Consider index freshness before showing a definitive “not reacted” state.

**Likely failure modes:** passing handles instead of a DID, sending a collection-less or malformed AT-URI, exceeding the 100-subject bound, deduplicating the response by URI when occurrences matter, or treating a failed indexed query as absence. Inspect the operation in the [bundled OpenAPI contract](openapi.json) and see [reliability.md](reliability.md).

## Load profile and organization context

1. For one actor profile, call `app.certified.actor.getProfile` with a DID or handle. For many known actor DIDs, use `app.certified.actor.getProfiles` with repeated `actors` values; the returned results correspond to the input occurrences and `profile` can be null.
Expand Down
4 changes: 2 additions & 2 deletions .agents/skills/hypercerts-api/references/reliability.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ For a potentially fresh record that is absent:

## Null, omitted, empty, not-found, and failure are different

- **Null field:** the endpoint returned a known enclosing result, but one optional or nullable projection is unavailable/absent under that contract. Examples include a null profile in batch `getProfiles`, a null organization in `getOrganizations`, a null `follow` in `getFollow`, or a null resolved collection-item `record`. Preserve and render this state intentionally.
- **Null field:** the endpoint returned a known enclosing result, but one optional or nullable projection is unavailable/absent under that contract. Examples include a null profile in batch `getProfiles`, a null organization in `getOrganizations`, a null `follow` in `getFollow`, a null resolved collection-item `record`, or a null `like`/`repost` from `getActorReactions` when that reaction is not indexed. Preserve and render this state intentionally.
- **Batch relationship result:** `getFollows` and `getEntityFollows` return an explicit target and nullable `follow` for every input occurrence. Null means no relationship is indexed for that actor and target; a database/query failure remains an error and must not be converted to null.
- **Omitted optional field:** the schema does not require the property in that condition. Do not treat omission as the same representation as explicit null unless the exact endpoint contract says so.
- **Empty list:** the query succeeded and returned no matching items. It is not the same as an invalid query or failed hydration.
- **Not-found error:** a `get...` query may declare `RecordNotFound` when no matching record is indexed. That is not necessarily a successful response containing a null record. Use the endpoint's own declared error contract.
- **Query/hydration error:** an operation may fail if required indexed data cannot be queried or hydrated. Do not hide it by returning an empty list or null unless the endpoint explicitly defines that behavior.
- **Query/hydration error:** an operation may fail if required indexed data cannot be queried or hydrated. `app.certified.feed.getActorReactions` returns `ActorReactionsQueryFailed` for a failed or malformed indexed lookup; it must not be interpreted as a successful null reaction. Do not hide query failures by returning an empty list or null unless the endpoint explicitly defines that behavior.
- **Domain status:** `getBadgeAward` can return a valid award with `responseStatus: "unanswered"` and `recipientResponse: null`. That is neither a not-found error nor a failed request. The award view can separately have `badge: null` if its definition projection is unavailable.

A nullable actor profile does not imply an invalid DID; a missing organization sidecar does not prove the actor is missing; an unavailable exact CID does not prove another version at that URI is absent.
Expand Down
Loading
Loading