Skip to content

Generated file

This page is generated from the GraphQL SDL in hadron-server/src/api/graphql/schema/typeDefs.ts. To refresh it, run npm run docs:graphql from the root of this repo.

Code paths below are not local. The descriptions come from doc comments written inside hadron-server, so a path like src/api/assetPublic.ts is relative to the hadron-server repository — there is no such file here. They point at the implementation and are volatile; the durable statement is the description itself.

Convention: ID or URN

Across the GraphQL API, fields that take an entity reference (memoryId, agentId, appId, orgId, a ref argument, or id on an entity-keyed op) accept either the entity's database ID or its URN. URNs may be passed bare (e.g. acme:family-mealplan) or with the optional canonical hrn:<type>: prefix (e.g. hrn:mem:acme:family-mealplan); the legacy urn:<type>: prefix is also accepted on input. All shapes resolve to the same entity, with identical authorization and behavior. The closing line of every in-scope field's description — "Accepts the entity's ID or URN." — calls out which fields participate.

# These two queries are equivalent:
query { memory(ref: "cm5x...kqp") { name } }
query { memory(ref: "acme:family-mealplan") { name } }

GraphQL API Reference

Table of Contents * [Query](#query) * [Mutation](#mutation) * [Objects](#objects) * [AccessGrant](#accessgrant) * [ActionTicket](#actionticket) * [ActionTicketsPage](#actionticketspage) * [AddMemoryMemberPayload](#addmemorymemberpayload) * [Agent](#agent) * [AgentAIConfig](#agentaiconfig) * [AgentImport](#agentimport) * [AgentMemoryItem](#agentmemoryitem) * [AgentOrgGrant](#agentorggrant) * [AgentSchedule](#agentschedule) * [AgentSchedulesPage](#agentschedulespage) * [AgentSubscription](#agentsubscription) * [AgentWebhook](#agentwebhook) * [AgentWebhookCredentials](#agentwebhookcredentials) * [AgentWebhooksPage](#agentwebhookspage) * [AgentsPage](#agentspage) * [AiModelPrice](#aimodelprice) * [AiModelPriceList](#aimodelpricelist) * [AiServiceConfig](#aiserviceconfig) * [AiServiceConfigsPage](#aiserviceconfigspage) * [App](#app) * [AppAIConfig](#appaiconfig) * [AppAgent](#appagent) * [AppCreated](#appcreated) * [AppKey](#appkey) * [AppKeyCreated](#appkeycreated) * [AppMember](#appmember) * [AppRun](#apprun) * [AppRunsPage](#apprunspage) * [AppsPage](#appspage) * [Asset](#asset) * [AssetDownloadUrl](#assetdownloadurl) * [AssetListResult](#assetlistresult) * [AssetPutHeader](#assetputheader) * [AssetsPage](#assetspage) * [AuthContext](#authcontext) * [BeginAssetUploadResult](#beginassetuploadresult) * [CalendarAttendee](#calendarattendee) * [CalendarEvent](#calendarevent) * [CalendarEventTime](#calendareventtime) * [CalendarInfo](#calendarinfo) * [CalendarPerson](#calendarperson) * [CastWorkerPreview](#castworkerpreview) * [Chat](#chat) * [ChatMessage](#chatmessage) * [ChatPromptResult](#chatpromptresult) * [ChatResponseResult](#chatresponseresult) * [ChatStartResult](#chatstartresult) * [ConnectionGrant](#connectiongrant) * [ConnectionGrantsPage](#connectiongrantspage) * [CreateMemorySharePayload](#creatememorysharepayload) * [CreditBalance](#creditbalance) * [CreditLedgerEntry](#creditledgerentry) * [CreditLedgerEntryList](#creditledgerentrylist) * [DashboardWidget](#dashboardwidget) * [DashboardWidgetData](#dashboardwidgetdata) * [DashboardWidgetPreset](#dashboardwidgetpreset) * [DeleteMemorySharePayload](#deletememorysharepayload) * [DeleteTeamRolePayload](#deleteteamrolepayload) * [DriveFile](#drivefile) * [DriveFileExport](#drivefileexport) * [DriveFilePage](#drivefilepage) * [Edge](#edge) * [EdgesPage](#edgespage) * [EditorLockResult](#editorlockresult) * [EffectiveAccess](#effectiveaccess) * [EffectiveActionPolicy](#effectiveactionpolicy) * [EmailDraftInfo](#emaildraftinfo) * [ExchangeConnection](#exchangeconnection) * [ExchangeFolder](#exchangefolder) * [ExchangeMessage](#exchangemessage) * [FindNodesResult](#findnodesresult) * [GlobalSearchHit](#globalsearchhit) * [GlobalSearchResult](#globalsearchresult) * [GraphEdge](#graphedge) * [GraphEdgesPage](#graphedgespage) * [GraphNode](#graphnode) * [GraphNodesPage](#graphnodespage) * [HomeAssistantInstance](#homeassistantinstance) * [HomeAssistantInstancesPage](#homeassistantinstancespage) * [HomeAssistantOp](#homeassistantop) * [ImpersonationInfo](#impersonationinfo) * [ImpersonationSession](#impersonationsession) * [ImpersonationSessionList](#impersonationsessionlist) * [ImportNodeResult](#importnoderesult) * [InstallAgentIntoAppPayload](#installagentintoapppayload) * [InstallationPolicy](#installationpolicy) * [JoinAppPayload](#joinapppayload) * [LeaveAppPayload](#leaveapppayload) * [McpServer](#mcpserver) * [McpServerTool](#mcpservertool) * [McpServersPage](#mcpserverspage) * [MemoriesPage](#memoriespage) * [Memory](#memory) * [MemoryMember](#memorymember) * [MemoryProvisioning](#memoryprovisioning) * [MemoryShare](#memoryshare) * [MemorySubscription](#memorysubscription) * [MemoryValidationFinding](#memoryvalidationfinding) * [MemoryValidationResult](#memoryvalidationresult) * [MemoryValidationSkippedCheck](#memoryvalidationskippedcheck) * [Node](#node) * [NodeBatchResult](#nodebatchresult) * [NodeExportResult](#nodeexportresult) * [NodeHit](#nodehit) * [NodeRevision](#noderevision) * [NodeRevisionEditor](#noderevisioneditor) * [NodeVectorMeta](#nodevectormeta) * [ObjectList](#objectlist) * [OrgMember](#orgmember) * [Organization](#organization) * [OrganizationsPage](#organizationspage) * [Passage](#passage) * [PolicyLayerVerdict](#policylayerverdict) * [PrincipalGrant](#principalgrant) * [PrincipalGrantsPage](#principalgrantspage) * [PublicOrganization](#publicorganization) * [PublicResourceRef](#publicresourceref) * [PublicResourceRefPage](#publicresourcerefpage) * [QuotaCounter](#quotacounter) * [RemoveMemoryMemberPayload](#removememorymemberpayload) * [ResendSender](#resendsender) * [ResendSendersPage](#resendsenderspage) * [ResolvedAiConfig](#resolvedaiconfig) * [RevisionResult](#revisionresult) * [ScheduleBusyInterval](#schedulebusyinterval) * [ScheduleFreeBusy](#schedulefreebusy) * [SearchReplaceFieldResult](#searchreplacefieldresult) * [SearchReplaceNodeResult](#searchreplacenoderesult) * [SearchReplaceResult](#searchreplaceresult) * [Secret](#secret) * [SecretsPage](#secretspage) * [ServerInfo](#serverinfo) * [Session](#session) * [SlackConnection](#slackconnection) * [SlackConnectionsPage](#slackconnectionspage) * [StartImpersonationResult](#startimpersonationresult) * [SummarizationRequest](#summarizationrequest) * [TeamChatMessage](#teamchatmessage) * [TeamChatMessagesPage](#teamchatmessagespage) * [TeamCollectionsPayload](#teamcollectionspayload) * [TeamRole](#teamrole) * [TeamRoleName](#teamrolename) * [TeamRolesPage](#teamrolespage) * [TeamWorkItem](#teamworkitem) * [TeamWorkItemsPage](#teamworkitemspage) * [UninstallAgentFromAppPayload](#uninstallagentfromapppayload) * [UpdateMemoryMemberRolePayload](#updatememorymemberrolepayload) * [UpdateMemoryShareRolePayload](#updatememorysharerolepayload) * [UrnResolution](#urnresolution) * [UsageActivityBucket](#usageactivitybucket) * [UsageEvent](#usageevent) * [UsageSummaryEntry](#usagesummaryentry) * [User](#user) * [UserApiKey](#userapikey) * [UserApiKeyCreateResult](#userapikeycreateresult) * [UserInvitation](#userinvitation) * [UsersPage](#userspage) * [Worker](#worker) * [WorkersPage](#workerspage) * [Inputs](#inputs) * [AgentFilter](#agentfilter) * [AiServiceConfigFilter](#aiserviceconfigfilter) * [AppFilter](#appfilter) * [AssetFilter](#assetfilter) * [BeginAssetUploadInput](#beginassetuploadinput) * [BeginAssetUploadV2Input](#beginassetuploadv2input) * [CalendarEventTimeInput](#calendareventtimeinput) * [CompleteAssetUploadInput](#completeassetuploadinput) * [CreateAgentScheduleInput](#createagentscheduleinput) * [CreateAgentWebhookInput](#createagentwebhookinput) * [CreateAssetReferenceNodeInput](#createassetreferencenodeinput) * [CreateNodeInput](#createnodeinput) * [DashboardWidgetInput](#dashboardwidgetinput) * [EdgeFilter](#edgefilter) * [EdgeInput](#edgeinput) * [GrantCreditsInput](#grantcreditsinput) * [ImpersonationSessionFilter](#impersonationsessionfilter) * [ImportNodeInput](#importnodeinput) * [MemoryFilter](#memoryfilter) * [MergeMemoriesInput](#mergememoriesinput) * [MergeNodesInput](#mergenodesinput) * [MergeUsersInput](#mergeusersinput) * [MintActionTicketsInput](#mintactionticketsinput) * [NodeEdgeInput](#nodeedgeinput) * [NodeFilter](#nodefilter) * [NodeInput](#nodeinput) * [NodePropertySort](#nodepropertysort) * [NodeWhereInput](#nodewhereinput) * [OrganizationFilter](#organizationfilter) * [PublicAgentFilter](#publicagentfilter) * [SearchReplaceInNodesInput](#searchreplaceinnodesinput) * [SessionInput](#sessioninput) * [SetAgentAssetUploadEnabledInput](#setagentassetuploadenabledinput) * [SetAiModelPriceInput](#setaimodelpriceinput) * [SetQuotaLimitInput](#setquotalimitinput) * [TriggerAppRunInput](#triggerappruninput) * [UpdateAgentScheduleInput](#updateagentscheduleinput) * [UpdateNodeInput](#updatenodeinput) * [UsageEventInput](#usageeventinput) * [UserFilter](#userfilter) * [Enums](#enums) * [AccessSource](#accesssource) * [AgentType](#agenttype) * [AgentVisibility](#agentvisibility) * [AiConfigOwnerType](#aiconfigownertype) * [AppMembershipRole](#appmembershiprole) * [AppMemoryKind](#appmemorykind) * [AppRunSortField](#apprunsortfield) * [AppRunStatus](#apprunstatus) * [AppRunTriggerKind](#appruntriggerkind) * [AppType](#apptype) * [AssetScanStatus](#assetscanstatus) * [CalendarEventResponse](#calendareventresponse) * [ChatScope](#chatscope) * [CreateUserPermission](#createuserpermission) * [DashboardWidgetType](#dashboardwidgettype) * [DriveExportFormat](#driveexportformat) * [DriveFileKind](#drivefilekind) * [EmailFlag](#emailflag) * [EmbeddingSource](#embeddingsource) * [FindNodesMode](#findnodesmode) * [IdentifyUserMethod](#identifyusermethod) * [ImportNodeStatus](#importnodestatus) * [MemoryClass](#memoryclass) * [MemoryMemberRole](#memorymemberrole) * [MemoryShareRole](#memorysharerole) * [MemoryValidationCheck](#memoryvalidationcheck) * [MemoryVisibility](#memoryvisibility) * [NodeExportEncoding](#nodeexportencoding) * [NodeExportFormat](#nodeexportformat) * [NodeExportSection](#nodeexportsection) * [NodeField](#nodefield) * [NodeMergeField](#nodemergefield) * [NodeSort](#nodesort) * [NodeTextField](#nodetextfield) * [NodeWhereCast](#nodewherecast) * [NodeWhereColumn](#nodewherecolumn) * [PrincipalType](#principaltype) * [Role](#role) * [SearchEntityType](#searchentitytype) * [SearchField](#searchfield) * [SearchGranularity](#searchgranularity) * [SortDirection](#sortdirection) * [SubscriptionType](#subscriptiontype) * [SyncStatus](#syncstatus) * [UploadIntent](#uploadintent) * [UsageActivityBucketSize](#usageactivitybucketsize) * [Scalars](#scalars) * [Boolean](#boolean) * [DateTime](#datetime) * [Float](#float) * [ID](#id) * [Int](#int) * [JSON](#json) * [String](#string)

Query

Field Argument Type Description
resolveUrn UrnResolution Resolve a fully-qualified, `hrn::`-prefixed Hadron URN (legacy `urn:` scheme also accepted) to the ids needed to reach its canonical page. Returns null when the URN is unresolvable (not found) OR the caller lacks access. Unlike the dedicated per-kind queries — which throw `Forbidden` on no-access — this query deliberately collapses both not-found and no-access to null, so a redirect resolver can 404 uniformly without disclosing which case it was. Per-kind access uses the SAME authorization rules as the dedicated queries (memory/org/agent: org membership; app: org ADMIN; node: memoryAccessFilter), only with the throw replaced by a null return. The `hrn::` prefix (legacy `urn::` also accepted) is the dispatch key — bare URNs without a type prefix are ambiguous across kinds (`root:slug` could be a memory or an agent) and resolve to null.
urn String!
effectiveAccess EffectiveAccess! issue #323: resolve the effective access a single user has to a single resource, with the grants that confer it. The authoritative backing for the 'hadron access check <user> <resource>' audit command — one resolver that reuses the server's authorization rules instead of re-deriving them client-side. 'user' (the subject) accepts a User ID or a hrn:user:<handle> URN (spec cor:urn:010:01). 'resource' is dispatched on URN type the same way resolveUrn dispatches: a memory, node, app, agent, org, or user MUST be a fully-qualified hrn:<type>: URN (a bare id is ambiguous across those kinds). A bare id with no scheme prefix is treated as an AiServiceConfig id — the only URN-less resource kind. Authorization (who may CALL this): the same visibility bar already enforced on the underlying grant tables — a platform ADMIN/OWNER, an ADMIN/OWNER of the resource's owning org, or (for a strict-owner memory) the memory's principal. Everyone else gets FORBIDDEN, NOT a silent empty result, so the command can't probe access it isn't allowed to audit. A subject with no access is a SUCCESS with an empty grants list (all capabilities false, role null) — not NOT_FOUND. An unresolvable or unknown resource ref is NOT_FOUND.
user ID!
resource ID!
node Node The uniform single-node read (#473) — subsumes the former nodeById(id:) and node(loc:, memory:) split. 'ref' accepts, in dispatch order: 1. a primary key (the unambiguous read — the old nodeById), 2. a fully-qualified node URN (`hrn:node:::`, legacy `urn:` scheme accepted), 3. a bare loc — scoped by 'memoryRef' (an ID or URN) when given; unscoped, it resolves across every readable memory and a cross-memory loc collision is REJECTED with extensions.code AMBIGUOUS_NODE_LOC (listing the candidate memoryIds) rather than silently returning one (#335). An unprefixed 3+-segment ref whose first two segments name a readable memory is treated as form 2 (a full URN); pass 'memoryRef' to force loc interpretation. raw: true skips Mustache template compilation. Soft-deleted nodes do not resolve. Access: the caller's readable-memory set (same gate the old queries used); denied and missing are both null.
ref ID!
memoryRef ID
raw Boolean
nodeExport NodeExportResult!
id ID!
format NodeExportFormat
full Boolean
sections [NodeExportSection!]
findNodes FindNodesResult! Unified node search (cor:api:090) — the single node list + retrieval surface (it replaced the removed `nodes` filter/list and `nodeSearch` rank queries in PR3). Omit `query` for a filtered list in deterministic order (subsumes `nodes`); pass `query` to rank by `mode` (keyword | vector | hybrid | regex). Lexical modes honor boolean operators (`(a OR b) AND c`, quoted phrases, NOT/-) — operator words are UPPERCASE-ONLY, so natural phrases like 'not sure' search literally — and `fields` as a ranking weight-mask. Malformed boolean syntax (unmatched parenthesis, unterminated quote) DEGRADES to a literal phrase search flagged `degraded: 'literal_fallback'` instead of erroring; only mode: regex fails loudly on bad syntax. `filter` is the structured, AND-combined filter context (SYSTEM memory class excluded by default; explicit wins). Returns a scored-hit envelope. Access-scoped identically to the per-kind node queries. orgId (optional) narrows the accessible scope to a single organization the caller is a member of; a non-member orgId returns an empty envelope (total 0, no existence disclosure). Combined with filter.isRunnable: true this is the canonical "the caller's runnable task nodes in one org" query (there is no separate myTasks surface — a task is simply an isRunnable node).
query String
mode FindNodesMode
filter NodeFilter
fields [NodeField!]
sort NodeSort
sortProperty NodePropertySort #719 — order by a properties/data JSON path; overrides sort when present.
expand Int
granularity SearchGranularity
orgId ID
limit Int
offset Int
minScore Float Optional absolute relevance floor (cor:api:090 / #497): drop ranked hits whose score is below this value. Scores are NOT comparable across modes, so the meaningful scale differs per mode (keyword ts_rank is roughly 0..a-few; vector cosine similarity is 0..1; hybrid is a small RRF fraction) — pick a floor for the mode in use. Ignored on the no-query browse list (unscored) and never trims expand-neighbours. A floor returns fewer hits, never weaker ones.
object JSON #745 — read one object by its id (the object store's flat projection of a node). Returns a JSON object { id, type, ...fields } or null if not found/inaccessible. The object store is the legible sugar surface over structured storage (an object IS a node); see createObject / findObjects.
ref ID!
findObjects ObjectList! #745 — query a collection. Returns objects of the given type (the collection / node objectType) in the memory, projected flat. 'match' is an equality shorthand ({ field: value }) desugared to a where predicate with each field's cast inferred from the memory schema; 'where' is the full #719 predicate (ANDed with match); 'sort' is a single-field shorthand desugared to a property-path sort.
memoryRef String! Memory ID or fully-qualified URN (hrn:memory:...) — relative refs are rejected (spec 022).
type String!
match JSON Equality shorthand: { field: value, ... } becomes an AND of eq predicates (cast inferred from the schema).
where JSON Full #719 structured predicate over the object's fields (ANDed with match).
sort JSON Single-field sort: a map of one field to the direction string 'asc' or 'desc', e.g. { fundingUsd: 'desc' }.
limit Int
offset Int
globalSearch GlobalSearchResult! Cross-entity global search across organizations, memories, nodes, agents, apps, AiServiceConfigs, and users — one ranked, flat list of hits. By default the query shape is smart-sniffed: a PK-shaped input does an exact id lookup, a URN-shaped input matches URNs, anything else matches name + URN. Pass `fields` to force specific fields (overrides the sniff) and `entityTypes` to restrict the kinds searched. Every hit is access-scoped to the caller exactly as the per-kind queries are. Distinct from `findNodes`, which is the node-only, vector-aware retrieval surface. orgId (optional) narrows the org-anchored slices to a single organization: node/memory hits are confined to that org's memories and organization / agent / app / aiServiceConfig hits to that org. (The user slice is NOT org-scoped — users aren't org-owned; they stay gated by the caller's user-visibility as usual.) Omit for the cross-org union (default). A caller who is not a member of orgId gets an empty page (total: 0) — no org-existence disclosure; membership-gated for everyone, no admin bypass. Paged in the repo standard idiom: limit (default 50, capped 200) + offset (default 0), with total in the envelope. NOTE: total is the ranked-match count WITHIN the per-entity candidate bound (a fixed cap per entity type), not an unbounded COUNT — deep paging past that bound is not surfaced. See GlobalSearchResult.total.
query String!
entityTypes [SearchEntityType!]
fields [SearchField!]
orgId ID
limit Int
offset Int
edge Edge The uniform single-edge read (#473) — edges are first-class, loc-addressed peers of nodes (spec 037). 'ref' accepts a primary key or a fully-qualified edge URN (`hrn:edge:::`; the edge's memory is its SOURCE node's memory). Access: the edge's memory must be in the caller's readable set; denied and missing are both null.
ref ID!
edges EdgesPage! Uniform paginated edge list (#473). Scope: edges whose (denormalized, source-side) memory the caller can read, AND-narrowed by the filter. orgId follows cor:api:100:01 (member -> scope, non-member -> empty page, no disclosure, no admin bypass). Deterministic loc-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
filter EdgeFilter
orgId ID
limit Int
offset Int
nodeBatch NodeBatchResult! Batch read (spec cor:api:040) — the full node projection (select any Node fields, including content + edges) for MANY nodes in one call, eliminating the N+1 of one node(ref:) per node (e.g. 'spec lint --all'). Provide EITHER 'refs' (explicit set, returned in input order) OR 'memory' + 'locPrefix' (subtree, loc order) — not both. Each entry of 'refs' is a primary key OR a fully-qualified node URN (cor:api:140), so a URN-holding caller batches in ONE call instead of resolving each ref first. The split on a bad ref is by KIND, not by luck: a ref whose SHAPE is wrong errors the call — unqualified / relative (UrnNotQualifiedError) or a URN of the wrong entity type, e.g. 'hrn:mem:...' (BAD_USER_INPUT) — while a well-formed ref that names nothing the caller may read comes back in 'unavailable'. A caller mistake stays loud instead of hiding among denials. Per-node access is applied independently AFTER resolution: denied or missing refs come back in 'unavailable' and never fail the call. Bounded by hard caps — over the node-count cap throws BAD_USER_INPUT; over the response-size cap returns a partial result with 'truncated: true' and the dropped refs in 'omitted' (never a silent short read). Node content is returned raw — Mustache templates are NOT compiled (unlike the single-node 'node' read), since this is a bulk source read for lint / audit / migration and compiling per node would re-introduce the N+1 it eliminates.
refs [ID!]
memory ID
locPrefix String
nodeUsage ⚠️ [UsageEvent!]! DEPRECATED: use usageEvents(loc: <loc>). Carried for source-compat; there are no known callers (checked across portal / CLI / docs at #802). Usage events for a node loc, most recent first. The migration is a rename, not a rewrite — usageEvents' loc argument is the SAME verbatim exact nodeLoc match under the same gate, so nodeUsage(loc: "x", limit: n) becomes usageEvents(loc: "x", limit: n) with identical results and identical access scoping: nodeUsage(loc: 'cor:acl:010:01', limit: 20) usageEvents(loc: 'cor:acl:010:01', limit: 20) Do NOT migrate to usageEvents(nodeId: <loc>): nodeId is shape-classified, and a hierarchical loc with 3+ colon-separated segments (like the spec citation above) qualifies as node-URN shape and routes to ref resolution instead — NODE_NOT_FOUND, or another node's events (PR-986 review). The loc argument exists precisely so the migration needs no shape caveats. usageEvents is a strict superset: nodeId accepts a PK or a fully-qualified node URN (memory-precise — a bare loc cannot disambiguate the same loc in two memories), plus type filtering, memoryId scoping and offset paging. It is also the surface that gets extended; nodeUsage will not grow arguments. Access control is identical and unchanged (#802) — see usageEvents below. Deprecated for redundancy, NOT because this field is unsafe.

⚠️ DEPRECATED

Use usageEvents(loc: <loc>) — identical exact-match loc semantics and access scoping, plus PK/URN refs via nodeId, type filtering, memoryId scoping and paging (#802).
loc String!
limit Int
usageEvents [UsageEvent!]!
type String
memoryId ID
nodeId ID
loc String
limit Int
offset Int
nodeRevisions [NodeRevision!]! Revision history for a node, most recent first. Accepts the node's ID or URN. Access-gated on the node's memory: a node whose memory the caller can't read returns an empty list (no existence disclosure).
nodeRef ID!
limit Int
nodeRevision NodeRevision A single node-revision snapshot by its id (#617 Display). Access-gated on the snapshot's node memory (read): null when the revision does not exist OR the caller cannot read the node's current memory OR the memory the snapshot was captured in (per-snapshot gating mirrors nodeRevisions — a moved node keeps its id, so a snapshot may belong to a memory the caller cannot read). A soft-deleted node is also null (its history drops out of every read surface). Null, never an error, so there is no existence disclosure.
revisionId ID!
memoryUsageSummary [UsageSummaryEntry!]! Aggregated usage counts per node and type for a memory. Accepts the entity's ID or URN.
memoryRef ID!
usageActivity [UsageActivityBucket!]! #796 — read/write activity counts, bucketed by time. Default scope is the caller's OWN events across everything they touched; pass memoryRefs to switch to all users' events attributed to ANY of those memories (#805), each of which requires read access. The result is the UNION as a single read/write series, not a per-memory breakdown; since every event carries exactly one memory, the union equals the sum of the separate scopes with no double-counting. A ref the caller cannot read — or that does not exist — is silently dropped from the union rather than failing the query, so the result never reveals which of the named memories exist. Passing an empty list therefore yields an empty result, NOT the caller's own activity. A malformed ref is still an error. At most 20 refs. Only non-empty buckets are returned — zero-fill the window client-side. Counts only events of type read and write. Window bounds are ISO-8601 strings: from is INCLUSIVE, to is EXCLUSIVE, so adjacent windows tile without double-counting. Defaults to the 7 days ending now; a span longer than 366 days is clamped by moving from forward.
from String Window start, inclusive. Default: to minus 7 days.
to String Window end, exclusive. Default: now.
bucket UsageActivityBucketSize
memoryRefs [ID!] Switch scope to all users of these memories, unioned (each ID or URN; max 20).
timeZone String IANA zone deciding where bucket boundaries fall. Default UTC.
sessions [Session!]! workerRef (#974): only sessions bound to that Worker (by id), newest first - the 'taken right now' / 'last driven by' read (cor:agt:020:03).
type String
repo String
customerId String
workerRef String
limit Int
offset Int
session Session
id ID!
user User The uniform single-user read (#473). 'ref' accepts a primary key or a `hrn:user:` URN. Resolves for the user themselves, a platform ADMIN/OWNER, or a caller sharing at least one organization with the target (the resolveUrn user gate); anyone else gets null — denied and missing are indistinguishable, preserving #384's anti-enumeration posture. PII fields (name/email) stay gated by the User field resolvers.
ref ID!
users UsersPage! Uniform paginated user list (#473) — replaces the admin-only users list and searchUsers. Platform ADMIN/OWNER: every live user, filter.query optional. Everyone else: filter.query is REQUIRED (blank/omitted -> empty page) and matching is enumeration-safe per cor:acl:070:02 — handle / githubUsername by substring, email by exact match, name only where the viewer may see it (self/admin/co-member). Name-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
filter UserFilter
limit Int
offset Int
me User
authContext AuthContext The resolved principal for the credential on THIS request (issue #562). Credential-type-agnostic: works for personal API keys, JWT sessions, and App keys alike — unlike me, which is null for a valid App credential. Returns null when the presented credential does not resolve (identically for revoked / never-existed / malformed — never a token oracle). See the AuthContext type for the full security posture.
impersonationSession ImpersonationSession One admin-impersonation audit record by id. Resolvable to the session's admin, an org ADMIN/OWNER of its org, or a platform admin; anyone else gets null (denied and missing are indistinguishable).
ref ID!
impersonationSessions ImpersonationSessionList! Uniform paginated admin-impersonation audit list (createdAt-desc). Platform admins may omit orgId (unscoped); everyone else must name an org they are a live ADMIN/OWNER of. filter.activeOnly keeps only currently-live sessions. limit default 50 / cap 200.
orgId String
filter ImpersonationSessionFilter
limit Int
offset Int
organizations OrganizationsPage! Uniform paginated organization list (#473) — replaces organizations + myOrganizations. Scope: the caller's memberships; platform ADMIN/OWNER get every live org (the established admin unscoped reach) unless filter.memberOnly restricts the list to their own memberships (the old myOrganizations view, as a slice-as-filter). Name-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
filter OrganizationFilter
limit Int
offset Int
organization Organization Fetch an Organization (org member or platform ADMIN). 'ref' accepts the entity's ID or URN.
ref ID!
publicOrganization PublicOrganization cor:acl:080:02 — the sanitized PUBLIC view of a DISCOVERABLE organization, safe for a non-member. Returns non-null only when the org exposes a public footprint (a PUBLIC memory/agent, or listedOnMarketplace); otherwise null (denied is indistinguishable from not-found — anti-enumeration). Never exposes members, private memories, apps, or credentials. 'ref' accepts the org ID or URN.
ref ID!
marketplaceOrganizations PublicResourceRefPage! cor:acl:080:04 — browse the marketplace catalogue: resources opted-in via listedOnMarketplace AND publicly accessible. Public (no membership required); sanitized flat refs only (never members / private data / credentials). One paginated query per resource type; ordered by (name, id) for stable paging. - marketplaceOrganizations: listedOnMarketplace orgs. - marketplaceAgents: listed + visibility=PUBLIC agents. - marketplaceMemories: listed + public-readable memories. Drill into an org's public footprint via publicOrganization(ref:).
limit Int
offset Int
marketplaceAgents PublicResourceRefPage!
limit Int
offset Int
marketplaceMemories PublicResourceRefPage!
limit Int
offset Int
invitation UserInvitation
slug String!
memory Memory Fetch a single Memory (org member, shared-read gate, or platform ADMIN). 'ref' accepts the entity's ID or URN.
ref ID!
memories MemoriesPage! Uniform paginated memory list (#473) — replaces myMemories, publicMemories, and orgSystemMemories. Default scope: the caller's union — (1) their OWN personal/private memories (always; they are user-owned and show in every org context), (2) memories their member orgs own, (3) memories their member orgs subscribe to. Per-user agent memories (userMemoryOfAgentId) are excluded. App-key callers get the union of their installed Agents' memory items. filter.visibility: PUBLIC selects the public marketplace slice instead (every PUBLIC memory — the old publicMemories). filter.memoryClasses restricts to exactly the listed classes; omitted, the noisy agent system class is hidden by default (pass it explicitly to surface system memories, e.g. the old orgSystemMemories = orgId + memoryClasses: [system]). orgId follows cor:api:100:01: member -> the "active organization" view (own personal/private + that org's owned + subscribed memories); non-member -> empty page, no existence disclosure, no admin bypass. Name-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
filter MemoryFilter
orgId ID
limit Int
offset Int
dashboardWidgets [DashboardWidget!]! #772 — the caller's placed dashboard widgets, ordered by position. Empty for a non-user (App-key) caller.
dashboardWidgetData [DashboardWidgetData!]! #797 — data for each of the caller's PLACED widgets, in position order, one entry per placement built from its own config. Empty for a non-user caller.
dashboardWidgetPresets [DashboardWidgetPreset!]! #806 — the caller's saved widget configurations, name-ordered (id tiebreak), optionally narrowed to one widget type. Empty for a non-user caller; never another user's presets.
type DashboardWidgetType Return only presets for this widget type. Omit for all of them.
exchangeConnections [ExchangeConnection!]! Exchange connections for an org. Accepts the entity's ID or URN.
orgId ID!
slackConnection SlackConnection Fetch one Slack connection by id (spec 043). Returns null when the row does not exist OR the caller is not a member of its org — no existence disclosure.
ref ID!
slackConnections SlackConnectionsPage! Uniform paginated Slack-connection list (cor:api:120). Default scope: the caller's member orgs. orgId follows cor:api:100:01 (member -> that org, non-member -> empty page, no disclosure, no admin bypass). Team-name-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
orgId ID
limit Int
offset Int
mcpServer McpServer Fetch one registered external MCP server by id. Returns null when the row does not exist OR the caller is not a member of its org — no existence disclosure.
ref ID!
mcpServers McpServersPage! Uniform paginated MCP-server list (cor:api:120). Default scope: the caller's member orgs. orgId follows cor:api:100:01 (member -> that org, non-member -> empty page, no disclosure, no admin bypass). Slug-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
orgId ID
limit Int
offset Int
mcpServerTools [McpServerTool!] Live tools/list passthrough for one registered server (org member) — what authors browse to pick data.tools entries. Applies the same admissibility filter as run-tool materialization, so what it returns IS what a run can call: a disabled server errors with MCP_SERVER_DISABLED rather than listing uncallable tools. Null when the row does not exist or the caller is not a member of its org; errors with MCP_TOOL_* codes when the conduit or the external server fails.
ref ID!
secret Secret Fetch one secret's inspectable half (never the value). Null when the row does not exist OR the caller is not entitled to its owner scope — no existence disclosure. Entitlement: user -> that user; org -> org member; app -> app owner or org member; memory -> memory READ.
ref ID!
secrets SecretsPage! Paginated secret list for ONE owner scope (the hadron secret ls surface). ownerRef accepts ID or URN (cor:api:140) and defaults to the caller for ownerType user. An unresolvable ref or a non-entitled owner yields an empty page — no disclosure. Name-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
ownerType String!
ownerRef ID
limit Int
offset Int
homeAssistantInstance HomeAssistantInstance Fetch one registered Home Assistant instance (org member). Null when the row does not exist OR the caller is not a member of its org — no existence disclosure.
ref ID!
homeAssistantInstances HomeAssistantInstancesPage! Uniform paginated Home Assistant instance list (cor:api:120). Default scope: the caller's member orgs. orgId follows cor:api:100:01 (member -> that org, non-member -> empty page, no disclosure, no admin bypass). Slug-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
orgId ID
limit Int
offset Int
resendSender ResendSender Fetch one sanitized BYO Resend sender config; null for missing or inaccessible.
ref ID!
resendSenders ResendSendersPage! Uniform paginated BYO Resend sender list scoped to the caller's member orgs.
orgId ID
limit Int
offset Int
homeAssistantInstanceOps [HomeAssistantOp!] The ops one registered instance exposes (the closed catalog filtered by the row's allowlist) — what authors browse to pick data.tools entries; what this returns IS what a run can call. Null when the row does not exist or the caller is not a member of its org; a disabled instance errors with HA_INSTANCE_DISABLED.
ref ID!
exchangeMessages [ExchangeMessage!]!
connectionId ID!
top Int
filter String Deprecated: raw provider filters are gone; only 'isRead eq false' still translates. Use unreadOnly.
unreadOnly Boolean
exchangeFolders [ExchangeFolder!]!
connectionId ID!
calendars [CalendarInfo!]! Calendars the connected account can see. Grant scope: calendar.read.
connectionRef ID!
calendarEvents [CalendarEvent!]! Events in a time window (recurring events expand to instances, ordered chronologically). start/end are RFC 3339; calendarId defaults to the account's primary calendar. Grant scope: calendar.read.
connectionRef ID!
calendarId String
start String
end String
query String Free-text search over event fields.
top Int
calendarEvent CalendarEvent! One event by id. Grant scope: calendar.read.
connectionRef ID!
eventId ID!
calendarId String
calendarSchedule [ScheduleFreeBusy!]! Free/busy intervals for one or more schedules (calendar ids or addresses the account can read; defaults to the account's primary calendar). Structurally capped at yes/no busy windows — never event contents. Grant scope: calendar.freebusy.
connectionRef ID!
start String!
end String!
schedules [String!]
driveFiles DriveFilePage! Browse or search the connected drive. With no search criteria, lists the children of folderId (default: the drive root), folders first. Any of query/nameContains/mimeType/modifiedAfter switches to a search, most recently modified first. Grant scope: drive.read.
connectionRef ID!
folderId ID
query String Full-text search over file content.
nameContains String
mimeType String Exact MIME type filter.
modifiedAfter String RFC 3339 lower bound on last modification.
top Int
pageToken String
driveFile DriveFile! File metadata by id. Grant scope: drive.read.
connectionRef ID!
fileId ID!
driveFileExport DriveFileExport! Export a drive file as text: native documents convert (Docs export natively to MARKDOWN; spreadsheets to TEXT as CSV; presentations to TEXT), text files return verbatim. Binary files are refused (typed validation error). Size-capped with a typed file_too_large — never truncated. Grant scope: drive.read.
connectionRef ID!
fileId ID!
format DriveExportFormat
apps AppsPage! Uniform paginated app list (#473) — replaces the org-ADMIN apps(orgId!) and the member myApps. Scope: Apps in the caller's member orgs (App doesn't carry a userId, so org membership is the routing); platform ADMIN/OWNER unscoped get every live App. orgId follows cor:api:100:01 (member -> scope, non-member -> empty page, no disclosure, no admin bypass). Name-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only. filter.ownedByMe (#782) narrows to the caller's own user-owned (org-less) Apps for every caller including platform admins.
filter AppFilter
orgId ID
limit Int
offset Int
app App Fetch an App (member of the App's org, or platform ADMIN — the myApps exposure bar; #473 relaxed this from org ADMIN for read parity with the list). 'ref' accepts the entity's ID or URN.
ref ID!
myApp App
agent Agent The uniform single-agent read (#473) — the first top-level Agent query; previously Agents were reachable only via Organization.agents / App.agents nesting. Gate mirrors resolveUrn's agent branch: member of the Agent's org or platform ADMIN/OWNER; denied throws Forbidden, missing is null. 'ref' accepts the entity's ID or URN.
ref ID!
agents AgentsPage! Uniform paginated agent list (#473). Scope: Agents owned by the caller's member orgs; platform ADMIN/OWNER unscoped get every live Agent. orgId follows cor:api:100:01 (member -> scope, non-member -> empty page, no disclosure, no admin bypass). filter narrows by type / visibility. filter.ownedByMe (#782) narrows to the caller's own user-owned (org-less) agents for every caller including platform admins. Name-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
filter AgentFilter
orgId ID
limit Int
offset Int
publicAgents AgentsPage! #551 — the public-agent marketplace slice: every live PUBLIC agent, readable by ANY caller (no membership required), so an org can discover foreign public agents to subscribe to (008/009 AgentOrgGrant; hadron-portal#486). Kept SEPARATE from agents() on purpose: agents() stays bounded to the caller's own orgs, and the cross-org widening is this explicit, paginated surface rather than a value in a filter. filter.type narrows by AgentType; filter.visibility is IGNORED (the slice is PUBLIC by definition). Field-level exposure: a PUBLIC agent publishes its OWN definition (systemPrompt / systemMemoryId / memoryItems / imports) to every caller — that is what a marketplace listing is (#551). The fields that surface OTHER tenants (apps / appAgents / appCount / orgGrants / importedBy) are scoped to the caller's own access and come back empty for an outsider (#552, #757). Name-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
filter PublicAgentFilter
limit Int
offset Int
myAgentSubscriptions [AgentSubscription!]!
agentSubscriptions [AgentSubscription!]! 005-agent-subscription FR-022: list all AgentSubscriptions for an Agent. Authorized for ADMIN/OWNER of the Agent's owning org. Accepts the entity's ID or URN.
agentRef ID!
appNodes [Node!]! All nodes accessible by an App: the union of every installed agent's system memory (read-only) and its knowledge memoryItems (#524). Accepts the entity's ID or URN. An optional NodeFilter pushes node-level predicates server-side — e.g. filter: { isRunnable: true } to list the App's runnable task nodes (#525). The App's memory scope is authoritative, so the filter's memory-scope fields (memoryIds / memoryClasses) are rejected with BAD_USER_INPUT rather than silently ignored — use findNodes for cross-memory scoping. Only node-level predicates (nodeType, tags, isRunnable, locPrefix, createdBy, updatedAfter/Before, includeDeleted) apply. Unlike findNodes, system-memory nodes are NOT excluded by default.
appRef ID!
filter NodeFilter
limit Int
memoryNodes GraphNodesPage! Slim, paginated node list for rendering a memory's graph view (issue #466). Returns ONLY the fields a node-link graph draws (id, loc, name, nodeType, tags) — no content / abstract / data / tokens / edges — so the payload is a fraction of the full node fragment. The graph view loads this to completion (page by page) and renders nodes, THEN loads memoryEdges to draw the links. memoryRef accepts the memory's ID or URN; a memory the caller can't read returns an empty page (total 0, no existence disclosure). Paged via limit (default 1000, hard-capped 2000) + offset; total is the memory's full node count so the client can show "N of M" and know when it has paged them all. limit: 0 returns an empty page with just the total — the cheap "how big is this memory" node count. Deterministic loc-ascending order so offset paging never drops/duplicates.
memoryRef ID!
limit Int
offset Int
memoryEdges GraphEdgesPage! Slim, paginated edge list for a memory's graph view (issue #466) — phase two after memoryNodes. Returns endpoint IDs only (sourceId/targetId); the client already holds the nodes by the time it draws edges, so it maps id -> node itself. Scoped by the edge's denormalized memoryId (edges whose SOURCE is in the memory); a cross-memory edge may reference a target outside this memory, which the client drops as a dangling endpoint. Same access gate, paging, and deterministic loc-ascending order as memoryNodes.
memoryRef ID!
limit Int
offset Int
appAIConfig AppAIConfig Decrypted AI config for an App (org ADMIN of the App's org). Accepts the entity's ID or URN.
appRef ID!
appKeys [AppKey!]! List keys for an App (org ADMIN of the App's org). Accepts the entity's ID or URN.
appRef ID!
myUserApiKeys [UserApiKey!]! 025-oauth-for-mcp FR-004: list the calling User's API keys (active + revoked, createdAt DESC). Powers Phase 3's portal revocation UI (SC-006). Rejected with UNAUTHENTICATED for AppKey-resolved callers (no user in context). PR-137 review delta D5 — Query not present in PR 137.
agentAIConfig AgentAIConfig Agent AI config (org ADMIN) — returns the decrypted API key so the portal backend can make LLM calls on behalf of the user. 036-ai-service-config: registry-backed (the Agent's config named 'default'). Prefer resolveAIConfig for new callers. Accepts the entity's ID or URN.
agentRef ID!
aiServiceConfig AiServiceConfig The uniform single-config read (#473). 'ref' is the config's ID — AiServiceConfig is the one URN-less entity (matching resolveUrn / effectiveAccess dispatch). Masked: never returns key material, only hasApiKey + apiKeyPreview (resolveAIConfig is the privileged decrypted read). Auth mirrors the list: platform ADMIN/OWNER for HADRON_SERVER-owned configs, org ADMIN of the owning org otherwise; denied throws Forbidden, missing is null.
ref ID!
aiServiceConfigs AiServiceConfigsPage! 036-ai-service-config: masked, paginated list of AI configs (#473). Never returns key material — only hasApiKey + apiKeyPreview. filter names the owning entity. Auth: platform ADMIN/OWNER for HADRON_SERVER owners; org ADMIN of the owning org for ORGANIZATION / APP / AGENT owners. filter omitted entirely = the platform ADMIN/OWNER cross-owner view of every config (non-admin callers must filter). Name-ascending order (id tiebreak); limit default 50 / cap 200; limit: 0 -> count only.
filter AiServiceConfigFilter
limit Int
offset Int
resolveAIConfig ResolvedAiConfig! 036-ai-service-config: resolve a config name for an execution context and return the DECRYPTED credentials (privileged; successor to agentAIConfig/appAIConfig). Walk: App -> Agent -> Org (of the App, else of the Agent) -> HadronServer; disabled configs are skipped. When name is omitted, 'default' is resolved. When an explicit name misses, resolution falls back to 'default'; if that also misses, errors with NoAiConfigAvailableError. Consumers (webhooks, scheduled tasks, the portal chatbot) reference configs by name only — pass the name plus the execution context, never credentials. Auth: org ADMIN of the effective context org, or platform ADMIN/OWNER (required when no app/agent context is given). appRef/agentRef accept the entity's ID or URN.
name String
appRef ID
agentRef ID
resolveAiServiceConfigs [AiServiceConfig!]! 036-ai-service-config: the MASKED set of configs RESOLVABLE in an execution context — every distinct config name a chat in this context could select. Populates a config picker in the chatbot UI. Same walk as resolveAIConfig (App -> Agent -> Org (of the App, else of the Agent) -> HadronServer), but returns ALL names instead of resolving one: configs are deduped by name with the innermost owner winning, so each entry is the row resolveAIConfig would return for that name. Only the Agent named here contributes — sibling Agents installed in the same App are not consulted. Disabled configs are skipped. Never returns key material (hasApiKey + apiKeyPreview only). Auth: scoped to one App's chat context. A non-admin caller MUST pass an appRef, be a member of that App, and (when an agentRef is given) the Agent must be installed in that App. Because the result is masked (no key material), App membership — not org admin — is the bar, unlike resolveAIConfig and the aiServiceConfigs management list. Platform ADMIN/OWNER are always allowed and may omit appRef. appRef/agentRef accept the entity's ID or URN.
appRef ID
agentRef ID
myChats [Chat!]! Saved chats for the current user in their personal memory for an agent. Newest first. Accepts the entity's ID or URN.
agentRef ID!
limit Int
offset Int
chatHistory [ChatMessage!]!
chatId String!
limit Int
teamChatMessages TeamChatMessagesPage! Read a team App's chat (#939), seq-ordered ascending, as a uniform { items, total } page. sinceSeq is a watermark cursor: only messages with seq STRICTLY GREATER than it are returned (pass the last seq you have seen). mentionsRef filters to messages whose stored envelope mentions the referenced worker (a Worker id or name of THIS App, retired included) or user (handle/id) — matching runs against the mention tokens extracted at write time, never by re-parsing bodies. The ref must name this App's own staff or members (a Worker of the App, an AppMember, or the caller); an unresolvable or foreign mentionsRef yields the empty page identically (no existence oracle). limit defaults to 50 (cap 200); limit: 0 returns only total. Authorization: an AppMember of the App (any role), an org member with CONTRIBUTOR+ on the App's org, the owner of a user-owned App, or the App's own key (a pure App-key principal may READ its team chat). appRef and mentionsRef accept the entity's ID or URN.
appRef ID!
sinceSeq Int
mentionsRef ID
limit Int
offset Int
teamWorkItems TeamWorkItemsPage! Read a team App's worklog (#947) — the provenance query: which sessions (and transcripts) produced this PR? Newest first, as a uniform { items, total } page. ref accepts ANY accepted spelling (URL, short form, canonical) and is matched tool-awarely: with tool 'github' (or none) it is normalized, so 'https://github.com/o/r/pull/371' and 'o/r#371' return the same records; with another tool it matches the stored verbatim ref; with no tool it matches either spelling. sessionRef / tool / kind are equality filters; kind must be one of pr, issue, commit, branch, repo when given. limit defaults to 50 (cap 200); limit: 0 returns only total. Authorization: an AppMember of the App (any role), an org member with CONTRIBUTOR+ on the App's org, the owner of a user-owned App, or the App's own key (a pure App-key principal may READ its own App's worklog). appRef accepts the entity's ID or URN; sessionRef is the session id.
appRef ID!
ref String
sessionRef ID
tool String
kind String
limit Int
offset Int
worker Worker One Worker by ref (#974) — its id, its URN (#991), or (with appRef) its NAME (#1015), the ergonomic handle a human already knows. The name form is ADDITIVE: it is activated by appRef, since a name is unique only within an App. Without appRef the ref must be an id or URN, and anything else refuses WORKER_NOT_FOUND as before. An id or URN wins over appRef rather than being checked against it, so a typo'd URN never degrades into a roster search. Selecting `prompt` re-renders the worker's boot briefing live from the role agent's template — the read that lets an agent recover a briefing it lost to a context compaction, instead of opening a second session or forcing a takeover of itself. Authorization: an AppMember of the worker's App (any role), an org member with CONTRIBUTOR+ on its org, the owner of a user-owned App, or the App's own key. For the NAME form the gate runs BEFORE the lookup and a denial is reported as WORKER_NOT_FOUND, so the roster is not an existence oracle.
ref ID!
appRef ID
workers WorkersPage! A team App's STAFF (#974, cor:agt:020:01 — Workers are the staff; the AppAgent join is the install roster): the App's castings, oldest first, as a uniform { items, total } page. Retired castings are hidden unless includeRetired. Same authorization as worker. appRef accepts the App's ID or URN.
appRef ID!
includeRetired Boolean
limit Int
offset Int
teamRoles TeamRolesPage! An App's role definitions (#960): every roles:<role> node in the Team Agent's system memory, projected with the one answer a client cannot compute — which register names are still FREE, judged against the App's full worker roster (names are unique per App, case-insensitively, forever — cor:agt:020:02). Ordered by role slug. Same read authorization as workers. teamAgentRef disambiguates when more than one installed agent carries a roles: branch (TEAM_AGENT_AMBIGUOUS otherwise); an encrypted system memory without an active session key refuses SESSION_EXPIRED.
appRef ID!
teamAgentRef ID
limit Int
offset Int
castWorkerPreview CastWorkerPreview! Dry-run castWorker (#964): run the cast's exact resolution — same arguments, same typed refusals (WORKER_AGENT_NOT_FOUND / _AMBIGUOUS / _NOT_INSTALLED, WORKER_ROLE_NOT_FOUND, WORKER_REGISTER_EXHAUSTED, WORKER_NAME_TAKEN, APP_UNINSTALLED, TEAM_AGENT_NOT_FOUND / _NOT_INSTALLED / _AMBIGUOUS, and SESSION_EXPIRED for an encrypted register without an active session key), same MINT gate — up to but not including the writes, and return what would be created. A Query, not a dryRun flag: casting a name is the one irreversible act in the team feature (cor:agt:020:02 — permanence), and previewing it must not need a mutation permission model or a fake Worker row. THE PREVIEW RESERVES NOTHING: no lease exists by law (cor:agt:020:03), so a previewed name may be gone at cast time — by design; the cast's uniqueness constraint remains the only allocation primitive.
appRef ID!
agentRef ID
role String
name String
teamAgentRef ID
promptOverride String
agentAssets AssetListResult!
agentUrn String!
mimeType String
skip Int
count Int
includeDeleted Boolean
memoryAssets AssetListResult! v2 (spec 006) — memory-addressed listing. Returns every asset attached to the memory; the gate is the memory's read access. The replacement for agentAssets in the v2 surface. Set mine: true to narrow to the caller's own uploads — a filter on top of the read gate, not a substitute for it. Accepts the entity's ID or URN.
memoryId ID!
mimeType String
skip Int
count Int
includeDeleted Boolean
mine Boolean
assets AssetsPage! Cross-memory asset list (#891) — every file the caller can reach, which is every asset held by a memory they can read. The uniform find-many surface for assets (spec cor:api:120); memoryAssets stays as the per-memory one. The three tabs of a top-level Assets section are filters over this, not separate queries: mine: true, no filter, and orgId respectively.
filter AssetFilter
orgId ID
limit Int
offset Int
assetDownloadUrl AssetDownloadUrl!
assetId ID!
ttlSeconds Int
serverInfo ServerInfo! Identity of the hadron-server this GraphQL endpoint is bound to: the server-identity version and the deployment's canonical base URL. The GraphQL counterpart to the hadron_server_info MCP tool — both read the same getDeploymentInfo() helper, so MCP and GraphQL callers get one consistent answer to "which server/API am I talking to?". 'version' is HADRON_SERVER_VERSION — the MCP/API-surface contract version, bumped when the tool/query surface changes in a caller-visible way. It is intentionally NOT the repo's package.json release version. Public — no authentication required. Does NOT expose the DATABASE_URL (it may carry credentials).
nextNode Node The next sibling node under a parent, ordered by seq (#817) — the GraphQL twin of hadron_get_next_node, so guided reading order is no longer MCP-only. parentRef / currentRef take a node PK or a fully-qualified URN (cor:api:140). Omit currentRef to get the FIRST child. Order: seq ascending; a NULL seq sorts LAST, after every explicitly ordered sibling; ties break on loc ascending. Identical to the MCP tool, so the two surfaces cannot present different reading orders. Returns null at the end of the sibling chain, and for a parent that does not exist or the caller cannot read — denied and missing are indistinguishable. A currentRef that is not among the parent's direct children is likewise null rather than an error, so it cannot probe a node's parentage. A MALFORMED ref still throws: a shape error discloses nothing about what exists. Stateless — this is a next-sibling read, not a session-backed cursor.
parentRef ID!
currentRef ID
raw Boolean
renderRunNode String! Render a run/action node WITHOUT executing it (#818) — the GraphQL twin of hadron_run_action, which despite its name executes nothing: it loads the node, resolves its dependency edges, and renders with args. runTask covers the EXECUTE half. This is the render half, for previewing a task before running it (a task run --dry-run), for reading an action's assembled instructions when the CALLER is the executor, and for debugging template/dependency resolution without side effects. A Query because it is side-effect-free, and unlike the MCP tool it records NO action-run UsageEvent — metering a preview would inflate the ledger with actions nobody took. Uses the SAME assembler runTask executes (Mustache compilation via compileTemplate; flow-ROUTING edges skipped, since they are the walker's rails rather than references), so a dry run predicts the real prompt. Two deliberate narrowings relative to execution, both fail-safe: a referenced node the caller cannot READ is omitted rather than inlined (an edge may cross memories), and an edge whose target was soft-deleted is skipped so a preview cannot resurrect removed instructions. NOTE this is NOT the legacy MCP hadron_run_action bundle, which does a literal placeholder replace and inlines every outgoing edge. Where the two differ, this one matches execution. nodeRef is a node PK or a fully-qualified URN (cor:api:140). Denied and missing both raise NODE_NOT_FOUND - no existence oracle.
nodeRef String!
args JSON
validateMemory MemoryValidationResult! Memory health audit (#819) — the GraphQL twin of hadron_validate, which was MCP-only, so the CLI, the portal and CI had no way to answer "is this memory healthy?". Every check is over server-owned state a client cannot compute: abstractOriginHash vs current content, embedding_failed_at (not projected on Node at all), and property-schema conformance. So unlike other gaps there is no slow client-side fallback. Returns TYPED findings so a caller can branch and CI can gate on totalFindings. findings is capped by limit (default 200, max 1000) while totalFindings reports the true count - so a gate is never fooled by truncation. Read gate as the rest of the memory reads.
memoryRef ID!
limit Int
appRun AppRun One run (cor:agt:010:02). ref is an AppRun ID or an hrn:apprun:<root>:<app>:<run-id> URN (#696).
ref ID!
latestAppRun AppRun The latest run of an App resolved to a concrete run (#696) — 'current/latest/previous' are queries, never magic run-ids in URN space (cor:urn:010:02). previous: true returns the run before the latest.
appRef String!
previous Boolean
appRuns AppRunsPage! The run audit list. statuses (#836) is a disjunction — 'everything still in flight' is [PENDING, RUNNING] and 'what went wrong' is [FAILED, TIMED_OUT], neither of which the single-valued status arg could express. Per conventions:multi-ref-scope-args: OMITTING it means no status filter, while an explicitly EMPTY list is the EMPTY scope and returns nothing - it never silently falls back to 'all'. Values are deduped; an unknown member is rejected by enum validation rather than dropped. status is DEPRECATED in favour of statuses. Both are accepted for one release; when both are given, statuses wins. sortBy / sortDir (#833) order the whole result set server-side, so a client table is no longer limited to sorting the page it happens to hold.
appRef String
orgRef String
statuses [AppRunStatus!]
parentRunId ID
sortBy AppRunSortField
sortDir SortDirection
limit Int
offset Int
agentSchedules AgentSchedulesPage!
appRef String!
limit Int
offset Int
agentWebhooks AgentWebhooksPage!
appRef String!
limit Int
offset Int
actionTickets ActionTicketsPage! The ticket ledger: minted, consumed-by-which-run, expired (org-ADMIN).
orgRef String!
limit Int
offset Int
connectionGrant ConnectionGrant One connection grant the caller created, by ID; null if not theirs (no existence oracle).
ref ID!
connectionGrants ConnectionGrantsPage! The caller's own connection grants; connectionRef narrows to one connection.
connectionRef String
limit Int
offset Int
principalGrant PrincipalGrant One action grant by ID - visible to the grantee or an admin of its org; null otherwise (no existence oracle).
ref ID!
principalGrants PrincipalGrantsPage! Action grants. Default: the caller's own (self-audit is never gated). An org admin passing orgRef sees that org's grants, optionally narrowed by userRef.
orgRef String
userRef String
limit Int
offset Int
quotaCounters [QuotaCounter!]! Usage-vs-limit counters for an org (+ one app when appRef given). Org-ADMIN. Rows materialize on first view, seeded with platform defaults (#510).
orgRef String!
appRef String
effectiveActionPolicy EffectiveActionPolicy! Explain the standing policy chain (org / user / app) for one action - which layer denies it (#510, cor:acl:040:02). Org-ADMIN on the app's org.
appRef String!
action String!
userRef String
aiModelPrice AiModelPrice One provider rate row by id (spec 046). Authenticated read - rates are not a secret.
ref ID!
aiModelPrices AiModelPriceList! Provider rate rows, newest effective first, optional provider/model filter (spec 046). Authenticated read.
provider String
model String
tier Int
limit Int
offset Int
creditLedgerEntries CreditLedgerEntryList! One org's append-only credit-ledger page, newest first (spec 046). Org-ADMIN.
orgRef String!
limit Int
offset Int
creditBalance CreditBalance! One org's credit balance - SUM over the append-only ledger (spec 046). Org-ADMIN.
orgRef String!

Mutation

Field Argument Type Description
startImpersonation StartImpersonationResult! Start impersonating another member of orgRef (admin support/diagnostics). Caller must be a live ADMIN/OWNER of the org (platform ADMIN/OWNER is OWNER-equivalent), the target a live member, PEER-OR-BELOW (an org ADMIN may not impersonate an org OWNER), never self. Returns the audit session and a short-TTL token (returned exactly once) whose requests run READ-ONLY as the target, scoped to this one org: other orgs and all personal-class resources stay invisible, and every mutation except stopImpersonation is rejected. Every request re-validates the session row, so stopping it (or demoting the admin) kills the token immediately.
orgRef String!
userRef String!
reason String
stopImpersonation ImpersonationSession! Stop an impersonation session (writes endedAt; the audit row is never deleted). With an impersonation token, id may be omitted (ends the token's own session — the one mutation an impersonated context may call). With a normal token, id is required and the caller must be the session's admin, an org ADMIN/OWNER of its org, or a platform admin. Idempotent on an already-ended session.
id ID
setDashboardWidgets [DashboardWidget!]! #772 — replace the caller's entire dashboard widget selection. Grid position is the array order; each widget's span (1-12) and rowSpan (1-4) are required and clamped server-side. Covers both create and update (the layout is always saved as a whole). Returns the new selection. Requires an authenticated user.
widgets [DashboardWidgetInput!]!
createDashboardWidgetPreset DashboardWidgetPreset! #806 — save a named widget configuration for the caller. 'name' is trimmed and must be 1-60 characters, unique among the caller's presets for that widget type; a duplicate is BAD_USER_INPUT. 'config' must be a JSON object within the same 4KB budget as a placement's config. Requires an authenticated user.
type DashboardWidgetType!
name String!
config JSON!
updateDashboardWidgetPreset DashboardWidgetPreset! #806 — rename a preset and/or replace its settings. Partial: an omitted (or null) argument leaves that field alone; there is no way to clear 'config', since a preset with no settings has nothing to apply. 'type' is immutable — delete and re-create to move settings to another widget. A preset the caller does not own is indistinguishable from one that does not exist (NOT_FOUND).
presetRef ID!
name String
config JSON
deleteDashboardWidgetPreset Boolean! #806 — delete one of the caller's presets. Placements already seeded from it keep their config (apply copies; there is no live link). A preset the caller does not own is indistinguishable from one that does not exist (NOT_FOUND).
presetRef ID!
createNode Node! Create a single node. Rejects with NodeLocConflictError when a live node already exists at (memoryId, loc) — creating is create-only (spec 039 Phase 0 D1); a soft-deleted node at the target loc is resurrected. 'name' is required here and only here (D4).
input CreateNodeInput!
updateNode Node! Update an existing node. Identify it by 'id' (PK or fully-qualified node URN) XOR the ('memoryId', 'loc') combo — supplying both selectors, or neither, is an error (D2). Rejects with NODE_NOT_FOUND when the target does not exist; updateNode never creates and never moves (relocation is moveNode's job, D3). Every content field is optional — omitted fields are preserved ('name' included, D4; 'abstract' keeps its omit/null/string contract; omitted 'tags' are preserved, issue #235).
input UpdateNodeInput!
updateNodeData Node!
nodeRef ID!
data JSON!
reason String
updateNodeProperties Node!
nodeRef ID!
properties JSON!
reason String
createObject JSON!
memoryRef String!
type String!
fields JSON!
key String
name String
updateObject JSON!
ref ID!
fields JSON!
reason String
deleteObject Boolean!
ref ID!
hard Boolean
searchReplaceInNodes SearchReplaceResult!
input SearchReplaceInNodesInput!
deleteNode Boolean!
nodeRef ID!
hard Boolean
recursive Boolean
cascadeCrossMemoryEdges Boolean
restoreNodeRevision Node!
revisionId ID!
truncate Boolean
deleteNodeRevision Boolean!
revisionId ID!
updateNodeRevision NodeRevision!
revisionId ID!
revLabel String
clearNodeHistory Int!
nodeRef ID!
moveNode Node!
sourceRef ID!
targetUrn String
targetMemoryRef ID
cloneNode Node!
sourceRef ID!
targetUrn String
targetMemoryRef ID
mergeNodes Node!
input MergeNodesInput!
mergeMemories Memory!
input MergeMemoriesInput!
replaceSubtree Int!
ownerRepo String!
memoryId String!
nodes [NodeInput!]!
edges [EdgeInput!]!
createEdge Edge!
sourceRef ID!
targetRef ID!
name String
loc String
description String
isRunnable Boolean
condition JSON
priority Int
data JSON
updateEdge Edge!
edgeRef ID!
name String
loc String
description String
isRunnable Boolean
condition JSON
priority Int
data JSON
deleteEdge Boolean!
edgeRef ID!
runTask String!
nodeRef String!
args JSON
appRef ID
runAsSelf Boolean
importNode ImportNodeResult! Import external content into a node (#457, sync v1). Source: exactly one of 'url' (server-fetched inline, SSRF-guarded, Readability-extracted, ~30s budget — the fetch carries NO user credentials, so authenticated pages must come as 'content') or 'content' (client-captured, e.g. the Web Clipper's authenticated DOM). Target: 'nodeUrn' XOR ('memoryId' + 'loc'); an existing node is updated IN PLACE (NodeRevision snapshot is the undo), a missing one is created. HTML converts to Markdown at the write seam (contentType defaults to text/html here, unlike createNode).
input ImportNodeInput!
createAgentSchedule AgentSchedule!
input CreateAgentScheduleInput!
updateAgentSchedule AgentSchedule!
id ID!
input UpdateAgentScheduleInput!
deleteAgentSchedule Boolean!
id ID!
triggerAppRun AppRun! Run an entry node now (MANUAL trigger) — same launch gate + kernel as a schedule.
input TriggerAppRunInput!
cancelAppRun AppRun! The kill switch manual handle: PENDING/RUNNING to CANCELLED (cor:agt:010:02).
id ID!
createAgentWebhook AgentWebhookCredentials! Create a webhook trigger — returns the URL path + platform token ONCE (D-2026-05-02).
input CreateAgentWebhookInput!
rotateAgentWebhook AgentWebhookCredentials! New secret + token; the old URL dies immediately.
id ID!
deleteAgentWebhook Boolean!
id ID!
createConnectionGrant ConnectionGrant! Grant an App install scoped access to a connection you OWN. scopes must be a subset of {mail.read, mail.send, calendar.freebusy, calendar.read}; expiresAt (ISO-8601) is optional and must be in the future. appRef is a PK or App URN.
connectionRef String!
appRef String!
scopes [String!]!
expiresAt String
revokeConnectionGrant Boolean! Revoke a connection grant you created (soft delete). Owner-only.
ref ID!
createPrincipalGrant PrincipalGrant! Grant a member extra management actions (org-ADMIN, interactive-only; design:grant-model). The grantee must be a live member of the org.
orgRef String!
userRef String!
actions [String!]!
expiresAt String
revokePrincipalGrant Boolean! Revoke an action grant (org-ADMIN, interactive-only; soft delete).
ref ID!
mintActionTickets Int! Mint comm.outbound tickets into the org ledger (org-ADMIN; cor:acl:050:04).
input MintActionTicketsInput!
setQuotaLimit QuotaCounter! Set the stored (enforced) quota limit for a scope x action (#510) - the operator dial that previously required psql. Org-ADMIN.
input SetQuotaLimitInput!
setAiModelPrice AiModelPrice! Append an effective-dated provider rate row (spec 046). PLATFORM ADMIN - org admins must never set the prices they are billed at.
input SetAiModelPriceInput!
grantCredits CreditLedgerEntry! Mint credits for an org - a positive grant ledger row (spec 046). PLATFORM ADMIN ONLY (self-grant risk); processor top-ups land here later.
input GrantCreditsInput!
updateMyPolicy User! Author YOUR user-layer action-policy link (cor:acl:040:02, #510). Null clears (= no restriction).
policy JSON
beginAssetUpload BeginAssetUploadResult!
input BeginAssetUploadInput!
completeAssetUpload Asset!
input CompleteAssetUploadInput!
setAgentAssetUploadEnabled App!
input SetAgentAssetUploadEnabledInput!
softDeleteAsset Asset!
assetId ID!
restoreAsset Asset!
assetId ID!
beginAssetUploadV2 BeginAssetUploadResult!
input BeginAssetUploadV2Input!
createAssetReferenceNode Node!
input CreateAssetReferenceNodeInput!
startSession Session!
input SessionInput!
updateSession Session! #931: update a live session's mutable provenance fields (a PR is usually opened after startSession already ran). Explicit null clears; omitted preserves; an empty update is a valid liveness touch (bumps updatedAt, which the #930 inactivity reaper counts). id-only - sessions have no URN. Gate: platform admin, the session's App, or the attributed user (not via impersonation). Updates on an ended session stay allowed (late PR-merge attribution).
id ID!
prNumber Int
branch String
endSession Session! Gate (#931): platform admin, the session's App, or the attributed user (not via impersonation).
id ID!
summary String
inputTokens Int
outputTokens Int
turnCount Int
errorCount Int
recordUsage Boolean!
event UsageEventInput!
regenerateAppKey AppCreated! App key management — revoke all active keys for an App and mint a fresh one. (See createAppKey / revokeAppKey / deleteApp below.) Accepts the entity's ID or URN.
appRef ID!
updateMyProfile User!
name String
handle String
email String
updateUserRoles User!
userId ID!
roles [Role!]!
mergeUsers User!
input MergeUsersInput!
deleteUser Boolean! Delete a user account (self-serve account deletion, Apple 5.1.1(v) / GDPR erasure posture). Requires a user credential (JWT or hdr_user key); App-key callers are rejected. Omitting userRef deletes the CALLER's own account (no role needed). A platform ADMIN/OWNER may name another user; userRef accepts the user's ID, handle, or hrn:user:<handle> URN. Any other caller naming a target receives the same FORBIDDEN error whether or not that user exists (no user-enumeration oracle). Org memberships auto-resolve: an org where the target is the only active OWNER but which still has OTHER active members BLOCKS deletion (error code SOLE_ORG_OWNER, extensions.organizations lists the blockers - transfer ownership first, nothing is deleted); an org where the target is the ONLY active member is soft-deleted with the account; plain memberships are revoked. Owned data is hard-erased: personal/private and user-owned memories, user-owned Apps and Agents (with their standard delete cascades), sessions, OAuth/handoff codes, provider connections, grants, shares, subscriptions, widgets and user secrets; API keys are revoked. The User row itself is kept for audit/billing FK integrity but scrubbed (identity fields nulled, handle replaced with a random deleted-... value) and soft-deleted; a deleted account can no longer authenticate.
userRef ID
createOrganization Organization!
name String!
urn String!
updateOrganization Organization! Update an Organization. Accepts the entity's ID or URN.
id ID!
name String
urn String
listedOnMarketplace Boolean
policy JSON
deleteOrganization Boolean! Soft-delete an Organization. Accepts the entity's ID or URN.
id ID!
linkGithubApp Organization! Link a GitHub App installation to an organization (org ADMIN or platform ADMIN). Accepts the entity's ID or URN.
orgId ID!
installationId Int!
updateOrgGithubApp Organization! Set GitHub App credentials for an organization (encrypted at rest). Accepts the entity's ID or URN.
orgId ID!
appId String!
privateKey String!
unlinkGithubApp Organization! Remove all GitHub App config from an organization. Accepts the entity's ID or URN.
orgId ID!
createUserInvitation UserInvitation! User invitations (org ADMIN or platform ADMIN). Accepts the entity's ID or URN.
orgId ID!
memberRole Role!
name String
email String
githubUsername String
maxActivations Int
expiresInDays Int
inviteUser UserInvitation!
name String
email String
githubUsername String
maxActivations Int
expiresInDays Int
acceptInvitation Boolean!
slug String!
addOrgMember OrgMember! Accepts the entity's ID or URN (orgId).
orgRef String #764 — the organization as an id / slug / hrn:org:<slug> URN. Supply this OR orgId.
userRef String #764 — the user as an id / email / handle / hrn:user:<handle> URN. Supply this OR userId.
role Role!
updateOrgMember OrgMember! Accepts the entity's ID or URN (orgId).
orgRef String #764 — the organization as an id / slug / hrn:org:<slug> URN. Supply this OR orgId.
userRef String #764 — the user as an id / email / handle / hrn:user:<handle> URN. Supply this OR userId.
role Role!
removeOrgMember Boolean! Accepts the entity's ID or URN (orgId).
orgRef String #764 — the organization as an id / slug / hrn:org:<slug> URN. Supply this OR orgId.
userRef String #764 — the user as an id / email / handle / hrn:user:<handle> URN. Supply this OR userId.
createMemory Memory! Create a memory in an organization. Accepts the entity's ID or URN for orgId. Defaults to knowledge-class with ORGANIZATION visibility. Pass memoryClass: group + visibility: GROUP for a group-class memory (023-app-shape US4; the caller is auto-added as the first owner), or memoryClass: personal | private for an owner-only memory the caller owns (spec 034 — free-standing, no app/agent; the caller must be a member of the org container). system- and app-class memories are NOT created here — they auto-provision via Agent.systemMemoryId / the App install path.
orgId ID Owning organization. OPTIONAL (spec 047 — user-owned tenancy): when OMITTED, the memory is owned by the authenticated caller in their own handle namespace (organizationId NULL, ownerUserId = caller), and its URN roots on the caller's handle (hrn:mem:<handle>:<slug>) rather than an org domain. The org-less path supports only the owner-only classes 'personal' and 'private'; pass orgId for 'knowledge' / 'group'.
name String!
shortDescription String
description String
data JSON Free-form structured metadata bag (client-defined JSON). Null = unset.
tags [String!]
license String
category0 String
category1 String
category2 String
iconUrl String
heroUrl String
homeUrl String
source String
readBranch String
writeBranch String
visibility MemoryVisibility
memoryClass MemoryClass 'knowledge' (default), 'group', or the owner-only 'personal' / 'private' (spec 034). 'system' and 'app' are rejected — they auto-provision via different code paths.
vectorIndexEnabled Boolean Override the vector-index defaults. A 'knowledge'-class memory defaults to vectorIndexEnabled=true with embeddingSource=contentChunks (so any node with content is retrievable immediately, no abstract authoring needed — #281); every other class keeps the column defaults (false / abstract). An explicit value here wins for any class.
embeddingSource EmbeddingSource
maxRevCount Int #621 — per-node revision-history cap (default 10, minimum 1).
createMemoryInApp Memory! Add a NEW memory to an App, born App-scoped. Unlike createMemory (which only makes free-standing memories), this scopes the new memory to an App. memoryClass accepts only the App-associable classes: 'app', 'personal', or 'private' ('system'/'knowledge'/'group' forbid an app_id). appRef/agentRef accept an ID, bare URN, or prefixed URN; the Agent must be installed in the App. Authorization is split by class: 'app' is shared deployment data and requires org OWNER/ADMIN; 'personal'/'private' are the caller's OWN memory and require only App membership (the caller becomes the owner). Typed errors: UNSUPPORTED_MEMORY_CLASS, BAD_USER_INPUT (maxRevCount < 1), APP_UNINSTALLED, AGENT_NOT_INSTALLED, MEMORY_URN_CONFLICT, FORBIDDEN, UNAUTHENTICATED.
appRef ID!
agentRef ID!
memoryClass MemoryClass!
name String!
shortDescription String
description String
data JSON
tags [String!]
vectorIndexEnabled Boolean
embeddingSource EmbeddingSource
maxRevCount Int
attachMemoryToApp Memory! Attach an EXISTING free-standing memory to an App. Applies only to 'personal'/'private' memories owned by the caller (an 'app'-class memory can't be free-standing, so there is nothing to attach). Sets the App and Agent scope; the memory's URN, class, and owner are unchanged. memoryRef/appRef/agentRef accept an ID, bare URN, or prefixed URN; the Agent must be installed in the App. Requires App membership. Typed errors: UNSUPPORTED_MEMORY_CLASS, MEMORY_ALREADY_APP_SCOPED, APP_UNINSTALLED, AGENT_NOT_INSTALLED, FORBIDDEN, ORGANIZATION_MISMATCH.
memoryRef ID!
appRef ID!
agentRef ID!
updateMemory Memory! Update a Memory. Accepts the entity's ID or URN. Spec 033 FR-026: enabling `vectorIndexEnabled` on an `isEncrypted` memory requires `acknowledgeVectorInversionRisk: true` in the same call. Without the flag, an `EncryptedVectorIndexNotAcknowledgedError` is thrown carrying the full four-point disclosure on `error.disclosure` (single source of truth in `FR_026_DISCLOSURE` — see `src/lib/entityRef/errors.ts`). On a non-encrypted memory the flag is a no-op.
id ID!
name String
urn String
organizationId ID
shortDescription String
description String
data JSON
tags [String!]
license String
category0 String
category1 String
category2 String
iconUrl String
heroUrl String
homeUrl String
source String
readBranch String
writeBranch String
visibility MemoryVisibility
listedOnMarketplace Boolean
vectorIndexEnabled Boolean
embeddingSource EmbeddingSource
acknowledgeVectorInversionRisk Boolean
chunkTokens Int
chunkOverlap Int
forceFixedSize Boolean
maxRevCount Int
schema JSON
retryFailedEmbeddings Int! #882 — re-drive every FAILED embed in a memory (the operator recovery surface; previously hand-written SQL). Re-stamps each live node whose `embeddingFailedAt` is set — permanent-class failures whose pending marker was cleared, and backed-off retryable failures (made immediately eligible) — resetting the failure state exactly like a fresh write, then wakes the embedding worker. Returns the count re-stamped; 0 when the memory is not vector-indexed. `memoryRef` accepts the memory's ID or URN. Requires memory-owner or org-ADMIN (same gate as updateMemory).
memoryRef ID!
deleteMemory Boolean! Soft-delete a Memory. Accepts the entity's ID or URN.
id ID!
cloneMemory Memory! Clone a Memory into a new Memory at `targetUrn`. `ref` accepts the source's ID or URN. `targetUrn` is a fully-qualified "root:slug" memory URN naming the clone; its org segment MAY differ from the source's, cloning the memory into another organization. The clone's display name is derived from the target slug. Copies the Memory row plus all live Nodes, Edges, and PendingEdges; references to the source memory's URN inside node content/abstract (canonical and legacy spellings) are rewritten to the clone's URN. Vector-index config carries over and the clone's nodes are stamped for re-embedding. NOT copied: revision history, subscriptions, shares, group members (the caller is bootstrapped as a group clone's first owner), sessions, licenses, log entries, assets, and git-sync config (the clone starts DB-only). Authorization: the SOURCE side mirrors deleteMemory (personal/private → owner only; knowledge/group → source-org ADMIN). When `targetUrn` names a DIFFERENT org, the caller must additionally be a non-reader member of that target org. system/app-class sources and encrypted memories are rejected.
ref ID!
targetUrn String!
extractParentNodeToMemory Memory! Extract a parent node and its whole loc-subtree into a BRAND-NEW memory, making the parent the new memory's root. The subtree is loc-prefix defined: the node at the parent's loc plus every live descendant (loc starting with 'parentLoc:'). Locs are REBASED so the parent becomes the root — 'findings:auth' becomes the memory slug and 'findings:auth:oauth' becomes '<slug>:oauth'. Edges wholly inside the subtree carry over (their loc re-derived from the rebased endpoints); boundary-crossing edges and PendingEdges are dropped. 'parentRef' is the parent node's ID or fully-qualified URN. 'targetUrn' is a fully-qualified '<root>:<slug>' URN naming the new memory (it may land in a DIFFERENT org). 'move' = false (default) COPIES the subtree, leaving the source intact; 'move' = true relocates it, soft-deleting the source subtree (its nodes, the source memory's touching edges, and its pending edges). The new memory PRESERVES the source's class so an extract never widens who can read the content: a member-restricted 'group' stays group, a personal/private source stays owner-owned, knowledge stays knowledge. Governance/config (requiresLicense, chunk dials, revision cap, acceptsUploads) carries over from the source. Authorization: read access to the source memory (denial reads as NODE_NOT_FOUND). For knowledge/group sources the caller needs the SOURCE org's memory.clone grant (an export) AND the destination org's memory.create (plus a non-reader membership for a cross-org drop); a personal/private extract instead requires the owner to be a member of the destination org. 'move' additionally requires source write access, and cannot target the source root (that would empty the source — clone + deleteMemory instead). Encrypted and system/app-class sources are rejected. v1 limitation: node content is copied verbatim — because both the slug and node locs change, URN references among the moved nodes WILL break; and unresolved PendingEdges within the subtree are dropped.
parentRef ID!
targetUrn String!
move Boolean
setMemorySourceToken Memory! Set encrypted source token for non-GitHub-App repos. Accepts the entity's ID or URN.
id ID!
token String!
expiresAt String
createAgent Agent! Create an agent. Provide orgId to create an ORG-owned agent (requires org ADMIN); OMIT orgId to create a USER-OWNED agent owned by the caller — its URN is rooted on the caller's bare handle (hrn:agent:<handle>:<slug>, grammar v2 — no @ sigil) and its system memory is user-owned too. Exactly one owner (org XOR user). personaRole / personaPrompt are the persona dressing (cor:agt:020:01) — the reusable role plus the '{{name}}'-templated identity prompt. The NAMED identity is a Worker, cast with castWorker; names never live on agents. orgId accepts the org's ID or URN.
orgId ID
name String!
description String
systemPrompt String
systemMemoryId String
visibility AgentVisibility
type AgentType
surfaces [String!]
personaRole String
personaPrompt String
updateAgent Agent! Update an Agent. urn renames the slug (org-owned agents only). personaRole / personaPrompt are the persona dressing (cor:agt:020:01); explicit null or blank clears, omitted preserves. Worker castings referencing this agent are unaffected — the named identity lives on the Worker. Accepts the entity's ID or URN.
ref ID!
name String
urn String
description String
systemPrompt String
systemMemoryId String
visibility AgentVisibility
listedOnMarketplace Boolean
type AgentType
surfaces [String!]
personaRole String
personaPrompt String
deleteAgent Boolean! Soft-delete an Agent. Accepts the entity's ID or URN.
ref ID!
repairAgentSystemMemory Agent! #949 — re-own an Agent's class=system memory to the Agent's own owner (org XOR user) and re-derive its URN as '<agent-urn>-system'. The recovery path for a system memory that ended up owned by a different tenant. Access to a memory follows the MEMORY's owner, so such a row puts one tenant's Agent design (for a Team Agent: its 'roles:<role>' definitions and name registers) inside another tenant's audience. System memories are only ever created by Agent provisioning, so before this the only fix was to recreate the Agent. Authorization: PLATFORM ADMIN only — the row being moved belongs to a different tenant than the Agent, so neither side's org admin is the right authority. Idempotent: an already-consistent pair is a no-op. Error codes (extensions.code): FORBIDDEN, AGENT_HAS_NO_SYSTEM_MEMORY, SYSTEM_MEMORY_NOT_FOUND. Accepts the entity's ID or URN.
agentRef ID!
addMemoryToAgent Agent! Attach a Memory to an Agent. Accepts the entity's ID or URN.
agentRef ID!
memoryRef ID!
role String
updateAgentMemoryRole Agent! Update an Agent's role on an attached Memory. Accepts the entity's ID or URN.
agentRef ID!
memoryRef ID!
role String!
removeMemoryFromAgent Agent! Detach a Memory from an Agent. Accepts the entity's ID or URN.
agentRef ID!
memoryRef ID!
createMemorySubscription MemorySubscription! Create a cross-org Memory subscription. Accepts the entity's ID or URN.
memoryRef String #764 — the memory as an id or URN. Supply this OR memoryId.
orgRef String #764 — the organization as an id / slug / hrn:org:<slug> URN. Supply this OR orgId.
role Role!
createAgentOrgGrant AgentOrgGrant! Subscribe an organization to a PUBLIC Agent without creating an App. Accepts the entity's ID or URN.
agentRef ID!
orgRef ID!
revokeAgentOrgGrant AgentOrgGrant! Revoke an organization's Agent subscription without deleting install state. Accepts the entity's ID or URN.
agentRef ID!
orgRef ID!
updateMemorySubscription MemorySubscription! Update a cross-org Memory subscription. Accepts the entity's ID or URN.
memoryRef String #764 — the memory as an id or URN. Supply this OR memoryId.
orgRef String #764 — the organization as an id / slug / hrn:org:<slug> URN. Supply this OR orgId.
role Role!
deleteMemorySubscription Boolean! Delete a cross-org Memory subscription. Accepts the entity's ID or URN.
memoryRef String #764 — the memory as an id or URN. Supply this OR memoryId.
orgRef String #764 — the organization as an id / slug / hrn:org:<slug> URN. Supply this OR orgId.
syncMemory Memory! Trigger an on-demand sync for one memory (org ADMIN or CONTRIBUTOR). Accepts the entity's ID or URN.
id ID!
pushMemoryToGit Boolean! Push all nodes in a memory to its configured git repo. Accepts the entity's ID or URN.
id ID!
deleteExchangeConnection Boolean!
id ID!
testExchangeConnection Boolean!
id ID!
createSlackConnection SlackConnection! Register a Slack workspace install (spec 043). orgRef/appRef accept ID or URN (cor:api:140); the App must belong to the org. Both tokens are validated live by the tool and stored encrypted THERE — core keeps identity only, and no field ever returns a token. Requires org ADMIN/OWNER.
orgRef ID!
appRef ID!
botToken String!
appToken String!
deleteSlackConnection Boolean! Soft-delete a Slack connection (org ADMIN/OWNER); tears down the tool side best-effort.
ref ID!
createMcpServer McpServer! Register an external MCP server (org ADMIN/OWNER). orgRef accepts ID or URN (cor:api:140). headers is a JSON object of static request headers (e.g. Authorization) — encrypted at rest, write-only, never returned. Registration grants nothing by itself: runs still need the policy chain to allow tool.mcp__<slug>__<tool>.
orgRef ID!
slug String!
name String!
url String!
headers JSON
toolAllowlist [String!]
enabled Boolean
updateMcpServer McpServer! Update a registered MCP server (org ADMIN/OWNER). The slug is immutable — flow nodes reference it in data.tools names. headers REPLACES the stored object; clearHeaders: true removes it (pass one or the other, not both).
ref ID!
name String
url String
headers JSON
clearHeaders Boolean
toolAllowlist [String!]
enabled Boolean
deleteMcpServer Boolean! Hard-delete a registered MCP server (org ADMIN/OWNER); runs referencing its tools fail loud afterwards.
ref ID!
createSecret Secret! Create a named, owner-scoped secret (#677). Gate per owner scope: user -> that user (ownerRef optional, defaults to the caller); org -> org ADMIN; app -> app owner / org ADMIN; memory -> memory WRITE. value is the secret payload — encrypted at rest, write-only, never returned. kind selects validation: generic (opaque JSON) or webfetch-auth ({type: bearer|basic|header, ...} + metadata.urlPrefix origin binding). A run resolves the name via the CSS cascade (memory -> app -> user -> org) at entitled scopes only.
ownerType String!
ownerRef ID
name String!
kind String!
metadata JSON
value JSON!
updateSecret Secret! Overwrite a secret's value and/or metadata (v1 rotation — no versioning). Name, kind, and owner are immutable — the cascade and flow config reference the name; create a new name instead. The effective (metadata, value) pair is re-validated per kind.
ref ID!
metadata JSON
value JSON
deleteSecret Boolean! Hard-delete a secret; referencing runs fail their resolution loud (or fall through the cascade) afterwards.
ref ID!
createHomeAssistantInstance HomeAssistantInstance! Register a Home Assistant instance (org ADMIN/OWNER). orgRef accepts ID or URN (cor:api:140). accessToken is an HA long-lived access token — encrypted at rest, write-only, never returned. Registration grants nothing by itself: runs still need the policy chain to allow tool.ha__<slug>__<op>.
orgRef ID!
slug String!
name String!
url String!
accessToken String!
opAllowlist [String!]
enabled Boolean
updateHomeAssistantInstance HomeAssistantInstance! Update a registered Home Assistant instance (org ADMIN/OWNER). The slug is immutable — flow nodes reference it in data.tools names. accessToken REPLACES the stored token (never cleared: an instance without a token is unusable).
ref ID!
name String
url String
accessToken String
opAllowlist [String!]
enabled Boolean
deleteHomeAssistantInstance Boolean! Hard-delete a registered Home Assistant instance (org ADMIN/OWNER); runs referencing its ops fail loud afterwards.
ref ID!
createResendSender ResendSender! Register one BYO Resend sender for an org. The API key is encrypted and never returned.
orgRef ID!
from String!
apiKey String!
enabled Boolean
updateResendSender ResendSender! Update the fixed sender, replace its write-only API key, or enable/disable it.
ref ID!
from String
apiKey String
enabled Boolean
deleteResendSender Boolean! Hard-delete an org's BYO Resend sender.
ref ID!
exchangeReply Boolean!
connectionId ID!
messageId ID!
body String!
exchangeMoveMessage Boolean!
connectionId ID!
messageId ID!
folderId String!
emailSaveDraft EmailDraftInfo! Save a draft in the mailbox's own Drafts folder (spec 002 US5): either a reply-draft (replyToMessageId) or a fresh draft (to + subject). Owner-only. idempotencyKey makes retries safe (at-least-once callers).
connectionRef ID!
replyToMessageId ID
to [String!]
subject String
bodyHtml String!
idempotencyKey String
emailUpdateDraft Boolean! Update a provider-side draft's body. Owner-only.
connectionRef ID!
draftId ID!
bodyHtml String!
emailSendDraft Boolean! Send a provider-side draft. Owner-only; idempotencyKey makes retries safe.
connectionRef ID!
draftId ID!
idempotencyKey String
emailDeleteMessage Boolean! Delete a message (provider trash semantics). Owner-only.
connectionRef ID!
messageId ID!
emailMarkRead Boolean! Mark a message read or unread (default read). Owner-only.
connectionRef ID!
messageId ID!
isRead Boolean
emailFlagMessage Boolean! Flag, unflag, or complete a message (default FLAGGED). Owner-only.
connectionRef ID!
messageId ID!
flag EmailFlag
emailCategorizeMessage Boolean! Set the categories (color labels) on a message. Owner-only.
connectionRef ID!
messageId ID!
categories [String!]!
calendarCreateEvent CalendarEvent! Create an event. calendarId defaults to the primary calendar. Owner-only.
connectionRef ID!
calendarId String
title String!
description String
location String
start CalendarEventTimeInput!
end CalendarEventTimeInput!
attendees [String!] Attendee email addresses.
notifyAttendees Boolean
idempotencyKey String
calendarUpdateEvent CalendarEvent! Patch an event — absent fields stay unchanged; attendees replaces the set. Owner-only.
connectionRef ID!
eventId ID!
calendarId String
title String
description String
location String
start CalendarEventTimeInput
end CalendarEventTimeInput
attendees [String!]
notifyAttendees Boolean
idempotencyKey String
calendarDeleteEvent Boolean! Delete (cancel) an event. Owner-only.
connectionRef ID!
eventId ID!
calendarId String
notifyAttendees Boolean
idempotencyKey String
calendarRespondToEvent CalendarEvent! Set the connected account's own RSVP on an event it was invited to (ACCEPTED / DECLINED / TENTATIVE — NONE is not a settable response). Owner-only.
connectionRef ID!
eventId ID!
response CalendarEventResponse!
calendarId String
exportNodeToGoogleDoc DriveFile! Export a node's markdown as a NEW Google Doc in the connected drive (nodeRef is a PK or fully-qualified URN; title defaults to the node name; folderId defaults to the drive root). Always creates — the drive tool's scope cannot edit existing files, and no update surface exists. Owner-only: no grant scope maps to doc creation (fail-closed for App/headless callers).
nodeRef ID!
connectionRef ID!
folderId ID
title String
startChat ChatStartResult! Start a chat session (creates chat nodes, loads conversation, returns compiled prompt). When called by a JWT user, the chat is created in that user's personal memory for the agent (provisioned lazily if needed). Accepts the entity's ID or URN.
agentId ID!
userId String
conversationName String
scope ChatScope
isTestRun Boolean
sendChatMessage ChatPromptResult!
chatId String!
userMessage String!
processChatResponse ChatResponseResult!
chatId String!
toolResponse JSON!
saveChatSummary Boolean!
chatId String!
summary String!
updateChatTitle Boolean!
chatId String!
title String!
deleteChat Boolean!
chatId String!
updateAgentAIConfig Agent! Update an Agent's AI provider config. Key is encrypted at rest. 036-ai-service-config: upserts the Agent's registry config named 'default'. Prefer createAiServiceConfig/updateAiServiceConfig for new callers. Accepts the entity's ID or URN.
agentId ID!
provider String!
model String!
apiKey String
clearAgentAIConfig Agent! Clear an Agent's AI provider config. 036-ai-service-config: deletes the Agent's registry config named 'default'. Accepts the entity's ID or URN.
agentId ID!
createAiServiceConfig AiServiceConfig! 036-ai-service-config: create a named AI config on an owner entity. apiKey semantics: omitted = stored without a key (unusable for execution until one is set); non-empty = encrypted at rest with a masked preview. Name must be 1-64 lower-case [a-z0-9_-], unique per owner. provider must be a known provider; params are validated per provider. Auth: as aiServiceConfigs. ownerId accepts ID or URN (HADRON_SERVER: ID only).
ownerType AiConfigOwnerType!
ownerId ID!
name String!
provider String!
model String!
apiKey String
params JSON
enabled Boolean
updateAiServiceConfig AiServiceConfig! 036-ai-service-config: update a named AI config. All fields optional. apiKey semantics: omitted = keep the stored key; empty string = clear it; non-empty = replace (encrypted, preview recomputed). Auth: admin rights on the owning entity (as aiServiceConfigs).
id ID!
name String
provider String
model String
apiKey String
params JSON
enabled Boolean
deleteAiServiceConfig Boolean! 036-ai-service-config: delete a named AI config (hard delete; the resolution walk simply no longer finds it). Auth: admin rights on the owning entity (as aiServiceConfigs).
id ID!
createRevision RevisionResult! Snapshot an Agent's system memory as a new revision. Accepts the entity's ID or URN.
agentId ID!
description String
publishRevision RevisionResult! Publish a revision and pin the Agent to it. Accepts the entity's ID or URN.
agentId ID!
revisionLoc String!
versionLabel String
restoreRevision RevisionResult! Restore an Agent's system memory from a revision (auto-saves first). Accepts the entity's ID or URN.
agentId ID!
revisionLoc String!
acquireEditorLock EditorLockResult! Acquire (or renew) the editor lock for an Agent's system memory. Accepts the entity's ID or URN.
agentId ID!
releaseEditorLock Boolean! Release the editor lock for an Agent's system memory. Accepts the entity's ID or URN.
agentId ID!
joinWaitingList Boolean!
email String!
requestedFeatures String
sendContactMessage Boolean!
name String!
email String!
message String!
createApp App! Install an Agent into an organization, creating an App that deploys it. Auto-provisions an AgentOrgGrant for (orgId, agentId) on first install, and adds the caller as an AppMember with role 'owner'. Required AgentImports cascade automatically; optional imports cascade only when their id appears in installOptional. 009-install-agent-flow: the cross-org install restriction (FR-009) is enforced at the portal — the Install affordance is hidden for Agents not owned by the calling org. The server still auto-provisions grants on first install (preserved from 008); a hard server-side cross-org gate is reserved for the marketplace spec. Accepts the entity's ID or URN.
orgRef ID Provide to create an ORG-owned App (requires org ADMIN). OMIT to create a USER-OWNED App owned by the caller — rooted on the caller's bare handle (hrn:app:<handle>:<slug>, grammar v2 — no @ sigil), owner-only. Accepts the org's ID or URN.
agentRef ID! The Agent this App deploys. Required as of 009-install-agent-flow: every App must reference an Agent. The server itself accepts any Agent the caller can resolve and auto-provisions an AgentOrgGrant (008 behavior preserved); the portal's install flow restricts the affordance to Agents owned by the caller org. A hard server-side cross-org gate is reserved for the marketplace spec.
name String!
urn String
appType AppType
role AppMembershipRole
description String
systemPrompt String
agentTools [String!]
aiProvider String
aiModel String
aiApiKey String
expiresAt String
surfaces [String!]
trainingMode Boolean
installOptional [ID!] 008-agent-installation: optional dep Agent ids to cascade-install. Required imports of the parent Agent always cascade; optional imports install only when their id appears here. Pass [] (or omit) to skip all optional deps. v1 accepts ID or URN.
createUserPermission CreateUserPermission
identifyUserMethod IdentifyUserMethod
sessionTimeoutSeconds Int
anonymousTtlDays Int
policy JSON App-layer action-policy link (cor:acl:040:02, #510). Explicit null clears; omitted preserves.
updateApp App! Update an App. Accepts the entity's ID or URN.
ref ID!
name String
urn String
appType AppType
role AppMembershipRole
description String
systemPrompt String
agentTools [String!]
aiProvider String
aiModel String
aiApiKey String
expiresAt String
surfaces [String!]
trainingMode Boolean
createUserPermission CreateUserPermission
identifyUserMethod IdentifyUserMethod
sessionTimeoutSeconds Int
anonymousTtlDays Int
deleteApp Boolean! Soft-delete an App. Accepts the entity's ID or URN.
ref ID!
installAgentIntoApp InstallAgentIntoAppPayload! Install an Agent into an App (023-app-shape US1). Creates an AppAgent row joining the two. An App can have multiple Agents installed; one credential addresses all of them. This is the ONE operation that attaches an EXISTING Agent to an EXISTING App — distinct from createApp (which makes a NEW App from an Agent). It is therefore also the re-attach that cor:dmo:050:03 promises: detaching an Agent retains the memories accumulated under that App-and-Agent pairing as orphans, and installing the Agent again is what makes them reachable. Under cor:agt:020:01 the AppAgent join is a team's install ROSTER (which agents are available); the App's STAFF are its Workers, cast from installed agents with castWorker. Worker rows survive uninstall (cor:dmo:050:11) — uninstalling severs future casting, not history. Rejects with code DUPLICATE_APP_AGENT when the Agent is already installed in the App. Authorization: the owner of a user-owned App, or an org member with CONTRIBUTOR+ on an org-owned App's org (platform admins included). NOT plain AppMembers: installing an existing Agent is itself a read grant on that Agent's design — its system memory becomes readable from every App context, and the returned Agent carries its systemPrompt — so this gate stays at the level that can already read the org's Agents. Accepts the entity's ID or URN for both appId and agentId. Optional trainingMode flag updates the per-App training flag (applies to every installed Agent — training mode is per-App, not per-Agent, per spec 023 FR-001).
appRef ID!
agentRef ID!
trainingMode Boolean
castWorker Worker! #974 — cast a Worker (cor:dmo:050:11, cor:agt:020:01/:02): the named casting of an agent ALREADY INSTALLED in the App, superseding createTeamPersona's minting semantics (nothing is minted — the agent carries the persona dressing; the Worker is the local named identity). Casting is opt-in, never requires a Team Agent (an explicit name skips the register entirely), and multiple castings of one agent per App are legal (Iris and Henry, both backend-engineer). Agent resolution: agentRef when given (must be installed here — WORKER_AGENT_NOT_INSTALLED); otherwise role picks the single installed agent whose personaRole matches (zero / several candidates: WORKER_AGENT_NOT_FOUND / WORKER_AGENT_AMBIGUOUS, never a guess). The casting's role defaults to the agent's personaRole when role is omitted. Name allocation (cor:agt:020:02): a caller-supplied name wins (one attempt — WORKER_NAME_TAKEN is the answer); otherwise the Team Agent's cast-list register for the role (the roles:<role> node's data.names, located as before: teamAgentRef, or the single installed agent with a roles: branch) is walked first-to-last, advancing past WORKER_NAME_TAKEN — the workers_app_name_uniq constraint IS the allocation primitive. Names are unique per App, case-insensitively, FOREVER (two Apps may each have an Iris; retirement and uninstall never free a name). A worker-scoped working memory is provisioned in the App's container (Worker.memoryId; best-effort — a failed provision leaves it null for lazy provisioning). Authorization: an org member with CONTRIBUTOR+ on the App's org, an AppMember of the App whose role is not 'reader', or the owner of a user-owned App. Pure App-key principals are denied. Error codes (extensions.code): WORKER_NAME_TAKEN, WORKER_REGISTER_EXHAUSTED, WORKER_AGENT_NOT_INSTALLED, WORKER_AGENT_NOT_FOUND, WORKER_AGENT_AMBIGUOUS, WORKER_ROLE_NOT_FOUND, TEAM_AGENT_NOT_FOUND, TEAM_AGENT_AMBIGUOUS, TEAM_AGENT_NOT_INSTALLED, SESSION_EXPIRED (encrypted system memory without an active session key), APP_UNINSTALLED. Accepts the entity's ID or URN for appRef, agentRef, and teamAgentRef.
appRef ID!
agentRef ID
role String
name String
teamAgentRef ID
promptOverride String
retireWorker Worker! #974 — retire a Worker (cor:agt:020:02): end the casting while reserving its name FOREVER. A retired worker stops authoring team chat at once (the worker-App pin checks retirement at post time), takes no new work records, and refuses new session bindings; the row and its name reservation survive. Idempotent — retiring an already-retired worker returns it unchanged. Same authorization as castWorker. workerRef is the worker's id or its URN (#991).
workerRef ID!
updateWorker Worker! #1010 — amend a casting's individuality after the fact. `promptOverride` is the per-worker escape hatch (cor:agt:020:01), but it could only be set at CASTING time — fixing a casting's individuality at the one moment nobody yet knows what makes it individual. The role agent's `personaPrompt` cannot stand in (it is SHARED by every casting of that role), and re-casting is barred by `WORKER_IN_USE` for any worker that has done work — precisely the ones with an identity to record. Scope is one field on purpose: `name` is permanent by law (cor:agt:020:02) and `role`/`agent` define the casting itself. OMITTING promptOverride preserves it; explicit `null` or a blank string CLEARS it, matching the nullable column and castWorker's blank-is-absent normalization. Refuses WORKER_RETIRED for a retired worker: an override is briefing text delivered at bind time, and a retired worker takes no new bindings, so the edit could never reach anyone. Same authorization as castWorker. workerRef is the worker's id or URN (#991).
workerRef ID!
promptOverride String
deleteWorker Boolean! #974 — hard-delete a NEVER-USED miscast (cor:dmo:050:11's only removal escape): refused with WORKER_IN_USE unless no session was ever bound and the worker's working memory holds no content. Anything with history retires instead — its name is bound to that history forever. Also removes the empty working memory. Same authorization as castWorker.
workerRef ID!
createTeamRole TeamRole! #960 — mint a roles:<role> definition in the Team Agent's system memory. Owns the spec knowledge a hand-authoring caller had to carry: the loc is roles:<role> (single atom), the register goes in data.names (ordered), and the write runs the register invariants — an added name may not appear in another of this App's registers (TEAM_ROLE_NAME_DUPLICATE) and must fall inside nameRange when one is set (TEAM_ROLE_NAME_OUT_OF_RANGE, override with allowOutOfRange; a supplied nameRange must parse as an initial-letter range like 'F-J'). Register checks and the write run in one App-scoped critical section, serialized with register-mode casting. Refuses an existing role (TEAM_ROLE_EXISTS — updateTeamRole is the edit path). Authorization is the Team Agent's definition-edit gate: whoever may write the agent's system memory through the generic node surface may write roles — the write delegates to that same seam (encryption, revision snapshot, git mirror included).
appRef ID!
teamAgentRef ID
role String!
names [String!]!
nameRange String
nameConvention String
description String
allowOutOfRange Boolean
updateTeamRole TeamRole! #960 — edit a roles:<role> definition. names is WHOLESALE (the natural fit for 'team role names set') but the invariants run against the DIFF between stored and submitted, so add/rm/mv sugar can never smuggle a violation: a name MINTED in this App may never be removed (TEAM_ROLE_NAME_MINTED — the register entry records the allocation), an added name may not appear in another register (TEAM_ROLE_NAME_DUPLICATE), and added names validate against nameRange (allowOutOfRange overrides). Omitted fields preserve; explicit null clears a convention key. Sibling data keys always survive (the single --data clobber hazard is unreachable through this surface). Unknown role: WORKER_ROLE_NOT_FOUND. Same authorization as createTeamRole. #987 — expectedNames turns the wholesale write into COMPARE-AND-SWAP: when supplied, the write refuses TEAM_ROLE_STALE unless the STORED register still equals it (ordered, exact spellings, after the same trim/dedup canonicalization the register itself gets — pass back the register exactly as teamRoles returned it). The refusal's extensions carry the current storedNames, so a client rebases its edit without a second read. This is what makes read-modify-write sugar (names add/rm/mv) safe: the diff invariants deliberately protect only MINTED names, so without the precondition two concurrent composed writes silently drop each other's newly added FREE names — no refusal fires, because removing an unminted name is legal by design.
appRef ID!
teamAgentRef ID
role String!
names [String!]
nameRange String
nameConvention String
description String
allowOutOfRange Boolean
expectedNames [String!]
deleteTeamRole DeleteTeamRolePayload! #1002 — retire a roles:<role> definition. Soft-deletes the role node and any sub-nodes under it (roles:<role>:notes is content OF the role), so the subtree is recoverable. Unknown role: WORKER_ROLE_NOT_FOUND. Same authorization and same App-scoped critical section as createTeamRole, so a retirement serializes with register-mode casting. MINTED names decide whether a bare delete is allowed. A minted register entry is what records that a name was allocated to this role; dropping the register without rehoming it would erase that ledger, so a role holding minted names refuses TEAM_ROLE_IN_USE unless transferTo names a successor. A role whose register is entirely free deletes with no ceremony. Note this does NOT free the names themselves: a Worker's name is permanent per App (cor:agt:020:02, enforced by workers_app_name_uniq irrespective of any register), so retiring a role can never make a taken name castable again. The register is bookkeeping about ALLOCATION, not identity — which is exactly why moving it between roles is safe. transferTo performs the supersede as ONE step: the old definition is retired and its whole register is appended to the successor's, preserving order and skipping spellings the successor already lists. This removes the ordering trap a hand-run sequence has to rediscover (a name may not sit in two of an App's registers, so the old role must be gone BEFORE the successor can claim its names — TEAM_ROLE_NAME_DUPLICATE otherwise). Transferred names are EXEMPT from the successor's nameRange: they are re-homed allocations, not new ones, and the range governs what may be allocated next. The successor's own conventions are left untouched — changing them is updateTeamRole's job, not a side effect of a delete. The delete and the transfer are two operations that cannot share one transaction, so the source role is RESTORED if the transfer fails — the delete is soft, and the tombstone still holds the register verbatim. The minted check is also re-run AFTER the delete, because an explicit-name castWorker mints without taking the register lock and could otherwise slip a freshly minted name past the pre-check. Should the restore itself fail, TEAM_ROLE_DELETE_NOT_COMPENSATED reports the loc to recover by hand rather than leaving the caller to retry against a role that is silently gone.
appRef ID!
teamAgentRef ID
role String!
transferTo String
createTeamChatMessage TeamChatMessage! Post a message into a team App's chat (#939) as a platform operation. The team chat is ONE well-known chat per team App, at loc chats:team in the Team Agent's shared app-class memory, bootstrapped on first post. The message is written through the atomic chat-message allocator (#919), so racing posts get distinct consecutive seqs. Author derivation (#974): with sessionRef, the message is authored by that session's bound Worker (the session must be writable by the caller, a session OF this App, active, and bound to a non-retired Worker OF this App — the worker-App pin, checked at post time so retirement revokes) and the envelope records the driving sessionId; without it, by the calling human. Mentions ('@worker-name' / '@handle'; a multi-word name is mentioned by its slug, e.g. '@mary-jane') are extracted server-side at write time into the envelope. replyToSeq wires a replies-to edge to the cited message. body is capped at 65536 characters. Authorization: an AppMember of the App (any role — every member of the host is a participant per cor:acl:030:01), an org member with CONTRIBUTOR+ on the App's org, or the owner of a user-owned App. Pure App-key principals cannot post. Error codes (extensions.code): TEAM_CHAT_BODY_TOO_LARGE, TEAM_CHAT_REPLY_NOT_FOUND, SESSION_NOT_FOUND, SESSION_NOT_IN_APP (the session belongs to a different App — a worker never authors across Apps), SESSION_ENDED, SESSION_NOT_WORKER_BOUND, SESSION_WORKER_NOT_IN_APP (the worker-App pin), WORKER_RETIRED, SESSION_EXPIRED (encrypted team memory without an active session key), TEAM_AGENT_NOT_FOUND / TEAM_AGENT_AMBIGUOUS (first-post bootstrap could not locate the Team Agent), APP_UNINSTALLED, FORBIDDEN. appRef accepts the entity's ID or URN; sessionRef is the session id.
appRef ID!
body String!
replyToSeq Int
sessionRef ID
recordTeamWork TeamWorkItem! Record an externally visible work milestone into the team App's worklog (#947) — the append-only, authoritative PR-session join (spec cor:agt:020:03). The session must be writable by the caller and a session OF this App (SessionInput.appRef, #944); an ENDED session is accepted — late attribution (a merge lands after the session ends) is the point. ref accepts URL and short spellings and is stored in ONE canonical form (github: owner/repo#N, owner/repo@sha, owner/repo:branch, owner/repo); a bare number is refused — the server never infers a repo. kind must be one of pr, issue, commit, branch, repo; action is a free lowercased verb (opened, merged, claimed, reviewed, closed, pushed, ...). kind: pr also denormalizes the latest-wins Session.prNumber display convenience. detail is an optional JSON bag of display extras (title, URL) — stored, never filtered on. Records are append-only: correct a wrong record by recording a newer one. Authorization: an AppMember of the App (any role), an org member with CONTRIBUTOR+ on the App's org, or the owner of a user-owned App. A pure App-key principal may NOT record (read-only on the worklog). A worker-bound session records under its Worker's name (#974, cor:agt:020:05) — the worker must belong to THIS App and not be retired (SESSION_WORKER_NOT_IN_APP / WORKER_RETIRED — a retired or foreign worker refuses rather than reshaping the attribution); an unbound session records under the attributed user's handle. Typed refusals: WORK_REF_INVALID, SESSION_NOT_FOUND, SESSION_NOT_IN_APP, SESSION_WORKER_NOT_IN_APP, WORKER_RETIRED, TEAM_AGENT_NOT_FOUND / TEAM_AGENT_AMBIGUOUS (first-write bootstrap could not locate the Team Agent), APP_UNINSTALLED, FORBIDDEN, BAD_USER_INPUT. appRef accepts the entity's ID or URN; sessionRef is the session id.
appRef ID!
sessionRef ID!
tool String!
kind String!
ref String!
action String!
detail JSON
updateTeamCollections TeamCollectionsPayload! (Re)declare the server-owned team collections on the team App's shared memory, converging a drifted declaration to the canonical definition (hadron-cli#401). Idempotent: 'changed' is false when the declaration already matched. Why this exists as its own operation. recordTeamWork declares the worklog collection on first write, but deliberately leaves an ALREADY-declared one untouched — a deployment that tightened it governs that surface too, which is the point of schema governance. A declaration is not always a deployment decision though: 'hadron team init' shipped a client-side copy of this schema that has since drifted from the server's (its kind enum predates the 'repo' kind), so on a CLI-bootstrapped memory a recordTeamWork(kind: 'repo') is refused by a rule nobody chose. Overriding silently would break real governance; this operation makes convergence an explicit act instead. Only the server-owned collections are rewritten — every other collection on the memory is preserved. Authorization: owner or org ADMIN on the memory, the same bar updateMemory applies to a schema edit. Team participation is deliberately NOT enough: it lets you record work, not redefine what a record is. Typed refusals: APP_UNINSTALLED, UNAUTHENTICATED, TEAM_AGENT_NOT_FOUND / TEAM_AGENT_AMBIGUOUS (when the App's shared memory must still be bootstrapped). Accepts the entity's ID or URN.
appRef ID!
uninstallAgentFromApp UninstallAgentFromAppPayload! Uninstall an Agent from an App. Deletes the AppAgent row. The Agent's per-(App, Agent, *) memories are NOT cascade-deleted (spec 023 FR-005); they persist as orphans and become reachable again if the same Agent is later reinstalled. Idempotent — succeeds whether or not the AppAgent row exists. Accepts the entity's ID or URN.
appRef ID!
agentRef ID!
addAgentToApp ⚠️ App! DEPRECATED: use installAgentIntoApp. Carried for source-compat with pre-023 portal callers. Accepts the entity's ID or URN.

⚠️ DEPRECATED

Use installAgentIntoApp (spec 023-app-shape US1). Returns Payload type with the AppAgent row.
appRef ID!
agentRef ID!
trainingMode Boolean
removeAgentFromApp ⚠️ App! DEPRECATED: use uninstallAgentFromApp. Carried for source-compat with pre-023 portal callers. Accepts the entity's ID or URN.

⚠️ DEPRECATED

Use uninstallAgentFromApp (spec 023-app-shape US1).
appRef ID!
agentRef ID!
ensureAppMember AppMember! Idempotent UPSERT of an AppMember row. Per spec 008-agent-installation FR-004 / FR-016. The role MUST be a value present in the parent Agent's installationPolicy.memberRoles. Creating a new member is rejected if the App's current member count meets or exceeds the Agent's installationPolicy.maxMembers. Updating an existing member's role does NOT trigger the maxMembers check. Accepts the entity's ID or URN.
appRef String #764 — the App as an id / URN. Supply this OR appId.
userRef String #764 — the user as an id / email / handle / hrn:user:<handle> URN. Supply this OR userId.
role String!
removeAppMember Boolean! Delete an AppMember row. Idempotent (no-op when the row doesn't exist). Personal-class memory at (appId, userId) is retained as an orphan per FR-015 — re-attaches automatically if the user later rejoins the same App. Accepts the entity's ID or URN.
appRef String #764 — the App as an id / URN. Supply this OR appId.
userRef String #764 — the user as an id / email / handle / hrn:user:<handle> URN. Supply this OR userId.
joinApp JoinAppPayload! 023-app-shape US2 — user-level install. The currently-logged-in user joins the App as an AppMember. NO OrgMember check (spec 023 FR-009) so this works for B2C / consumer / therapy use cases where the end-user is not in the App's operator org. Role defaults to the first value in the Agent's installationPolicy.memberRoles (the conventional "guest" or "owner" slot). Idempotent — if the user is already an AppMember of the App, the existing row is returned. Error codes (GraphQLError extensions.code, Error.name style): - UNAUTHENTICATED — no logged-in user in context. - AppNotFoundError — the App does not exist or is soft-deleted. - AppUninstalledError — the App is in the spec-021 soft-uninstall lifecycle phase. - OrphanAppError — the App has no installed Agents (so there's no Agent.installationPolicy to consult). - NoMemberRolesError — the primary Agent's installation_policy.memberRoles is empty, so joinApp can't pick a default role. - MaxMembersExceededError — the Agent's maxMembers limit is hit. - InvalidRoleError — the picked default role isn't accepted by the Agent's policy (rare; would indicate a policy update race). Accepts the entity's ID or URN.
appId ID!
leaveApp LeaveAppPayload! 023-app-shape US2 — user-level uninstall. The currently-logged-in user leaves an App. Idempotent (no-op when not a member). The user's personal-class Memory at (appId, userId) is NOT cascade-deleted per spec 008 FR-015 — it re-attaches if the user later re-joins. Accepts the entity's ID or URN.
appId ID!
createMemoryShare CreateMemorySharePayload! 023-app-shape US3 — asymmetric cross-user grant on a personal-class Memory. The principal (memory.userId) grants a grantee read or write access. Used for the per-pairing pattern (Alice's paired-with-Mentor-A memory is distinct from her paired-with-Mentor-B memory; each gets its own MemoryShare). Upsert semantics: re-calling with a different role on an existing (memoryId, granteeId) pair updates the role rather than throwing. For v1 the caller MUST be the principal themselves (memory.userId === ctx.userId). The Agent-mediated path (App backend acting on the principal's behalf via MCP) is supported by the access-control predicate but not by this GraphQL surface — see the deferred policy discussion linked from joinApp.ts. Share-audience rule (#778): a plain ORG-OWNED personal memory (organizationId set, no agent scope) may be shared ONLY with a current member of that org; a FREE-STANDING (org-less) personal memory may be shared with any user. Agent-scoped personal memories (the spec-023 per-pairing App pattern) are exempt — their audience is governed by AppMember + AgentSubscription, not org membership. Error codes (extensions.code, Error.name style): - UNAUTHENTICATED — no logged-in user in context. - FORBIDDEN — caller is not the Memory's principal. The caller-authority guard runs first and deliberately does not differentiate between "memory doesn't exist", "memory is not personal-class", and "caller isn't the principal" — all three return FORBIDDEN so memory metadata isn't leaked to non-principals. - MemoryShareGranteeMissingError — granteeId doesn't resolve to an existing User. Only reachable when the caller passes the principal guard. - CrossOrgShareNotAllowedError — the grantee is not a member of an org-owned personal memory's org (the #778 audience rule above). - InvalidMemoryClassForShareError / MemoryNotFoundForShareError — defined on the controller for completeness; functionally unreachable via this GraphQL mutation in v1 because the caller-authority guard short-circuits to FORBIDDEN first.
memoryId ID!
granteeRef String #769 — the grantee as a reference resolved server-side: a user id, email, handle, or hrn:user:<handle> URN. Resolution sees the full user table, so a cross-org personal-memory share works by email/handle. Supply this OR granteeId.
role MemoryShareRole!
deleteMemoryShare DeleteMemorySharePayload! 023-app-shape US3 — delete a MemoryShare. Per FR-022, revocation takes effect on the next read (there's no "deactivated" state; just a row delete). Renamed from revokeMemoryShare in #785. Caller-authority rule (#785) — principal OR self, the same shape removeMemoryMember uses: - The memory's principal (memory.userId) may delete ANY grantee row on their memory. Idempotent: deleting a share that is already gone succeeds. - A GRANTEE may delete THEIR OWN row — the stop-sharing-with-me / leave path. Omit granteeRef entirely and the mutation targets the caller's own share. - Everyone else gets FORBIDDEN. On the self path the SHARE ROW itself is the authorization, so that path is idempotent only up to the row's lifetime: repeating a successful leave answers FORBIDDEN (you already left). That is what keeps every unauthorized outcome identical — a caller who is neither principal nor grantee cannot tell "no such memory" from "not shared with me" from "not yours", by error code or by the difference between an error and a successful no-op. The same rule covers the grantee reference: a non-principal caller gets FORBIDDEN whether the named user exists or not, so neither memories nor users can be enumerated here. (A principal, who by definition already knows the memory exists, still gets NOT_FOUND for a granteeRef that resolves to nobody.) A grantee may leave a memory whose owner has soft-deleted it (the row would otherwise be stranded); the principal path still treats a soft-deleted memory as FORBIDDEN.
memoryRef ID! The memory, by id or URN (#785).
granteeRef String #769 — the grantee as a server-resolved reference (id / email / handle / hrn:user URN). Supply this OR granteeId. Omit BOTH to target the caller's own share (self-removal).
updateMemoryShareRole UpdateMemoryShareRolePayload! 023-app-shape US3 — change the role on an existing MemoryShare. Throws MemoryShareNotFoundError if the (memoryId, granteeId) row doesn't exist — use createMemoryShare to upsert. Caller-authority rule matches createMemoryShare.
memoryId ID!
granteeRef String #769 — the grantee as a server-resolved reference (id / email / handle / hrn:user URN). Supply this OR granteeId.
role MemoryShareRole!
addMemoryMember AddMemoryMemberPayload! 023-app-shape US4 — add a team member to a group-class Memory. Idempotent on the (memoryId, userId) PK: re-calling with a different role upserts the role. The caller MUST be an owner of the Memory (role = owner). The bootstrap case is handled by createMemory itself, which adds the creator as the first owner of a newly-created group memory. Error codes (extensions.code, Error.name style): - UNAUTHENTICATED — no logged-in user in context. - FORBIDDEN — caller is not an owner of the memory. (Uniform for missing-memory / wrong-class / not-an-owner cases, by the same don't-leak-metadata rule as MemoryShare mutations.) - InvalidMemoryClassForMemberError — memory is not group-class (only reachable from non-GraphQL callers in v1 — the caller-authority guard short-circuits to FORBIDDEN first). - MemoryMemberUserMissingError — the userId doesn't resolve. - LastOwnerProtectedError (FR-038) — reachable via the idempotent upsert path when the call would demote an existing sole owner to reader/writer.
memoryRef String #764 — the memory as an id or URN. Supply this OR memoryId.
userRef String #764 — the user as an id / email / handle / hrn:user:<handle> URN. Supply this OR userId.
role MemoryMemberRole!
updateMemoryMemberRole UpdateMemoryMemberRolePayload! 023-app-shape US4 — change the role on an existing team member. Throws MemoryMemberNotFoundError when the row doesn't exist; use addMemoryMember to upsert. Throws LastOwnerProtectedError (FR-038) when demoting the sole remaining owner. Caller-authority rule matches addMemoryMember. Error codes (extensions.code, Error.name style): - UNAUTHENTICATED — no logged-in user in context. - FORBIDDEN — caller is not an owner of a live group memory. - MemoryNotFoundForMemberError — memory absent or soft-deleted (only reachable from non-GraphQL callers in v1 — the guard short-circuits to FORBIDDEN first). - InvalidMemoryClassForMemberError — memory is not group-class (same; guard short-circuits to FORBIDDEN first). - MemoryMemberNotFoundError — no row at (memoryId, userId). - LastOwnerProtectedError (FR-038) — would demote the sole owner.
memoryRef String #764 — the memory as an id or URN. Supply this OR memoryId.
userRef String #764 — the user as an id / email / handle / hrn:user:<handle> URN. Supply this OR userId.
role MemoryMemberRole!
removeMemoryMember RemoveMemoryMemberPayload! 023-app-shape US4 — remove a team member. Idempotent. Removing the LAST owner is rejected with LastOwnerProtectedError (FR-038) — group memories must always have ≥1 owner; the path to fully empty one is to delete the Memory. Removing the last non-owner does NOT delete the Memory (FR-031); the row persists with its remaining owner(s). Caller-authority: either an owner of the Memory, or the member being removed (self-removal).
memoryRef String #764 — the memory as an id or URN. Supply this OR memoryId.
userRef String #764 — the user as an id / email / handle / hrn:user:<handle> URN. Supply this OR userId.
publishAgentImport AgentImport! Publish a dependency edge from a parent Agent to an imported Agent (008-agent-installation FR-005). v1 supports 1-level imports only: the imported Agent must not itself be a parent of any other import. Authorization: ADMIN/OWNER of the parent Agent's owning org. The parent's owning org MUST hold an active AgentOrgGrant for the imported Agent — bundling requires the same kind of license that installation does. Accepts the entity's ID or URN for both Agent ids.
parentAgentRef ID!
importedAgentRef ID!
position Int!
required Boolean
removeAgentImport Boolean! Delete a dependency edge between two Agents. Idempotent (no-op when the row doesn't exist). Apps that already installed the imported Agent are unaffected; removing the import only stops *future* parent installs from cascading the dep. Accepts the entity's ID or URN.
parentAgentRef ID!
importedAgentRef ID!
createAppKey AppKeyCreated! Mint a new AppKey for an App. Accepts the entity's ID or URN.
appRef ID!
label String
revokeAppKey Boolean!
id ID!
createUserApiKey UserApiKeyCreateResult! 025-oauth-for-mcp FR-004: mint a new user-scoped API key for the calling User. Returns the raw key exactly once (the server stores only the SHA-256 hash). Rejected with UNAUTHENTICATED for AppKey- resolved callers (no user in context). Per Clarifications, label is optional (portal defaults to a placeholder when omitted).
label String
revokeUserApiKey UserApiKey! 025-oauth-for-mcp FR-004: revoke a user-scoped API key owned by the calling User. Returns the updated UserApiKey so the portal can render the new revokedAt without a refetch (PR-137 review delta D3 — was Boolean). Idempotent for already-revoked keys; rejected with FORBIDDEN if the key belongs to another user; NOT_FOUND if id does not exist; UNAUTHENTICATED for AppKey- resolved callers.
id ID!
revokeAgentSubscription AgentSubscription! 005-agent-subscription FR-023 + FR-028 + FR-029: revoke a user's AgentSubscription. Authorized for ADMIN/OWNER of the Agent's owning org. Side effect: empty personal Memory of (user, agent) is hard- deleted; non-empty is retained with userMemoryOfAgentId preserved. Accepts the entity's ID or URN (agentId).
userRef String #764 — the user as an id / email / handle / hrn:user:<handle> URN. Supply this OR userId.
agentRef String #764 — the Agent as an id / URN. Supply this OR agentId.
createAppUser User!
externalId String!
handle String
name String
email String
startAgentSession Session!
agentId ID!
externalUserId String
sessionTimeoutSeconds Int
dataKey String
endAgentSession Boolean!
sessionId ID!
linkMemoryToUser Memory! Link an anonymous memory to a real user (converts session memory ownership). Providing dataKey encrypts the memory in place atomically with the link. Accepts the entity's ID or URN.
memoryId ID!
externalUserId String!
dataKey String
encryptMemory Memory! Convert a plaintext PRIVATE memory to encrypted (spec 041, caller-held keys). Exactly one of dataKey (base64, 32 bytes) / passphrase (scrypt- derived; salt + params stored on the memory, the key itself never). Owner or org-App-key. All node content/abstract/data is re-written as ciphertext in one transaction. One-way without the key: the server cannot recover the content. Accepts the entity's ID or URN.
memoryId ID!
dataKey String
passphrase String

Objects

AccessGrant

issue #323: one reason a subject has (or would have) access to a resource.

Field Argument Type Description
source AccessSource!
role String! The role/level this particular grant confers.
via String Human label for the grant's origin (owning org URN, the inherited memory URN, the app URN, etc.); null when the grant has no distinct origin.

ActionTicket

One consumable ticket in the org ledger (cor:acl:050:04 tier 2).

Field Argument Type Description
id ID!
organizationId ID!
appId ID
action String!
mintedBy String!
note String
consumedByRunId ID
consumedAt DateTime
expiresAt DateTime
createdAt DateTime!

ActionTicketsPage

Field Argument Type Description
items [ActionTicket!]!
total Int!

AddMemoryMemberPayload

Field Argument Type Description
memoryMember MemoryMember!

Agent

Field Argument Type Description
id ID!
organizationId String
urn String!
name String!
description String
systemPrompt String
systemMemoryId String
visibility AgentVisibility!
listedOnMarketplace Boolean! cor:acl:080:04 — opt-in marketplace catalogue flag (advertisement, not access).
type AgentType!
surfaces [String!]!
personaRole String Persona role - free string with conventions ('backend-engineer').
personaPrompt String Persona identity TEMPLATE ('You are {{name}}, ...'); {{name}}/{{role}} are bound at casting time (Worker.prompt returns the bound result).
aiProvider String
aiModel String
hasAiApiKey Boolean!
aiApiKeyPreview String
properties JSON
memoryItems [AgentMemoryItem!]!
memoryProvisioning MemoryProvisioning!
installationPolicy InstallationPolicy!
imports [AgentImport!]!
importedBy [AgentImport!]!
apps [App!]! Apps that have this Agent installed (via the AppAgent join). After spec 023-app-shape, an App can install multiple Agents; this list contains every App where THIS Agent is one of the installed ones. #551: these are OTHER tenants' App objects (whose keys/members are not re-gated at the field level), so — unlike the Agent's own fields — this is NOT public on a PUBLIC agent. Scoped to Apps in orgs the CALLER belongs to (platform ADMIN/OWNER: all); a non-member gets an empty list.
appAgents [AppAgent!]! 023-app-shape: the AppAgent join rows where this Agent is installed. Use App.appAgents to get the join rows from the App side. #551: same caller-org scope as apps — never exposes a foreign org's App.
appCount Int! Adoption count. #551: the agent owning-org members' view (0 otherwise).
orgGrants [AgentOrgGrant!]! Org grants for this Agent (which orgs were granted it). #551: the agent's customer list — visible to members of the Agent's owning org only (empty otherwise), regardless of the agent's PUBLIC visibility.
createdAt DateTime!

AgentAIConfig

Field Argument Type Description
provider String!
apiKey String!
model String!

AgentImport

Field Argument Type Description
parentAgentId ID!
importedAgentId ID!
parentAgent Agent!
importedAgent Agent!
position Int!
required Boolean!
createdAt DateTime!

AgentMemoryItem

Field Argument Type Description
id ID!
memory Memory!
role String!
createdAt DateTime!

AgentOrgGrant

Field Argument Type Description
orgId ID!
agentId ID!
organization Organization!
agent Agent!
activatedAt DateTime
expiresAt DateTime
revokedAt DateTime
revokedBy ID
isActive Boolean!
createdAt DateTime!

AgentSchedule

Recurring trigger (cor:agt:010, D-2026-07-04-E).

Field Argument Type Description
id ID!
organizationId ID!
appId ID!
agentId ID
userId ID On-behalf-of user captured at creation; v1 only the creator themself.
name String!
cron String 5-field cron for recurring schedules; null for one-shots (#510).
runAt DateTime One-shot instant (#510); null for recurring schedules. XOR with cron.
timezone String!
entryNodeUrn String!
eventData JSON
policy JSON
aiConfigName String
enabled Boolean!
lastRunAt DateTime
nextRunAt DateTime
createdAt DateTime!
createdBy String

AgentSchedulesPage

Field Argument Type Description
items [AgentSchedule!]!
total Int!

AgentSubscription

Field Argument Type Description
userId ID!
agentId ID!
user User
agent Agent
activatedAt DateTime
expiresAt DateTime
revokedAt DateTime
revokedBy ID
isActive Boolean!
createdAt DateTime!

AgentWebhook

Webhook trigger (D-2026-05-02). The secret is NEVER exposed here — the URL is returned once at create/rotate.

Field Argument Type Description
id ID!
organizationId ID!
appId ID!
agentId ID
userId ID
name String!
argsSchema JSON
entryNodeUrn String!
eventData JSON
policy JSON
aiConfigName String
enabled Boolean!
lastCalledAt DateTime
createdAt DateTime!
createdBy String

AgentWebhookCredentials

Create/rotate result — path + platform token are shown ONCE.

Field Argument Type Description
webhook AgentWebhook!
path String! Server-relative URL path: /hooks/<secret>/<name>. Append ?hpt=<token>.
token String! The time-limited platform JWT (hpt) — the second factor. Store it now.

AgentWebhooksPage

Field Argument Type Description
items [AgentWebhook!]!
total Int!

AgentsPage

Field Argument Type Description
items [Agent!]!
total Int!

AiModelPrice

Field Argument Type Description
id ID!
provider String!
model String!
tier Int!
inputMicroCentsPerMTok String!
outputMicroCentsPerMTok String!
markupBasisPoints Int
effectiveAt DateTime!
createdAt DateTime!
createdBy String

AiModelPriceList

Field Argument Type Description
items [AiModelPrice!]!
total Int!

AiServiceConfig

036-ai-service-config: a named AI service configuration (masked management view — never carries key material beyond the preview). Owned by exactly one of HadronServer / Organization / App / Agent. Resolution walks App -> Agent -> Org (of the App) -> HadronServer and returns the first ENABLED config with the requested name. Well-known fallback name: 'default' (conventional extras: 'fast', 'frontier'). Name is unique per owner.

Field Argument Type Description
id ID!
name String!
ownerType AiConfigOwnerType!
ownerId ID! ID of the owning HadronServer / Organization / App / Agent.
provider String! Provider identifier; v1 known: 'anthropic' | 'openai' | 'glm' | 'bedrock'.
model String! Model identifier, passed verbatim to the provider.
hasApiKey Boolean!
apiKeyPreview String Ellipsis + last 4 characters of the stored key; null when no key.
params JSON Provider-specific knobs (maxTokens, thinking, effort, baseUrl, ...).
enabled Boolean! Disabled configs are skipped by resolution (the walk continues outward).
createdAt DateTime!
updatedAt DateTime

AiServiceConfigsPage

Field Argument Type Description
items [AiServiceConfig!]!
total Int!

App

Field Argument Type Description
id ID!
name String!
urn String!
policy JSON App-layer action-policy link (cor:acl:040:02, #510). Null = no restriction. Org-admin-authored via updateApp.
organizationId String
organization Organization
agentId ID
agent Agent
installedAgentUrn String The installed Agent's canonical URN. An installed agent stays AUTHOR-ROOTED forever, so this is simply the Agent's own URN: hrn:agent:<author-org>:<agent-slug>. Two orgs installing same-slug agents from different authors therefore still produce distinct URNs (they differ at the author root), enabling audit-log entries to identify each install unambiguously without a PK disambiguator. The v1 spec-021 R2 install chain (hrn:agent:<installing-org>::<app-slug>::<author-org>:<agent-slug>) is RETIRED — see #697 Stage 2 / D10 and emitInstalledAgentUrnV2. Returns null when the App has no agent attached (orphan apps from the 008 cutover; new apps require an agentId per 009).
trainingMode Boolean!
surfaces [String!]!
members [AppMember!]!
memberCount Int!
sharedMemory Memory The App's SHARED app-class memory (#965) — the team space the shared/team chat and the worklog live in, provisioned at install since #951. This is the App → memory hop clients need to default a team-memory argument (hadron-cli#399) instead of scanning every readable memory for Memory.appId. Read-only resolution, never provisions: the memory holding the App's 'worklog' root wins (the ledger home — oldest, mirroring the worklog locator), else the oldest agent-keyed shared row (sharedMemoryOfAgentId set; Worker working memories are also app-class rows under this App and are never this answer). Null when nothing has provisioned a shared memory yet (an App predating #951 with no team activity), or when the caller cannot read the memory record (the ordinary record read gate — denied and missing are indistinguishable).
appType AppType!
role AppMembershipRole!
description String
systemPrompt String
agentTools [String!]!
aiProvider String
aiModel String
hasAiApiKey Boolean!
expiresAt DateTime
createUserPermission CreateUserPermission!
identifyUserMethod IdentifyUserMethod!
sessionTimeoutSeconds Int!
anonymousTtlDays Int!
appAgents [AppAgent!]! 023-app-shape US1: Agents installed in this App, via the AppAgent N:M join. Multiple Agents can be installed; one App credential routes to all of them via the URN supplied in the request.
agents [Agent!]! 023-app-shape: convenience that returns every installed Agent (equivalent to App.appAgents.map(aa => aa.agent)). Previously was a soft-deprecated single-element synthesis; now returns the FULL multi-Agent set per spec 023 US1.
keys [AppKey!]!
createdAt DateTime!
updatedAt DateTime

AppAIConfig

Field Argument Type Description
provider String!
apiKey String!
model String!

AppAgent

023-app-shape US1: the App↔Agent N:M join. Reintroduced after spec 008 collapsed it; per FR-003 it carries NO role column (system memory is read-only to every App) and per FR-001 it carries NO trainingMode column (training mode is per-App, on App.trainingMode).

Field Argument Type Description
app App!
agent Agent!
createdAt DateTime!
createdBy String
updatedAt DateTime
updatedBy String

AppCreated

Field Argument Type Description
app App!
rawKey String!

AppKey

Field Argument Type Description
id ID!
appId String!
keyPreview String!
label String
createdAt DateTime!
lastUsedAt DateTime
revokedAt DateTime

AppKeyCreated

Field Argument Type Description
key AppKey!
rawKey String!

AppMember

Field Argument Type Description
appId ID!
userId ID!
app App!
user User!
role String!
isOrgExternal Boolean! 023-app-shape US2: true when this User is an AppMember of the App but NOT an OrgMember of the App's owning Organization. Derived at query time from the absence of an OrgMember row (per spec 023 FR-011 — no appOnly column is added to the AppMember table). Unlocks the B2C / therapy / consumer use cases where end-users use an App without joining the operator's org.
createdAt DateTime!
updatedAt DateTime

AppRun

Field Argument Type Description
id ID!
urn String Computed grammar-v2 URN hrn:apprun:<root>:<app>:<run-id> (#696). Null for the rare multi-segment App URN the flat shape cannot express.
organizationId ID!
appId ID!
agentId ID
userId ID On-behalf-of user (cor:agt:010:01). Null = pure App service identity.
triggerKind AppRunTriggerKind!
triggerId ID
entryNodeUrn String!
eventData JSON
data JSON The run envelope (plan-multi-node D-MN-1): fields extracted by flow nodes as the walker advances. eventData stays the immutable trigger payload; on key collision the envelope wins.
hops JSON Per-hop trail (#538): one element per completed hop — [{node, edgeOut, startedAt, finishedAt, tokensSpent}]. edgeOut is the routing edge taken FROM the hop (null on the last). A hop that failed mid-execution has no element; curNodeUrn + failure identify it.
spawn JSON Fan-out state (plan-spawn, #548): set on runs that called hadron_spawn — {processItem, itemKey, callback?, itemCallback?, total, callbackFiredAt?, callbackError?}. callbackError records a callback mint that was denied (quota/policy) — the digest that never came.
policy JSON
budgetTokens Int Remaining LLM-token budget — live-decremented; zero halts the run.
budgetActions Int Remaining action budget — live-decremented per write/tool action.
tokensSpent Int Total LLM tokens consumed by this run (#832). Unclamped, so it stays truthful when a hop overshoots the remaining budget — unlike budgetTokensInitial minus budgetTokens, whose decrement is clamped. Counts every hop whose LLM call COMPLETED, including hops whose run later failed — strictly more than a sum over the hops trail, which has no element for a hop that did not complete. KNOWN GAP: a hop aborted by the TOOL LOOP (a tool denied by policy, or a tool handler that threw) is NOT counted. The provider has already billed that call, but the tool-loop helper discards the accumulated usage when a tool throws, so the number is not available at the failure site. Such a run under-reports. Do not treat this as a billing figure. NULL means UNKNOWN: a run minted before the counter existed, with no hop trail to back-fill from. 0 means it genuinely spent nothing.
actionsSpent Int Total budgeted actions consumed (#832) — only actions actually admitted by the budget guard; a denied action counts nothing. NULL means UNKNOWN, not zero: runs minted before the counter existed have no recorded action spend and, unlike tokens, no hop-trail signal to reconstruct one from. Reporting 0 would contradict their already-decremented budgetActions.
budgetTokensInitial Int The token budget this run was MINTED with — budgetTokens is what REMAINS. NULL for runs minted before this was recorded, which is deliberate: 0 would render as 'no budget' rather than 'unknown'.
budgetActionsInitial Int The action budget this run was minted with (#832). NULL for pre-existing runs.
status AppRunStatus!
curNodeUrn String
parentRunId ID
failure JSON
timeoutMs Int
attempts Int!
startedAt DateTime
finishedAt DateTime
createdAt DateTime!
createdBy String
app App The App this run activated. Null when the caller may not read that App, or when the App row was hard-deleted. appId remains the audit record.
agent Agent The agent that ran, when the run resolved one and the caller may read it.
user User On-behalf-of user (cor:agt:010:01). Null = pure App service identity. Personal fields on the returned User carry their own #384 gate.
entryNode Node The resolved entry node. NULLABLE by design — entryNodeUrn is the immutable audit record and the node may have been deleted, moved, or be unreadable to this caller since the run. A null here is a normal, expected state.

AppRunsPage

Field Argument Type Description
items [AppRun!]!
total Int!

AppsPage

Field Argument Type Description
items [App!]!
total Int!

Asset

Field Argument Type Description
id ID!
memoryId ID!
filename String!
mimeType String!
sizeBytes Int!
scanStatus AssetScanStatus!
scanSignature String Engine signature name recorded when the scan verdict was BLOCKED (the row is kept as an audit tombstone; its bytes are deleted). Null otherwise.
description String
uploadedAt DateTime!
uploadedBy ID Uploader (User id). Null when the asset was created server-side by an app run (hadron_store_file).
deletedAt DateTime
urn String! The asset's URN, grammar v2 (cor:urn:010:01): hrn:asset:<root>:<mem...>:assets:<asset.id>, emitted by emitAssetUrnV2 from the holding memory's STORED urn. <mem...> is one or more atoms, not always one. A per-user memory urn minted before the #697 Stage-3 flip is still compound (<root>:<agent>:app-user:<id> and friends), and each extra memory atom lengthens the asset URN with it — so the 'assets' marker is not at a fixed offset. A parser recovering the holding memory must take everything between the type word and that marker, never a fixed two-atom prefix. Prefer locating the LAST 'assets' atom and reading the id after it (assetIdFromRef does exactly this). Two degraded shapes a parser must tolerate, both of which really occur: * hrn:asset:unknown:assets:<asset.id> — the holding memory row could not be loaded. Carries no memory identity at all. * <memory.urn>:assets:<asset.id> — the pre-#697 shape, with NO hrn:asset: prefix, served when v2 emission throws (empty, over-length or charset-invalid atom in the stored memory urn). It interpolates the stored memory urn verbatim, which is normally bare (<root>:<slug>), so this shape usually looks like acme.com:docs:assets:<id>. A third oddity is reachable through the NORMAL branch, not a fallback: a legacy memories.urn row that predates the chk_memory_urn_not_prefixed guardrail can still hold a rendered hrn:mem:-prefixed value, and that composes into hrn:asset:hrn:mem:<root>:<slug>:assets:<id>. A prefix strip that assumes one leading type word will mis-read it.
publicUrl String Stable, UNAUTHENTICATED hotlink to the bytes (GET /assets/<id>). Anyone with this URL can fetch the file — there is no read gate on it. A deliberate, temporary posture; see src/api/assetPublic.ts. Do not present it in a UI as though it were access-controlled. Null when the server has no BASE_URL configured (no canonical origin to build an absolute URL from), when the asset is not CLEAN, or when its memory is encrypted — encrypted memories are never hotlinkable, since an anonymous request holds no session key.

AssetDownloadUrl

Field Argument Type Description
url String!
expiresAt DateTime!
filename String!
mimeType String!
sizeBytes Int!

AssetListResult

Field Argument Type Description
assets [Asset!]!
total Int!
hasMore Boolean!

AssetPutHeader

Field Argument Type Description
name String!
value String!

AssetsPage

Uniform find-many envelope for assets (spec cor:api:120).

Field Argument Type Description
items [Asset!]!
total Int!

AuthContext

Field Argument Type Description
principalType PrincipalType!
user User
appId ID
agentId ID
apiKey UserApiKey
impersonation ImpersonationInfo

BeginAssetUploadResult

Field Argument Type Description
uploadId ID!
putUrl String!
putHeaders [AssetPutHeader!]!
expiresAt DateTime!
storageKey String!
maxSizeBytes Int!
allowedMimeType String!

CalendarAttendee

Field Argument Type Description
name String
address String!
optional Boolean!
response CalendarEventResponse!

CalendarEvent

Field Argument Type Description
id ID!
calendarId String!
title String
description String
location String
start CalendarEventTime!
end CalendarEventTime!
isAllDay Boolean!
status String! confirmed, tentative, or cancelled (provider-neutral vocabulary).
organizer CalendarPerson
isOrganizer Boolean! True when the connected account organized the event.
attendees [CalendarAttendee!]!
myResponse CalendarEventResponse The connected account's own response; null when it is not an attendee.
webLink String
seriesId ID Series id when this is an instance of a recurring event.
createdAt DateTime
updatedAt DateTime

CalendarEventTime

An event boundary: exactly one of dateTime (timed, with timeZone) or date (YYYY-MM-DD, all-day) is set.

Field Argument Type Description
dateTime DateTime Instant for a timed event. Exactly one of dateTime / date is set.
date String Calendar date for an all-day event, as YYYY-MM-DD. Deliberately String and NOT DateTime (#205): an all-day event has no instant, and widening it to a timestamp would force a timezone the provider never supplied.
timeZone String

CalendarInfo

One calendar the connected account can see.

Field Argument Type Description
id ID!
name String!
description String
timeZone String
isPrimary Boolean! True for the account's primary calendar (the default calendarId).
canEdit Boolean! True when the connected account may create/modify events here.

CalendarPerson

Field Argument Type Description
name String
address String

CastWorkerPreview

What castWorker WOULD do (#964) — an unsaved projection, deliberately not a Worker (no fake id to mistake for a real row). Scalars only: the ids/names here are attribution-level facts the mint-gate audience already sees, so no nested entity hands out its field resolvers.

Field Argument Type Description
name String! The name the cast would allocate: the explicit name, or the first register entry free against the App's FULL roster (retired names stay taken).
role String The casting's role: explicit, else the agent's personaRole dressing.
agentId ID! The role-agent the casting would bind.
agentName String!
teamAgentId ID The Team Agent whose register resolved the name (register mode only; null with an explicit name).
teamAgentName String
prompt String The composed boot prompt, post {{name}}/{{role}} substitution with promptOverride appended — the same composition Worker.prompt performs, reviewable BEFORE the name is permanent. Null when the agent carries no template and no override was given.
hasNamePlaceholder Boolean Whether the agent's personaPrompt binds {{name}} — a nameless template silently produces workers whose prompt never names them. Null when the agent has no template.

Chat

Field Argument Type Description
id ID!
loc String!
title String!
conversationName String
stageName String
messageCount Int!
createdAt DateTime!
lastMessageAt DateTime
scope ChatScope!
createdBy ID

ChatMessage

Field Argument Type Description
role String!
content String!
seq Int
createdAt DateTime!

ChatPromptResult

Field Argument Type Description
systemMessage String!
tools JSON
messageHistory JSON!
summarizationNeeded SummarizationRequest

ChatResponseResult

Field Argument Type Description
displayMessage String!
stageTransitioned Boolean!
newStageName String
conversationHandoff String
chatEnded Boolean!
onTrack Boolean!
offTrackReason String

ChatStartResult

Field Argument Type Description
chatId String!
systemMessage String!
tools JSON
conversationName String
stageName String

ConnectionGrant

A user-owned connection's scoped delegation to an App install (spec-042 Track B, #593). The connection OWNER grants a specific App scoped access to their mailbox/calendar; the enforcement gate is requireEmailConnection. The grantee App is exposed as SCALARS only (never a nested App object), so a cross-org grant can't reach the App keys/members. Token material is never exposed.

Field Argument Type Description
id ID!
connectionId ID!
granteeAppId ID! The App install this grant delegates to.
granteeAppUrn String Canonical URN of the grantee App (hrn:app:<root>:<slug>), or null if unresolvable.
granteeAppName String
scopes [String!]! Covered scopes: mail.read, mail.send, calendar.freebusy, calendar.read.
expiresAt DateTime ISO-8601 expiry, or null for perpetual (until revoked).
createdAt DateTime!

ConnectionGrantsPage

Field Argument Type Description
items [ConnectionGrant!]!
total Int!

CreateMemorySharePayload

Field Argument Type Description
memoryShare MemoryShare!

CreditBalance

Field Argument Type Description
organizationId ID!
balanceMicroCents String!

CreditLedgerEntry

Field Argument Type Description
id ID!
organizationId ID!
kind String!
amountMicroCents String!
expiresAt DateTime
sourceType String
sourceId String
note String
createdAt DateTime!
createdBy String

CreditLedgerEntryList

Field Argument Type Description
items [CreditLedgerEntry!]!
total Int!

DashboardWidget

One widget the caller has placed on their /app/dashboard grid (#772).

Field Argument Type Description
id ID!
type DashboardWidgetType!
span Int! Columns spanned on the 12-col desktop grid.
rowSpan Int! Rows spanned on the fixed-height row grid (#788).
position Int! 0-based sort order among the caller's widgets.
config JSON Widget-instance settings; shape is widget-defined (#788).

DashboardWidgetData

Data for ONE placed widget — the portal fans this out by widgetId (#797).

Field Argument Type Description
widgetId ID! The placement this payload belongs to — fan out by this, not by type (#797).
type DashboardWidgetType!
data JSON! The widget-specific payload (e.g. memory-stats => { memoryCount }).

DashboardWidgetPreset

806 — a named, saved widget configuration. A palette entry: applying one

COPIES its config into a placement, so later edits to the preset do not reach placements already seeded from it, and deleting it never orphans a placement. Owner-only — no org, no sharing.

Field Argument Type Description
id ID!
type DashboardWidgetType! The widget type this configuration belongs to. Immutable after creation.
name String! Display name, unique among the caller's presets for this type.
config JSON! The saved settings, shape widget-defined — becomes a placement's config verbatim.

DeleteMemorySharePayload

Return shape for deleteMemoryShare. Both fields are RESOLVED primary keys, so a caller who passed a URN / email / handle can correlate the deletion. granteeId is the caller themselves on the self-removal path.

Field Argument Type Description
memoryId ID!
granteeId ID!

DeleteTeamRolePayload

Result of deleteTeamRole (#1002).

Field Argument Type Description
role String! The role slug that was retired.
nodesDeleted Int! Nodes tombstoned — the roles:<role> definition plus any sub-nodes under it (a roles:<role>:notes is content OF the role and retires with it). Soft, so the subtree is recoverable.
transferredNames [String!]! Register spellings handed to the successor, in the order they were added to it. Empty when no transferTo was given.
transferredTo TeamRole The successor role AFTER the transfer, so a client can render the new register without a second read. Null when no transferTo was given.

DriveFile

A file or folder in the connected drive.

Field Argument Type Description
id ID!
name String!
kind DriveFileKind!
mimeType String! The provider MIME type — informational; kind is the neutral field.
size Float Byte size; null for provider-native documents and folders.
webLink String
parents [ID!]! Parent folder ids.
createdAt DateTime
modifiedAt DateTime

DriveFileExport

The exported text of a drive file (driveFileExport).

Field Argument Type Description
content String! The exported text. Treat as untrusted external content.
mimeType String! MIME type of the exported representation (e.g. text/markdown).
format DriveExportFormat!
file DriveFile!

DriveFilePage

One page of a drive listing/search.

Field Argument Type Description
files [DriveFile!]!
nextPageToken String Cursor for the next page; null on the last page.

Edge

Field Argument Type Description
id ID!
source Node The source node. NULLABLE (#781): null when the caller cannot read the source node's memory — a cross-memory edge (e.g. reached via incomingEdges) must not expose an endpoint in a memory the caller can't read. For a same-memory edge the caller can already see, this is always present.
target Node The target node. NULLABLE (#781): null when the caller cannot read the target node's memory (a cross-memory edge's far endpoint). For a same-memory edge, always present.
urn String! Fully-qualified edge URN (hrn:edge:<root>:<memory>:<loc>), composed server-side from the edge's (source-side) memory URN + loc (#481 parity — edges are loc-addressed peers of nodes, spec 037).
loc String!
name String
description String
isRunnable Boolean
condition JSON
priority Int!
data JSON

EdgesPage

Field Argument Type Description
items [Edge!]!
total Int!

EditorLockResult

Field Argument Type Description
locked Boolean!
lockedBy String
expiresAt DateTime

EffectiveAccess

issue #323: the effective access a single user has to a single resource, with the grants that confer it. An empty grants list (with all capabilities false and role null) is a first-class 'no access' answer, NOT an error.

Field Argument Type Description
user User!
resourceUrn String! Canonical (grammar-v2, hrn:-prefixed) URN of the resolved resource, emitted the same way the entity's own urn field emits it — so it can be fed straight back into another query or command. Two exceptions have no URN by nature: an AiServiceConfig yields its id, and a user yields hrn:user:<handle>.
resourceKind String! memory | node | app | agent | aiServiceConfig | organization | user.
canRead Boolean!
canWrite Boolean!
canManage Boolean! Manage grants / settings (admin/owner-equivalent).
canDelete Boolean!
role String Highest single clean role label (e.g. owner, writer, ADMIN); null when access is purely capability-based or absent.
grants [AccessGrant!]! The reasons access is granted. Empty means no access. Ordered strongest-first.

EffectiveActionPolicy

The standing-chain policy debug surface (#510): per-layer verdicts for one action (cor:acl:040:02). Trigger/run links are per-trigger and not part of the standing chain.

Field Argument Type Description
allowed Boolean!
layers [PolicyLayerVerdict!]!

EmailDraftInfo

Field Argument Type Description
draftId ID!
conversationId ID

ExchangeConnection

Field Argument Type Description
id ID!
organizationId String!
userId String!
mailboxEmail String!
displayName String
provider String!
syncEnabled Boolean!
syncStatus SyncStatus!
lastSyncAt DateTime
lastError String
createdAt DateTime!
updatedAt DateTime!

ExchangeFolder

Field Argument Type Description
id ID!
displayName String!
totalItemCount Int
unreadItemCount Int

ExchangeMessage

Field Argument Type Description
id ID!
subject String
from String
receivedDateTime DateTime
isRead Boolean
bodyPreview String
body String
hasAttachments Boolean

FindNodesResult

Envelope for findNodes (cor:api:090) — the unified node list + search field (it replaced the removed nodes + nodeSearch queries). hits carry per-hit score + vector metadata; passages carry chunk-granularity results; reason/degraded surface no-index / reduced-fidelity outcomes.

Field Argument Type Description
hits [NodeHit!]!
passages [Passage!]!
total Int
reason String
degraded String Reduced-fidelity flag(s); hits are usable. May carry MULTIPLE comma-separated codes (e.g. 'no_vector_index,literal_fallback') — parse the set, never compare the whole string. Codes: no_vector_index, embedding_unavailable, literal_fallback, and_relaxed_to_or (a bare multi-term keyword query matched nothing under AND, so it was retried as OR and these hits match ANY term).

GlobalSearchHit

One unified, flat globalSearch result — common fields across every entity type so a single ranked list renders uniformly. urn is null for an aiServiceConfig (no URN) and for a user with no handle or a not-URN-legal handle (a user's URN is hrn:user:<handle>); memoryId / organizationId are convenience handles for building canonical navigation paths.

Field Argument Type Description
entityType SearchEntityType!
id ID!
urn String
name String
description String
matchedField SearchField!
score Float!
memoryId ID
organizationId ID

GlobalSearchResult

Field Argument Type Description
hits [GlobalSearchHit!]!
total Int! Total ranked matches for building a pager. BOUNDED CONTRACT: this is the count within the per-entity candidate cap (each entity type contributes at most a fixed number of candidates before scoring), not an unbounded COUNT. On very large result sets it under-counts; page slicing (offset/limit) operates over this bounded, fully-ranked list.
degraded [String!]! Notes when the search ran at reduced fidelity (e.g. content search skipped on encrypted memories).

GraphEdge

Slim edge projection for the graph view (issue #466) — endpoint IDs only.

Field Argument Type Description
id ID!
loc String!
name String
sourceId ID!
targetId ID!

GraphEdgesPage

Paged envelope for memoryEdges — total is the memory's full edge count.

Field Argument Type Description
edges [GraphEdge!]!
total Int!

GraphNode

Slim node projection for the graph view (issue #466) — only what a node-link graph draws.

Field Argument Type Description
id ID!
loc String!
name String! Non-null — mirrors Node.name (the DB column is NOT NULL).
nodeType String! Non-null — mirrors Node.nodeType (NOT NULL, defaults to 'info').
tags [String!]!
seq Int Sibling sort order in the tree view (nullable; #513). Small scalar — kept in the slim projection.
isRunnable Boolean Whether the node can be run as a task — drives the tree action indicator (nullable; #513).
description String Short one-line description for graph tooltips / detail (nullable; #513). NOT the heavy body — content/abstract/data stay out of the slim projection.

GraphNodesPage

Paged envelope for memoryNodes — the standard limit/offset/total idiom; total is the memory's full node count.

Field Argument Type Description
nodes [GraphNode!]!
total Int!

HomeAssistantInstance

Field Argument Type Description
id ID!
organizationId String!
slug String! Run-tool name segment (ha__<slug>__<op>); lowercase [a-z0-9-], unique per org, immutable.
name String!
url String! Home Assistant base URL (e.g. https://ha.example.com or a Nabu Casa remote URL).
opAllowlist [String!]! Exposed-op allowlist over the closed op catalog; empty = every op. Lets an admin register a read-only instance.
enabled Boolean! Disabled instances fail run-tool resolution loud, same as an unregistered slug.
createdAt DateTime!
createdBy String
updatedAt DateTime!
updatedBy String

HomeAssistantInstancesPage

Field Argument Type Description
items [HomeAssistantInstance!]!
total Int!

HomeAssistantOp

Field Argument Type Description
op String! The op segment, e.g. call_service.
description String!
runToolName String! The run-tool / policy name: ha__<slug>__<op>.
inputSchema JSON The op's argument JSON Schema.

ImpersonationInfo

Field Argument Type Description
sessionId ID!
actorUser User
organizationId ID!
expiresAt DateTime!
readOnly Boolean!

ImpersonationSession

Field Argument Type Description
id ID!
adminUser User!
targetUser User!
organization Organization!
reason String
createdAt DateTime!
expiresAt DateTime!
endedAt DateTime
endedBy ID
isActive Boolean!

ImpersonationSessionList

Field Argument Type Description
items [ImpersonationSession!]!
total Int!

ImportNodeResult

Field Argument Type Description
status ImportNodeStatus!
node Node
jobId ID Reserved for the async path — always null in sync v1.

InstallAgentIntoAppPayload

Return shape for the installAgentIntoApp mutation. Wraps the new AppAgent row so callers can read its audit fields without re-querying.

Field Argument Type Description
appAgent AppAgent!

InstallationPolicy

Field Argument Type Description
maxMembers String! Integer-as-string OR the sentinel 'unlimited'. GraphQL does not have an Int|String union; clients parse: parseInt(maxMembers) succeeds for integer values; 'unlimited' is the sentinel.
memberRoles [String!]!

JoinAppPayload

Return shape for the joinApp mutation (023-app-shape US2). The AppMember row is included so callers can read its derived isOrgExternal flag without a re-query.

Field Argument Type Description
appMember AppMember!

LeaveAppPayload

Return shape for the leaveApp mutation (023-app-shape US2). The user's personal-class Memory at (appId, userId) is NOT cascade-deleted (spec 008 FR-015 orphan retention); it re-attaches if the user later re-joins the same App.

Field Argument Type Description
appId ID!
userId ID!

McpServer

Field Argument Type Description
id ID!
organizationId String!
slug String! Run-tool name segment (mcp__<slug>__<tool>); lowercase [a-z0-9-], unique per org, immutable.
name String!
url String! Streamable-HTTP MCP endpoint URL.
toolAllowlist [String!]! Exposed-tool allowlist; empty = every tool the server advertises.
hasHeaders Boolean! Whether encrypted static headers are stored (the values are never returned).
enabled Boolean! Disabled servers fail run-tool resolution loud, same as an unregistered slug.
createdAt DateTime!
createdBy String
updatedAt DateTime!
updatedBy String

McpServerTool

Field Argument Type Description
name String! The tool's name on the external server.
description String
runToolName String! The run-tool / policy name: mcp__<slug>__<name>.
inputSchema JSON The tool's argument JSON Schema, passed through verbatim.

McpServersPage

Field Argument Type Description
items [McpServer!]!
total Int!

MemoriesPage

Field Argument Type Description
items [Memory!]!
total Int!

Memory

Field Argument Type Description
id ID!
organizationId String
organization Organization
urn String! The memory's URN, grammar v2 (cor:urn:010:01): hrn:mem:<root>:<slug...>, emitted by safeCanonicalUrn/emitEntityUrnV2 from the stored urn — so a v1 double-colon chain, a legacy single-colon row and an already-v2 row all read back identically here. <slug...> is one atom for a migrated memory but still several for a compound pre-Stage-3 per-user one (<root>:<agent>:app-user:<id>). The STORED column is the bare form (<root>:<slug>, no scheme prefix — the chk_memory_urn_not_prefixed guardrail rejects writing a rendered one); this field is the rendered view of it. When emission throws, the stored value is served raw and logged, so a bare, unprefixed value is a possible read.
name String!
shortDescription String
description String
data JSON Free-form structured metadata bag (client-defined JSON, no server-side semantics). Null when unset. Settable via createMemory / updateMemory.
schema JSON #725 — opt-in per-memory property schema (declared collections + typed fields). NULL = unstructured. Authored via updateMemory; well-formedness validated server-side.
tags [String!]!
license String
category0 String
category1 String
category2 String
iconUrl String
heroUrl String
homeUrl String
source String
readBranch String
writeBranch String
visibility MemoryVisibility
listedOnMarketplace Boolean! cor:acl:080:04 — opt-in marketplace catalogue flag (advertisement, not access).
class MemoryClass!
shareable Boolean! #766 — derived shareability signal: true iff this memory can be shared with an individual user via MemoryShare, i.e. class = 'personal' (spec 023 FR-018). Lets the CLI and portal surface or gate the share action before a createMemoryShare attempt rather than discovering InvalidMemoryClassForShareError at execution time.
acceptsUploads Boolean!
userId ID
isEncrypted Boolean!
vectorIndexEnabled Boolean!
embeddingSource EmbeddingSource!
chunkTokens Int Spec 033 US2 — chunk-window size in tokens (~4 chars/token). Null = platform default (512). Applies when embeddingSource includes content chunks.
chunkOverlap Int Spec 033 US2 — overlap between consecutive chunks in tokens. Null = platform default (64). Must be < chunkTokens.
forceFixedSize Boolean! Spec 033 US2 — force the fixed-size chunking strategy, bypassing the structure-aware default. Useful when the content's heading structure is unreliable (e.g. transcripts, machine-generated reports).
maxRevCount Int! #621 — cap on how many NodeRevision rows are kept per node in this memory. On each new revision the oldest overflow is pruned. Default 10; minimum 1.
vectorIndexEncryptedAckAt DateTime Spec 033 FR-026 — timestamp at which the memory owner accepted the encrypted-memory vector-inversion disclosure. Set when the caller passes acknowledgeVectorInversionRisk: true on updateMemory for an isEncrypted: true memory enabling vectorIndexEnabled for the first time. The portal surfaces this readback so the user can confirm when they accepted the tradeoff (the disclosure text is the FR_026_DISCLOSURE constant in src/lib/entityRef/errors.ts). Survives a revoke + re-enable cycle (never cleared). Null for unencrypted memories and for encrypted memories where the index was never enabled.
userMemoryOfAgentId String
anonymousExpiresAt DateTime
appId ID
app App
agent Agent
syncStatus SyncStatus!
syncError String
pendingEdgeCount Int!
lastSyncedAt DateTime
createdAt DateTime!
updatedAt DateTime!
subscriptions [MemorySubscription!]!
shares [MemoryShare!]! 023-app-shape US3: cross-user grants on this memory. Non-empty only when class = personal (FR-018). Includes grantee + role for each row. Visible only to the principal (memory.userId) and to ADMIN/OWNER of the memory's owning org.
myShare MemoryShare The caller's OWN share of this memory (they are the grantee), or null. Grantee-readable — unlike shares (principal / org-admin only), this returns at most the single MemoryShare row keyed (memoryId, callerId), so it never leaks co-grantees. null for a non-grantee or an App-key caller. Lets the portal render Shared-by-@grantor + the role on each shared-with-me row.
members [MemoryMember!]! 023-app-shape US4: team membership rows on this memory. Non-empty only when class = group (FR-027). Visible to any current member (any role) and to ADMIN/OWNER of the memory's owning org.

MemoryMember

023-app-shape US4: symmetric team-membership row for group-class memory. The "Company Brain" model — multiple users collaboratively read/write a shared memory, governance by role, no single owner on the Memory itself.

Field Argument Type Description
memory Memory!
user User!
role MemoryMemberRole!
createdAt DateTime!
createdBy String
updatedAt DateTime
updatedBy String

MemoryProvisioning

Field Argument Type Description
appMemory AppMemoryKind!

MemoryShare

023-app-shape US3: asymmetric cross-user grant on a personal-class Memory. The principal (memory.userId) grants a grantee read/write access. Used for per-pairing isolation patterns (e.g., Alice's personal Memory paired-with-Mentor-A is distinct from her paired-with-Mentor-B Memory, each with its own MemoryShare).

Field Argument Type Description
memory Memory!
grantee User! The User who was granted access.
grantor User! The principal of the Memory (Memory.userId). Per spec 023 FR-019 this is always the principal, even when an App backend made the API call on the principal's behalf — that actor is recorded in createdBy instead.
role MemoryShareRole!
createdAt DateTime!
createdBy String The API actor who created the row. Distinct from grantor when an App backend creates the share on the principal's behalf.
updatedAt DateTime
updatedBy String

MemorySubscription

Field Argument Type Description
id ID!
memory Memory!
organization Organization!
role Role!
activated Boolean!
createdAt DateTime!

MemoryValidationFinding

One finding (#819). nodeUrn is null when the URN could not be composed - a memory URN the flat v2 shape cannot express, or an unexpected/legacy loc - in which case nodeId and nodeLoc still identify the node.

Field Argument Type Description
kind MemoryValidationCheck!
nodeId ID!
nodeLoc String!
nodeUrn String
detail String!

MemoryValidationResult

Field Argument Type Description
memoryId ID!
nodesChecked Int! Live (non-deleted) nodes scanned - soft-deleted tombstones are excluded, since their findings would be unactionable (#884). The whole memory in one pass - the checks are cross-referential, so a partial scan would produce false positives rather than fewer findings.
findings [MemoryValidationFinding!]! Findings, capped by the limit argument.
totalFindings Int! The TRUE finding count, before any truncation - gate CI on this, not on findings.length.
truncated Boolean! True when findings was capped and totalFindings is larger.
skippedChecks [MemoryValidationSkippedCheck!]!
ok Boolean! True only when EVERY check ran and none found anything. A skipped check makes this false even with zero findings - you cannot claim health for a check you did not run.

MemoryValidationSkippedCheck

A check that could NOT run (#819). Reported explicitly rather than silently omitted: a clean bill of health that quietly skipped a check is worse than no report at all.

Field Argument Type Description
check MemoryValidationCheck!
reason String!

Node

Field Argument Type Description
id ID!
memoryId String!
nodeType String!
objectType String #725 — collection discriminator (which domain object this node is, e.g. "competitor"). NULL for an ordinary node.
loc String!
urn String! Fully-qualified node URN (hrn:node:<root>:<memory>:<loc>), composed server-side from the node's memory URN + loc (#481). Carried by every Node-returning surface (findNodes, node, appNodes, nodeBatch, mutation returns).
portalUrl String #881 — the portal URL that opens this node, built server-side so no client ever has to construct one (constructing means guessing which URN spelling the /app/u/<urn> route resolves, and the legacy '::' forms in circulation make that guess wrong). Form: <portal-origin>/app/u/<urn>, the portal's stable URN-alias route. NULL when the deployment has no portal origin configured (FRONTEND_URL) — a link to the wrong host is worse than none, so clients render the field only when present.
isLink Boolean!
name String!
alias String
description String
abstract String Paragraph-length summary of this node. Opt-in on hadron_get_node via the contentScope parameter. hadron_find_nodes preview surfacing ships in spec 031 US2 — not yet live. Never surfaced in hadron_list_nodes. Cap is 2000 characters; longer values are rejected with NodeAbstractTooLongError. Empty + whitespace-only values normalize to null. Spec 031.
abstractOriginHash String Spec 032 — fingerprint of the content value at the time abstract was authored. SHA-256 of plaintext content, truncated to 8 hex chars. Compared at read time against computeContentHash(node.content) to detect staleness; when the two values differ AND abstractOriginHash is non-null, the abstract may not reflect current content. System-managed; never settable via NodeInput.
embeddingPendingAt DateTime Spec 033 FR-006/FR-007 — set when this node needs (re-)embedding; cleared on success. The single work signal the embedding worker drains. A FUTURE-dated value is a backed-off retry not yet due (#882) — the worker only selects stamps at or before now. Operational state (never versioned on NodeRevision). The portal renders this as a subtle "embedding…" badge so a user who just edited isn't confused that their change "didn't take" in search yet. System-managed.
embeddingFailedAt DateTime Spec 033 FR-009 — set when an embed attempt failed (record, not a work signal). Retryable failures (timeouts, 5xx) reschedule with exponential backoff and never give up (#882); permanent failures (deterministic 4xx, dimension mismatch, encrypted-no-plaintext) clear embeddingPendingAt — recovery is the retryFailedEmbeddings mutation. The portal renders this as a red badge with the embeddingError message inline so users with an empty index can distinguish "nothing matched" from "every embed failed". System-managed.
embeddingError String Spec 033 — last embed error message (diagnosability; also surfaced by hadron_validate). Common values: encrypted-no-plaintext (#206), embedding-endpoint-unreachable, dimension-mismatch. Null when no failure has been recorded since the most recent success or revoke. System-managed.
embeddingAttempts Int! Spec 033 — attempt counter feeding the exponential-backoff schedule (#882 — no terminal give-up; a retryable failure never removes the node from the queue). Resets to 0 on success or revoke. Surfaced for ops diagnostics (a node at a high attempt count is retrying at the backoff ceiling and likely needs operator attention). System-managed.
content String
tokens Int
tags [String!]!
properties JSON
data JSON
seq Int
ownerRepo String
isRunnable Boolean
llmModel String
aiAgent String
createdAt DateTime!
updatedAt DateTime!
memory Memory
outgoingEdges [Edge!]!
incomingEdges [Edge!]!
asset Asset The asset this node references, for a reference node created by createAssetReferenceNode or hadron_store_file (its data.asset points at one). Null for every ordinary node. Also null when the pointer is DANGLING — the asset was deleted, or is soft-deleted. There is no schema-level Asset-to-Node foreign key (cor:dmo:060:10 reserves it), so data.asset.id is a soft reference and this resolver is what keeps it honest: never assume a node carrying data.asset still has a live asset behind it.

NodeBatchResult

Spec cor:api:040 — result envelope for the batch node read (nodeBatch). 'nodes' is the authorized, existing subset (input order for a ref set, loc order for a prefix). 'unavailable' and 'omitted' are both lists of REFS, not node objects. 'unavailable' lists the requested refs that were denied OR not found — indistinguishable, so the result never discloses whether an unreadable node exists. 'truncated' is true when the response-size cap was reached, and 'omitted' then carries the refs of the nodes dropped to stay under it. (Over the node-count cap the query errors instead — never a silent short read.) Both lists echo the caller's OWN ref strings for the 'refs' form — pass a URN, get that URN back, not a primary key you never sent — and node ids for the prefix form, which has no caller refs.

Field Argument Type Description
nodes [Node!]!
unavailable [ID!]!
truncated Boolean!
omitted [ID!]!

NodeExportResult

Field Argument Type Description
format NodeExportFormat!
mimeType String! MIME type, e.g. text/markdown or application/json.
filename String! Suggested download filename, e.g. <loc-leaf>.md.
encoding NodeExportEncoding!
data String! The rendered file contents (TEXT).
bytes Int! Byte length of the rendered payload (UTF-8).

NodeHit

A scored node hit (cor:api:090:04). score is null for an unscored filtered list (no query).

Field Argument Type Description
node Node!
score Float
vector NodeVectorMeta

NodeRevision

Field Argument Type Description
id ID!
urn String Computed end-anchored URN hrn:noderev:<root>:<mem>:<loc...>:<rev> (#696). Null for legacy rows without a revNo, and for multi-segment per-user memories the flat shape cannot express.
revNo Int Per-node monotonic revision number (#696). Null on legacy rows predating the counter (backfilled by the migration).
nodeId String!
loc String!
name String!
alias String
description String
abstract String Paragraph summary at capture (spec 031).
content String
tags [String!]!
nodeType String
isLink Boolean
properties JSON
data JSON
seq Int
isRunnable Boolean
llmModel String
aiAgent String
editedBy String The editing User id, when a user is known (#620). Use editedByUser for resolution.
editedByInfo String What is known about the editor when no User id is available (#620): 'github:<login>' / 'email:<addr>' / 'user:<id>' identity strings, or 'app:<App.id>' for App-key principals. (Legacy free-form #88 reasons / commit messages that squatted in editedBy were migrated to revLabel.)
editedByUser NodeRevisionEditor The editor resolved to a user (handle + URN) — from editedBy as a User id, the createdBy fallback (#619), or an identity-string form of editedByInfo ('github:<login>' resolves via the user's linked GitHub username). Null when nothing resolves — the portal falls back to the raw strings. Public identifiers only (#617).
revLabel String User-settable label for this revision (#620, 500-char cap) — set via updateNodeRevision; also captures the 'reason' supplied with the edit that took this snapshot (legacy reasons were migrated here).
changes [String!]! Which node fields the edit that took this snapshot changed, e.g. ["abstract","tags"] (#620). The snapshot is the PRE-edit state, so this describes the delta between this snapshot and the state that replaced it. Empty for legacy rows.
approvedBy String Reserved (#620): User id that approved this revision. No write surface yet.
approvedByUser NodeRevisionEditor approvedBy resolved to public identifiers (handle + URN), like editedByUser.
createdAt DateTime!

NodeRevisionEditor

A revision's editor resolved to PUBLIC IDENTIFIERS ONLY (#617). Deliberately excludes name / email / any PII — resolving editedBy must never widen the disclosure surface. handle + urn are the same public identifiers the users search already exposes, so no per-caller visibility gate applies.

Field Argument Type Description
handle String
urn String

NodeVectorMeta

Per-hit vector-retrieval lineage (cor:api:090:04), present when a hit came from the vector index.

Field Argument Type Description
similarity Float
model String
chunkIndex Int
offsets [Int!]
abstractStale Boolean
source String

ObjectList

745 — a page of objects from the object store. Each object is a flat JSON

record { id, type, ...fields } (the projection of a node). 'total' is the full match count (null when unbounded).

Field Argument Type Description
objects [JSON!]!
total Int

OrgMember

Field Argument Type Description
id ID!
user User!
role Role Target member's role in this org. Null when the viewer isn't an ADMIN/OWNER of the org (#384 field-level visibility); always visible for one's own membership.
canInvite Boolean!
createdAt DateTime!

Organization

Field Argument Type Description
id ID!
name String!
urn String!
policy JSON Org-layer action-policy link (cor:acl:040:02, #510). Null = no restriction. Org-admin-authored via updateOrganization.
listedOnMarketplace Boolean! cor:acl:080:04 — opt-in marketplace catalogue flag (advertisement, not access).
githubInstallationId Int
githubAppId String
hasGithubAppPrivateKey Boolean!
members [OrgMember!]!
memories [Memory!]!
agents [Agent!]!
apps [App!]!
subscriptions [MemorySubscription!]!
exchangeConnections [ExchangeConnection!]!
agentOrgGrants [AgentOrgGrant!]!
createdAt DateTime!
updatedAt DateTime!

OrganizationsPage

Field Argument Type Description
items [Organization!]!
total Int!

Passage

Spec 033 US2 — one matching chunk from a content-chunk vector index. Carries the locator metadata a RAG consumer needs for context-stuffing: span text, character offset within the parent node, chunk index, and the parent node's URN.

Field Argument Type Description
parentNodeId ID!
parentNodeUrn String!
chunkIndex Int!
charStart Int!
charEnd Int!
text String!
score Float!

PolicyLayerVerdict

One layer's verdict in an explained policy evaluation (#510).

Field Argument Type Description
layer String! org, user, or app.
present Boolean! Whether this layer has a link at all (absent = no restriction).
allowed Boolean!
allow [String!] The layer's allow-list, for display; null when absent.

PrincipalGrant

An individual action grant (design:grant-model): extra management actions for one member of one org, on top of their role bundle. Grantee and org are projected as scalars, never nested objects.

Field Argument Type Description
id ID!
principalType String! Grantee kind - 'USER' in v1.
principalId ID!
principalHandle String
organizationId ID!
organizationUrn String
actions [String!]! Allowed actions - exact ('memory.clone'), prefix ('memory.*'), or '*'.
expiresAt DateTime ISO-8601 expiry, or null for perpetual (until revoked).
createdAt DateTime!

PrincipalGrantsPage

Field Argument Type Description
items [PrincipalGrant!]!
total Int!

PublicOrganization

cor:acl:080:02 — a sanitized, non-member-safe view of a DISCOVERABLE org. Deliberately a SEPARATE type from Organization: it exposes only public identity + the org's public footprint, never members / private memories / apps / credentials (which the full Organization's nested resolvers would leak).

Field Argument Type Description
id ID!
name String!
urn String!
listedOnMarketplace Boolean!
publicMemories [PublicResourceRef!]! The org's PUBLIC, non-app-scoped memories (sanitized refs).
publicAgents [PublicResourceRef!]! The org's PUBLIC agents (sanitized refs).

PublicResourceRef

A minimal, safe reference to a public resource (marketplace / discovery).

Field Argument Type Description
id ID!
name String!
urn String!
description String

PublicResourceRefPage

A paginated page of sanitized public resource refs (marketplace catalogue).

Field Argument Type Description
items [PublicResourceRef!]!
total Int!

QuotaCounter

Usage-vs-limit for one scope x action window (#510). The stored limit is the enforced value; env defaults only seed first touch.

Field Argument Type Description
id ID!
scopeKind String! app or org.
scopeId String!
action String! run.execute, llm.tokens, sms.send, or email.send.
window String! Window kind (day). The row rolls in place at UTC midnight - used resets, limit persists.
used Int!
limit Int!
resetAt DateTime!

RemoveMemoryMemberPayload

Field Argument Type Description
memoryId ID!
userId ID!

ResendSender

One org-owned BYO Resend sender. The API key is encrypted and write-only.

Field Argument Type Description
id ID!
organizationId String!
from String! Fixed sender identity, e.g. Hadron Agent ; Resend enforces verification.
hasApiKey Boolean! Whether an encrypted API key is stored; the key is never returned.
enabled Boolean!
createdAt DateTime!
createdBy String
updatedAt DateTime!
updatedBy String

ResendSendersPage

Field Argument Type Description
items [ResendSender!]!
total Int!

ResolvedAiConfig

036-ai-service-config: privileged resolution result. Carries the DECRYPTED key — only returned by resolveAIConfig (org ADMIN of the effective context org, or platform ADMIN/OWNER); successor to agentAIConfig / appAIConfig.

Field Argument Type Description
configId ID!
name String!
ownerType AiConfigOwnerType! Which level matched: APP | AGENT | ORGANIZATION | HADRON_SERVER.
provider String!
model String!
apiKey String! Decrypted key. For provider 'bedrock' this is the JSON-encoded accessKeyId/secretAccessKey/region triple the portal stores.
params JSON

RevisionResult

Field Argument Type Description
revisionLoc String!
label String!
published Boolean!
createdAt DateTime!

ScheduleBusyInterval

Field Argument Type Description
start DateTime!
end DateTime!

ScheduleFreeBusy

Free/busy intervals for one requested schedule (calendarSchedule).

Field Argument Type Description
id ID!
busy [ScheduleBusyInterval!]!
error String Set when the provider could not resolve this schedule; the query still succeeds for the others.

SearchReplaceFieldResult

Field Argument Type Description
field NodeTextField!
matches Int!

SearchReplaceNodeResult

Field Argument Type Description
nodeId ID!
loc String!
memoryId ID!
replacements Int! Total replacements across all searched fields on this node.
fields [SearchReplaceFieldResult!]!

SearchReplaceResult

Field Argument Type Description
nodesScanned Int! Nodes the selection resolved to (after auth + prefix filtering).
nodesChanged Int! Nodes with at least one replacement.
totalReplacements Int!
dryRun Boolean! Echoes the request — true means nothing was written.
results [SearchReplaceNodeResult!]! Per-node breakdown; only nodes with at least one match are listed.

Secret

Field Argument Type Description
id ID!
ownerType String! Owner scope: user | org | app | memory.
ownerId ID!
name String! Cascade-resolution key; unique per owner; lowercase [a-z0-9-], max 64.
kind String! Extensible kind; v1: generic | webfetch-auth.
metadata JSON The NON-secret, inspectable half (webfetch-auth: { type, urlPrefix }).
createdAt DateTime!
createdBy String
updatedAt DateTime!
updatedBy String

SecretsPage

Field Argument Type Description
items [Secret!]!
total Int!

ServerInfo

Identity of the running hadron-server (see Query.serverInfo).

Field Argument Type Description
version String!
baseUrl String!

Session

Field Argument Type Description
id ID!
type String!
appId String
userId String
agentId String The role-agent driving the session (with workerId set, the agent behind the casting).
workerId String #974 / cor:agt:020:03: the Worker (named casting) this session works as.
worker Worker #980 / cor:agt:020:02: the Worker behind workerId, nested — so a session list can render the app-qualified compound ('eng-team/Iris') without a per-row worker(ref:) + app(ref:) round trip (Worker carries name and app). Resolves for RETIRED workers too: retirement ends the casting, not the history, so past sessions stay attributable. Worker.app and Worker.agent run their OWN read gates and mask to null on deny (#552), so this nesting never widens what the session read admits.
memoryId String
expiresAt DateTime
repo String
branch String
prNumber Int
customerId String
language String
plan String
llmModel String
transcriptPath String #928: where the driving tool's transcript lives on 'host'.
host String #928: machine identifier the session ran on.
tool String #928: the tool driving the session ('claude-code', 'codex', ...).
inputTokens Int
outputTokens Int
turnCount Int
errorCount Int
parentSessionId String
prevSessionId String
summary String
outcome Float
outcomeRef String
outcomeMeta JSON
startedAt DateTime!
endedAt DateTime
autoExpiredAt DateTime
events [UsageEvent!]!

SlackConnection

Field Argument Type Description
id ID!
organizationId String!
defaultAppId String!
provider String! Slack provider backing this connection ('slack' today).
teamId String! Slack workspace (team) id, e.g. T0123456789.
teamName String!
botUserId String! The bot's Slack USER id (U…) — the sender on messages it posts.
botId String! The bot's BOT id (B…) — what bot message events carry. Distinct from botUserId; the bridge loop filter needs both.
status String! 'ACTIVE' or 'ERROR' (the tool's connection-status vocabulary).
lastError String
createdAt DateTime!
updatedAt DateTime!

SlackConnectionsPage

Field Argument Type Description
items [SlackConnection!]!
total Int!

StartImpersonationResult

Field Argument Type Description
session ImpersonationSession!
token String!

SummarizationRequest

Field Argument Type Description
messageCount Int!
prompt String!

TeamChatMessage

One message in a team App's chat (#939, Worker envelope since #974). Exactly one of authorUserId / authorWorkerId is set: a human post carries the user, a worker post carries the Worker (the named casting, cor:dmo:050:11) plus the driving sessionId. mentions holds the lowercased tokens extracted server-side at write time (the '@worker-name / @handle' format, stored without the '@').

Field Argument Type Description
nodeId ID! The message node's id.
seq Int! Ordering key, unique per chat, allocated atomically (ascending from 1).
body String!
at DateTime!
authorUserId ID
authorWorkerId ID
authorName String Display convenience: the worker name or the user handle.
sessionId ID The session driving the worker author, when posted via sessionRef.
replyToSeq Int The seq this message replies to, when it is a reply.
mentions [String!]!

TeamChatMessagesPage

Field Argument Type Description
items [TeamChatMessage!]!
total Int!

TeamCollectionsPayload

Result of updateTeamCollections (hadron-cli#401).

Field Argument Type Description
memoryId ID! The team App's shared memory the declaration was written to.
collections [String!]! The server-owned collections declared on it.
changed Boolean! False when the declaration already matched the canonical definition (idempotent no-op).

TeamRole

A role definition (#960): the roles:<role> node in the Team Agent's system memory, carrying the name register (data.names) and register conventions. The persona prompt template is NOT here — with the Worker model (#974) it lives on the role-agent as dressing (personaRole + personaPrompt); roleAgent points at it.

Field Argument Type Description
role String! The role slug, e.g. backend-engineer.
loc String! The node loc: roles:<role>.
nodeId ID!
description String
register [TeamRoleName!]! Ordered register = allocation order (trimmed, case-insensitive dedup, first spelling wins).
freeCount Int!
exhausted Boolean! True when no register name is free (empty registers included) — the next register-mode cast refuses WORKER_REGISTER_EXHAUSTED.
nameRange String Register convention: initial-letter range like 'F-J' (data.nameRange). Writes validate added names against it.
nameConvention String Register convention prose (data.nameConvention).
roleAgent Agent The single installed agent whose personaRole matches this role — exactly the agent a role-mode castWorker would use (null when zero or ambiguous). Runs Query.agent's own read gate and masks to null on deny (the #552 posture), like Worker.agent.
hasNamePlaceholder Boolean Whether the role-agent's personaPrompt binds {{name}} — the check that finds templates which silently produce nameless workers (role-agents authored before any guard existed). Null when no single role-agent resolves. Computed even when roleAgent itself is masked: it discloses one boolean about the caller's own App's casting default.

TeamRoleName

One entry of a role's name register (#960, cor:agt:020:02). Order is allocation order — castWorker walks the register first-to-last.

Field Argument Type Description
name String!
taken Boolean! True when a Worker holds this name in the App (case-insensitive, retired included — retirement never frees a name). Judged against the App's FULL roster server-side, which is why a client cannot compute this column.
heldBy Worker The Worker holding the name, when taken.

TeamRolesPage

Field Argument Type Description
items [TeamRole!]!
total Int!

TeamWorkItem

One team-worklog record (#947) — an externally visible work milestone (a PR opened, a branch pushed, an issue closed), append-only. The worklog is the AUTHORITATIVE PR-session join (spec cor:agt:020:03); Session.prNumber is a latest-wins display convenience. ref carries the ONE canonical spelling per artifact (github: owner/repo#N, owner/repo@sha, owner/repo:branch, owner/repo; owner/repo lowercased).

Field Argument Type Description
nodeId ID! The record node's id.
sessionId ID! The session the work is attributed to.
workerName String! Display convenience, denormalized at write: the session's bound worker name, else the attributed user's handle (pre-#974 records surface their stored personaName here).
workerId ID The Worker (named casting) behind the record, when the session was worker-bound.
tool String! The external tool the artifact lives in ('github', ...). Lowercased.
kind String! Artifact kind: pr, issue, commit, branch, or repo.
ref String! The canonical artifact ref — the equality-lookup key.
action String! What happened: opened, merged, claimed, reviewed, closed, pushed, ... (free string, lowercased).
at DateTime! When the record was made (server-stamped).
detail JSON Optional display extras (title, URL) — never filtered on.

TeamWorkItemsPage

Field Argument Type Description
items [TeamWorkItem!]!
total Int!

UninstallAgentFromAppPayload

Return shape for the uninstallAgentFromApp mutation. The Agent's per-(App, Agent, *) memories are NOT cascade-deleted (spec 023 FR-005); they persist as orphans on the now-removed AppAgent edge.

Field Argument Type Description
appId ID!
agentId ID!

UpdateMemoryMemberRolePayload

Field Argument Type Description
memoryMember MemoryMember!

UpdateMemoryShareRolePayload

Field Argument Type Description
memoryShare MemoryShare!

UrnResolution

Result of resolving a Hadron URN to the ids a client needs to navigate to the resource's canonical page. Powers the portal's /app/u/<urn> redirect route (hadron-portal#262).

kind is the URN's type segment: memory | node | agent | org | app | user | apprun | worker | noderev. id is the resolved entity's primary id. memoryId is set only for nodes (their owning memory), organizationId for apps, app runs, and workers (their owning org) — both are the extra ids those resources' canonical routes require.

Field Argument Type Description
kind String!
id ID!
memoryId ID
organizationId ID
fragment String Set to 'data' when the resolved URN named a #data fragment of its parent node/apprun (#696); null otherwise.

UsageActivityBucket

One time bucket of read+write activity (#796).

Field Argument Type Description
date String! Bucket start as YYYY-MM-DD, in the requested timeZone. Deliberately String and NOT DateTime (#205): it is a calendar-day label in the caller's zone, not an instant — rendering it as a UTC timestamp would shift buckets across the date line.
reads Int!
writes Int!

UsageEvent

Field Argument Type Description
id ID!
type String!
nodeLoc String
memoryId String Memory the event is attributed to (#796). Stored at write time, so it outlives the node — null only for events written before the backfill whose node was already deleted, or paths with no memory in scope.
actionArgs JSON
appId String
sessionId String
model String
tokensIn Int
tokensOut Int
userId String
organizationId String
provider String
keyOwnerType String
costMicroCents String
createdAt DateTime!

UsageSummaryEntry

Field Argument Type Description
nodeLoc String!
type String!
count Int!

User

Field Argument Type Description
id ID!
handle String
policy JSON User-layer action-policy link (cor:acl:040:02, #510) — constrains runs made on the user's behalf. Null = no restriction. Self-authored via updateMyPolicy.
urn String
githubId Int
githubUsername String
googleId String Google account subject id (#837). Opaque provider identifier, never an address. Withheld (null) from a viewer who is not the user themselves, a platform admin, or a co-member of one of their orgs — the same #384 gate that name/email use. Load-bearing for duplicate-account triage: mergeUsers adopts a source provider id only where the target column is null, and identityProvider records only which provider CREATED the row, so it cannot be used to infer this (a GITHUB row may carry a linked googleId).
appleId String Apple account subject id (#837). Same gate and rationale as googleId.
identityProvider String
externalId String
externalAppId String
linkedAt DateTime
name String
email String
avatarUrl String
roles [Role!]!
maxReferrals Int
appMemberships [AppMember!]!

UserApiKey

Field Argument Type Description
id ID!
keyPreview String!
label String
createdAt DateTime!
lastUsedAt DateTime
revokedAt DateTime
issuedVia String

UserApiKeyCreateResult

Field Argument Type Description
userApiKey UserApiKey!
rawKey String!

UserInvitation

Field Argument Type Description
id ID!
slug String!
senderUserId String
sender User
organizationId String
organization Organization
memberRole Role!
name String
email String
githubUsername String
maxActivations Int
expiresAt DateTime
acceptedAt DateTime
createdAt DateTime!
activationCount Int!

UsersPage

Field Argument Type Description
items [User!]!
total Int!

Worker

A Worker (#974, cor:dmo:050:11) — the named casting of an installed Agent into an App: 'Iris', the backend-engineer agent cast into the eng-team App. The Agent carries the reusable persona dressing; the Worker is the local named identity that does attributable work. Names are unique per App, case-insensitively, forever (retirement and uninstall never free them — cor:agt:020:02); rows survive the agent's uninstall. A Worker is addressable by its id or by the computed urn below (#991).

Field Argument Type Description
id ID!
appId ID!
agentId ID!
name String! The worker's name ('Iris') — the identity every surface renders.
slug String! The URN atom, derived from the name at cast time and permanent thereafter (#991). Lowercased, sanitized to the URN slug charset, and iterated ('iris', 'iris-2', …) until free within the App — so deriving it NEVER refuses a cast, and the name collision stays the only allocation failure a caller sees (cor:agt:020:02).
urn String hrn:worker:<root>:<app-slug>:<slug> (#991) — computed from the App's URN plus `slug`, not stored. Accepted anywhere a workerRef is taken, and resolvable via Query.resolveUrn, so a client can address a worker without holding its id. Null only when the App's URN predates the flat grammar-v2 shape this arity requires.
role String The cast-list role this filling answers ('backend-engineer').
promptOverride String Per-worker individuality layered over the agent's template prompt.
memoryId ID The worker-scoped working memory in the App's container (null until provisioned).
agent Agent The role-agent behind the casting.
app App The App whose staff this casting fills.
prompt String The worker's boot prompt, resolved: the agent's personaPrompt template with {{name}}/{{role}} bound, then promptOverride appended as its own paragraph. Null when the agent carries no template and the worker no override.
createdAt DateTime!
createdBy String
retiredAt DateTime Retirement instant — a retired worker stops authoring and takes no new sessions; the name stays reserved.
retiredBy String

WorkersPage

Field Argument Type Description
items [Worker!]!
total Int!

Inputs

AgentFilter

Filter for the uniform agents() list (#473). Clauses AND-combine.

Field Type Description
type AgentType
visibility AgentVisibility
ownedByMe Boolean #782 — true restricts the list to the caller's OWN user-owned (org-less) agents: organizationId IS NULL AND ownerUserId = the caller. For ALL callers INCLUDING platform ADMIN/OWNER (owner scope is never an admin-bypass surface), mirroring the owner-only personal/private memories slice. Org-less by definition, so orgId is not consulted. App-key callers (no user context) get an empty page. Powers the portal's "My agents".

AiServiceConfigFilter

Filter for the uniform aiServiceConfigs() list (#473) — the owning entity. Omitted entirely, the list is the platform ADMIN/OWNER's cross-owner view of every config; non-admin callers MUST filter by owner (org ADMIN of the owning org, mirroring the management-surface gate).

Field Type Description
ownerType AiConfigOwnerType!
ownerId ID! The owning entity — accepts ID or URN (HADRON_SERVER: ID only).

AppFilter

Filter for the uniform apps() list (#473). Clauses AND-combine.

Field Type Description
ownedByMe Boolean #782 — true restricts the list to the caller's OWN user-owned (org-less) apps: organizationId IS NULL AND ownerUserId = the caller. For ALL callers INCLUDING platform ADMIN/OWNER (owner scope is never an admin-bypass surface), mirroring the owner-only personal/private memories slice. Org-less by definition, so orgId is not consulted. App-key callers (no user context) get an empty page. Powers the portal's "My apps".

AssetFilter

Filter for the cross-memory assets() list. Every field narrows the caller's accessible set; none of them widens it.

Field Type Description
memoryRefs [ID!] Narrow to these memories (id or fully-qualified URN). Unreadable and unknown refs are silently dropped; a malformed URN is an error. An explicitly EMPTY list is the empty scope, never a fallback to the default scope.
mine Boolean Only the caller's own uploads. Never widens the gate.
mimeType String
scanStatus AssetScanStatus
includeDeleted Boolean

BeginAssetUploadInput

Field Type Description
agentUrn String! Accepts the entity's ID or URN.
filename String!
mimeType String!
sizeBytes Int!
description String
uploadIntent UploadIntent!
uploadRequestId String

BeginAssetUploadV2Input

Field Type Description
memoryId ID! Memory reference. Accepts the entity's ID (CUID / 32-char hex) or its URN (per spec 007 ID-or-URN dispatch). URN inputs MUST be fully qualified (org:memory) per spec 022 — relative-form URNs are rejected as GraphQL errors with extensions.code "URN_NOT_QUALIFIED".
filename String!
mimeType String!
sizeBytes Int!
description String
uploadIntent UploadIntent!
uploadRequestId String

CalendarEventTimeInput

An event boundary for create/update: exactly one of dateTime (timed) or date (YYYY-MM-DD, all-day). A dateTime needs timeZone unless it carries its own UTC offset — a zone-less value is rejected, never guessed.

Field Type Description
dateTime String
date String
timeZone String

CompleteAssetUploadInput

Field Type Description
uploadId ID!

CreateAgentScheduleInput

Field Type Description
appRef String! App the run executes as — ref: PK or fully-qualified URN.
name String!
cron String Recurring: 5-field cron expression, evaluated in timezone (default UTC). Provide exactly one of cron / runAt.
runAt String One-shot: run once at this ISO-8601 instant (#510). Provide exactly one of cron / runAt.
timezone String
entryNodeUrn String! Fully-qualified URN of the prompt node to run (D-2026-05-09-012/017).
agentRef String Agent — ref: PK or URN; must be installed in the App.
runAsSelf Boolean true: the run acts on behalf of YOU (required to reach your personal memories). v1 never delegates a third party (cor:agt:010:01).
eventData JSON Static payload merged into each run's template args.
policy JSON Trigger-layer allow-list { allow: [...] } — one link of the conjunctive chain (cor:acl:040).
aiConfigName String Named AI config for this trigger (spec-036 walk override).
enabled Boolean

CreateAgentWebhookInput

Field Type Description
appRef String! App — ref: PK or fully-qualified URN.
name String! Lowercase alphanumeric/dash, 1-64 chars — part of the URL.
entryNodeUrn String!
agentRef String Agent — ref: PK or URN; must be installed in the App.
runAsSelf Boolean
argsSchema JSON JSON Schema for POST args (stored in v1; enforcement is follow-on).
eventData JSON
policy JSON
aiConfigName String
enabled Boolean

CreateAssetReferenceNodeInput

Attach an existing asset to the graph by creating a reference node that points at it.

The node is a nodeType: reference node whose data.asset carries the asset's id, urn, filename, mimeType and sizeBytes — the same shape hadron_store_file writes for run-created files, so a reader handles both origins identically. There is no schema-level Asset-to-Node link (cor:dmo:060:10 reserves it); the pointer is a soft reference, and Node.asset resolves to null once the asset is gone.

Requires READ access to the asset's holding memory and WRITE access to the memory the reference node lands in — which need not be the same memory.

Field Type Description
assetRef String! Asset id, or its URN — canonically hrn:asset:<root>:<mem...>:assets:<asset.id>. Parsing is Postel-liberal (assetIdFromRef): the id is whatever follows the LAST 'assets' atom, so every shape Asset.urn can emit is accepted, including the pre-#697 memory-prefixed <memory.urn>:assets:<asset.id> spelling and the other degraded fallback. A ref with no 'assets' atom is taken as a bare id.
nodeUrn String! Fully-qualified node URN for the reference node.
name String Node name. Defaults to the asset's filename.
description String Node description. Defaults to the asset's own description.

CreateNodeInput

Input for createNode. 'memoryId', 'loc', and 'name' are required; creating is create-only — a live node at (memoryId, loc) rejects with NodeLocConflictError (spec 039 Phase 0 D1/D4).

Field Type Description
id String Forced PK (importer/sync use case, e.g. a stable UUIDv7). Only ever a create-id here — never a selector (D2). Omit to mint.
memoryId String! Memory reference. Accepts the entity's ID (CUID / 32-char hex) or its URN (per spec 007 ID-or-URN dispatch). URN inputs MUST be fully qualified (org:memory) per spec 022 — relative-form URNs are rejected as GraphQL errors with extensions.code "URN_NOT_QUALIFIED".
loc String!
name String!
nodeType String
objectType String #725 — collection discriminator (e.g. "competitor" / "insight"). NULL for an ordinary node.
isRunnable Boolean Whether this node can be run as a task by hadron_run_task (cor:api:060).
alias String
description String
abstract String Paragraph-length summary of this node — see Node.abstract for the surfacing contract. Optional. Empty + whitespace-only normalize to null. Cap is 2000 characters.
content String
contentType String MIME type of content (#476/#488, spec cor:cnv:010:01): 'text/markdown' (default) stores as-is; 'text/html' converts captured DOM to Markdown; 'application/pdf' extracts a PDF's text layer to Markdown (send 'content' as raw base64 — a PDF is binary; scanned/image-only PDFs error). The conversion runs before storage and fills properties.title from the extracted title when not supplied. Consumed at write time — never persisted. Any other value is rejected.
seq Int
tags [String!]
properties JSON
data JSON
ownerRepo String
llmModel String
aiAgent String
edges [NodeEdgeInput!] Outgoing edges to create with the node.
reason String Recorded on revision history only when a soft-deleted node is resurrected (a pure create snapshots nothing).

DashboardWidgetInput

One widget in a setDashboardWidgets selection; grid position is the array order.

Field Type Description
id ID When set and owned by the caller, update that placement in place (id survives the save); otherwise create a new one (#788).
type DashboardWidgetType!
span Int! Columns to span (1-12) on the 12-col grid; clamped server-side.
rowSpan Int! Rows to span (1-4); clamped server-side (#788).
config JSON Widget-instance settings; shape is widget-defined (#788).

EdgeFilter

Filter for the uniform edges() list (#473). Clauses AND-combine and are intersected with the caller's readable memories. memoryId / sourceNodeId / targetNodeId each accept an ID or a fully-qualified URN; an unresolvable ref yields an empty page (consistent with the no-disclosure posture).

Field Type Description
memoryId ID Confine to edges whose (denormalized, source-side) memory is this one.
sourceNodeId ID Edges leaving this node.
targetNodeId ID Edges arriving at this node.
isRunnable Boolean
includeDeleted Boolean Include soft-deleted edges (default false).

EdgeInput

Field Type Description
sourceLoc String!
targetLoc String!
name String Relationship name (was 'label'). Optional — loc is the identity.
loc String Explicit edge loc. Omit to derive <sourceLoc>:<name>:<targetLoc>.
description String
isRunnable Boolean

GrantCreditsInput

Field Type Description
orgRef String!
amountMicroCents String!
expiresAt String
sourceType String
sourceId String
note String

ImpersonationSessionFilter

Field Type Description
activeOnly Boolean

ImportNodeInput

Input for importNode (#457). Target: 'nodeUrn' XOR ('memoryId' + 'loc') — the URN may name a not-yet-existing node (import creates it). Source: exactly one of 'url' | 'content'.

Field Type Description
memoryId String Target memory (ID or fully-qualified URN), with 'loc'. XOR with 'nodeUrn'.
loc String Target loc within 'memoryId'. XOR with 'nodeUrn'.
nodeUrn String Fully-qualified node URN naming the target (existing or new). XOR with memoryId+loc.
url String Source URL (http/https) — fetched server-side, SSRF-guarded, WITHOUT user credentials.
content String Inline source content (e.g. the Web Clipper's authenticated-DOM capture). XOR with 'url'.
contentType String MIME type of 'content': text/html (DEFAULT here — unlike createNode) converts to Markdown at the write seam; text/markdown stores as-is; application/pdf extracts a PDF's text layer to Markdown ('content' must be raw base64 — a PDF is binary; scanned/image-only PDFs error). Ignored on the url path (always HTML).
name String Display name. Default: the extracted page/article/document title; on a re-import of an existing node the current name is preserved; a fresh create without either falls back to the loc leaf.
nodeType String Default 'webpage' (or 'info' when contentType is application/pdf).
properties JSON Merged provenance metadata; the server sets properties.url on the url path when absent (properties.title is filled from the extracted title by the write seam).
taskRef ID Task node to run against the imported node once stored (#528) — PK or fully-qualified URN. Presence triggers a MANUAL app run; the result envelope is FETCH_PENDING + jobId (poll appRun(ref:)). The imported node's URN is passed to the task as eventData.importedNodeUrn.
taskArgs JSON Extra template args merged into the task run's eventData (only meaningful with taskRef).
appRef ID App to run the task under — PK or URN. Falls back to the caller's active App. Only meaningful with taskRef.

MemoryFilter

Filter for the uniform memories() list (#473). All clauses AND-combine and only ever narrow the caller's accessible scope — with two documented slice SELECTIONS, each switching which readable set the list draws from (never widening access beyond what the caller may already read): - visibility: PUBLIC switches from the caller's own union (org-owned + org-subscribed + own personal/private) to the public marketplace slice (every PUBLIC memory — the old publicMemories query). - sharedWithMe: true switches to the memories shared WITH the caller via MemoryShare (the caller is a grantee) — the portal's Memories-shared-with-me tab.

Field Type Description
memoryClasses [MemoryClass!] Restrict to exactly these classes. Omitted, the noisy agent system class is hidden by default; pass it explicitly to surface system memories.
visibility MemoryVisibility Restrict by visibility. PUBLIC selects the marketplace slice (see above).
sharedWithMe Boolean true selects the distinct set of memories shared WITH the caller via MemoryShare (the caller is a grantee) — the portal's Memories-shared-with-me tab. This is its own slice, NOT part of the caller's owned/org union: a grantee is never their own grantor, so it excludes owned memories. App-key callers get an empty page (sharing is a user-to-user concept). See Memory.myShare for the per-row grantor + role.

MergeMemoriesInput

Field Type Description
source String! Source memory — ID or fully-qualified URN. Emptied into 'target'.
target String! Target memory — ID or fully-qualified URN. The surviving memory.
include [NodeMergeField!] Field strategy for source nodes whose loc collides with an existing target node (folded via the mergeNodes rules). Omit (or null) = every mergeable field. Nodes with no target counterpart move over unchanged (loc preserved).
deleteSourceMem Boolean Delete the (now-empty) source memory after a successful merge.

MergeNodesInput

Field Type Description
source String! Source node — ID or fully-qualified URN. Folded into 'target'.
target String! Target node — ID or fully-qualified URN. The surviving node.
include [NodeMergeField!] Fields to merge. Omit (or null) to merge every mergeable field.
deleteSource Boolean Hard-delete the source node after a successful merge.

MergeUsersInput

Field Type Description
source String! Source user — ID, bare handle, or fully-qualified user URN. Folded into 'target' and soft-deleted.
target String! Target user — ID, bare handle, or fully-qualified user URN. The surviving user; target wins non-combinable conflicts while roles preserve the strongest live entitlement.

MintActionTicketsInput

Field Type Description
orgRef String! Organization — ref: PK or URN.
appRef String Scope tickets to one App (ref: PK or URN); omit for org-wide.
action String! v1: comm.outbound only.
count Int!
note String Ledger legibility — why these tickets exist.
expiresAt String

NodeEdgeInput

Field Type Description
targetId String! Reference to the target node. Accepts a node ID, a full URN (hrn:node:<memory-urn>:<loc>), a memory-prefixed loc (<memory-urn>:<loc>), or a short loc resolved within the source node's memory.
name String Relationship name (was 'label'). Optional — loc is the identity.
loc String Explicit edge loc. Omit to derive <sourceLoc>:<name>:<targetLoc>.
description String
isRunnable Boolean

NodeFilter

Structured, unscored, AND-combined filter context for findNodes (cor:api:090:02).

Field Type Description
memoryIds [ID!] Memory scope — a mix of memory IDs and fully-qualified URNs; intersected with the caller's access.
memoryClasses [MemoryClass!] Restrict by memory class. SYSTEM is excluded by default; passing this (or naming a system memory in memoryIds) overrides that.
nodeType String
objectType String #725 — collection facet: only nodes whose objectType equals this (e.g. "competitor").
tags [String!]
isRunnable Boolean
locPrefix String
createdBy String
updatedAfter String
updatedBefore String
includeDeleted Boolean Include soft-deleted nodes (default false).
where NodeWhereInput Structured predicate over the node's properties/data JSONB (#719).

NodeInput

Bulk-import node shape, used only by replaceSubtree (git-sync). Single-node writes use CreateNodeInput / UpdateNodeInput (spec 039 Phase 0 D1).

Field Type Description
id String Forced PK (importer-supplied UUIDv7 from node.yaml, stable across moves). Omit to mint.
memoryId String! Memory reference. Accepts the entity's ID (CUID / 32-char hex) or its URN (per spec 007 ID-or-URN dispatch). URN inputs MUST be fully qualified (org:memory) per spec 022 — relative-form URNs are rejected as GraphQL errors with extensions.code "URN_NOT_QUALIFIED".
nodeType String
objectType String #725 — collection discriminator (e.g. "competitor" / "insight"). NULL for an ordinary node.
isRunnable Boolean Whether this node can be run as a task by hadron_run_task (cor:api:060).
loc String!
name String!
alias String
description String
abstract String Paragraph-length summary of this node — see Node.abstract for the surfacing contract (hadron_get_node opt-in via contentScope; hadron_find_nodes preview ships in US2). Optional. Omit to preserve; null to clear; string to replace. Empty + whitespace-only normalize to null. Cap is 2000 characters.
content String
seq Int
tags [String!]
properties JSON
data JSON
ownerRepo String
llmModel String
aiAgent String
edges [NodeEdgeInput!]
reason String Why this change was made — recorded on the revision-history snapshot (NodeRevision.revLabel, #620; historically it squatted in editedBy), mirroring hadron_update_node's reason arg so CLI and MCP edits leave equally-traceable history. Only an update snapshots a prior revision, so reason has no effect on a pure create.

NodePropertySort

Order findNodes by the value at a properties/data JSON path (#719).

Reuses the NodeWhere leaf addressing: path into field (properties|data), typed by as (text|number|datetime|boolean). number/datetime route through the same DB guards, so a missing or unparseable value sorts LAST regardless of direction; loc ascending breaks ties for stable pagination. Overrides the sort enum when present. On vector/hybrid modes it re-orders the retrieved candidate window (the ranking runs against the vector index, not the JSONB), like the sort enum does.

Field Type Description
path [String!]! Path of object keys into the column, e.g. ['stage'].
field NodeWhereColumn JSONB column (default properties).
as NodeWhereCast Value typing before comparison (default text).
direction SortDirection Direction (default asc).

NodeWhereInput

A recursive structured predicate over a node's properties/data JSONB (#719).

A node is EITHER a branch (exactly one of and/or/not) OR a leaf (a path plus exactly one operator). Leaf values are JSON scalars, bound as parameters; path segments are identifier-validated. datetime/number comparisons route through DB guard functions so unparseable data drops the row (never a 500). Bounded: depth ≤ 4, ≤ 32 leaves, path ≤ 8 segments — a malformed/oversized tree is BAD_USER_INPUT. Composes with every mode (keyword/regex/vector/hybrid) and the no-query browse: for lexical modes + browse the predicate is applied in-query; for vector/hybrid it post-filters the ranked candidate set (rank order preserved).

Field Type Description
and [NodeWhereInput!]
or [NodeWhereInput!]
not NodeWhereInput
field NodeWhereColumn JSONB column (default properties).
path [String!] Path of object keys into the column, e.g. ['capturedAt'].
as NodeWhereCast Value typing for the comparison (default text).
eq JSON
ne JSON
in [JSON!]
lt JSON
lte JSON
gt JSON
gte JSON
between [JSON!]
exists Boolean
contains JSON jsonb containment (@>) of the JSON value at the path.

OrganizationFilter

Filter for the uniform organizations() list (#473).

Field Type Description
memberOnly Boolean true restricts the list to the caller's own memberships — even for platform ADMIN/OWNER, whose unscoped reach otherwise spans every live org; the old myOrganizations semantics.

PublicAgentFilter

Filter for the publicAgents() marketplace slice (#551). ONLY 'type' narrows. Deliberately a SEPARATE, narrower input from AgentFilter: the slice is PUBLIC by definition (so 'visibility' is meaningless) and a PUBLIC agent is never user-owned (user-owned agents are strictly PERSONAL, spec 047), so an 'ownedByMe' here would always be empty — rejecting it at the schema keeps a client from applying the filter uniformly and silently getting cross-org marketplace agents (#782 Codex review).

Field Type Description
type AgentType

SearchReplaceInNodesInput

Bulk literal/regex search-and-replace across selected nodes.

Selection is a union — at least one of 'nodeIds' or 'memoryIds' is required: - nodeIds: explicit nodes (IDs or fully-qualified URNs). - memoryIds: every live node in those memories (IDs or URNs). - prefix: further restrict the memoryIds set to the node at 'prefix' plus its descendants, matched on colon loc-path boundaries (so 'auth' matches 'auth' and 'auth:tokens' but not 'authoring'). Requires 'memoryIds' — loc is only unique within a memory.

Matching is literal substring by default; set 'regex: true' to treat 'oldText' as a RegExp source (and 'newText' as a replacement pattern with dollar-sign backrefs). 'caseInsensitive' toggles case folding. Matching is always global.

Set 'dryRun: true' to get per-node/per-field match counts WITHOUT writing.

Field Type Description
oldText String! Text (literal) or RegExp source (regex mode) to find. Must be non-empty.
newText String! Replacement. May be empty (deletes the matched text). Regex mode honors dollar-sign backrefs.
nodeIds [ID!] Explicit node IDs or fully-qualified URNs.
memoryIds [ID!] Memory IDs or URNs — selects every live node in each.
prefix String Loc-prefix filter applied within 'memoryIds' (parent loc + descendants).
fields [NodeTextField!]! Which text fields to search. At least one required.
caseInsensitive Boolean
regex Boolean Treat oldText as a RegExp source and newText as a replacement pattern.
dryRun Boolean When true, report matches without writing anything.
reason String Why this change was made — recorded on each changed node's revision-history snapshot (NodeRevision.revLabel, #620; historically it squatted in editedBy), mirroring hadron_update_node's reason arg.

SessionInput

Field Type Description
id String!
type String
repo String
branch String
prNumber Int
customerId String
language String
llmModel String
parentSessionId String
prevSessionId String
transcriptPath String
host String
tool String
agentRef String #928 / cor:api:140: the role-Agent driving this session, as a PK or URN. Resolves to Session.agentId. The caller must be able to READ the agent (PUBLIC, or owner / org member) - a session is never attributed to an agent the caller cannot see. Usually omitted with workerRef, which derives it from the casting.
workerRef String #974 / cor:agt:020:03: the Worker (named casting) this session works as. Three forms resolve, told apart by SHAPE (never by trying each in turn, so a typo'd URN can't silently fall through to a roster search): - the worker's NAME ("Iris") — #990. Unique per App, case-insensitively, matched with the DATABASE's lower(), the expression workers_app_name_uniq indexes. Requires App context (appRef, an App-key credential, or an MCP active-App selection): a name means nothing without one, so a nameless-App call refuses SESSION_WORKER_NAME_NEEDS_APP rather than guessing across the caller's Apps. Gated on the STAFF READ GATE before the lookup runs — resolving a name discloses roster membership, which the id/URN forms never do. Which refusal you get depends on WHERE the denial happens, and clients should not assume one code covers both: a caller who supplied appRef has already been checked against the same participant predicate, so an outsider is refused FORBIDDEN there, before any name is read. Only a denial at the in-branch staff gate — reachable when the App came from an App-key credential rather than appRef — is masked as WORKER_NOT_FOUND, indistinguishable from an App with no such worker. - the worker's URN (hrn:worker:<root>:<app-slug>:<slug>, #991); the URN's leaf is the derived slug, never the display name (cor:agt:020:02). - the worker's id. Resolves to Session.workerId, and stamps Session.agentId with the worker's role-agent. The worker must belong to the session's App: with appRef (or an App-key credential) it must match the worker's App; without one, the worker's App becomes the session's, behind the same membership gate as appRef. A retired worker refuses (WORKER_RETIRED). #940: a worker with an ACTIVE session refuses WORKER_TAKEN — extensions carry workerId, sessionId, lastDriver, lastSeenAt, everything the takeover prompt needs — unless force is true (informed takeover, cor:agt:020:03: show who last drove it, proceed only on explicit override, never silently).
force Boolean #940: take over a worker whose binding would otherwise refuse WORKER_TAKEN. Only meaningful with workerRef. Clients must surface the WORKER_TAKEN payload (who last drove it, when) before retrying with force - that IS the informed-takeover contract; force exists so the override is explicit, never the default.
plan String The session's stated intent (Session.plan) - what this session is about. MCP's hadron_start_session description lands here.
appRef String #943 / cor:api:140: the App this session is a unit of work for, as a PK or URN. Resolves to Session.appId - the pivot that was previously stamped ONLY from an App-key credential, which made a user-started session structurally unable to satisfy the team-chat authorship gate (cor:agt:020:04 condition b, SESSION_NOT_IN_APP). The caller must be a member of that App: an AppMember at any role, an org member with CONTRIBUTOR+ on its owning org, or the owner of a user-owned App. Unknown or deleted App: BAD_USER_INPUT; non-member: FORBIDDEN. An App-key credential wins - if the caller authenticated as an App and appRef names a DIFFERENT App, the call is refused (SESSION_APP_MISMATCH). Uninstalled Apps differ by ref form, because App URNs are only unique among ACTIVE rows (spec 021 FR-027: one live App plus N uninstalled history rows may share a URN). By URN an uninstalled App is simply not found - BAD_USER_INPUT - since there is no single row the URN names; by PK it is found and refused APP_UNINSTALLED.

SetAgentAssetUploadEnabledInput

Field Type Description
agentUrn String! Agent reference. Accepts the entity's ID (CUID / 32-char hex) or its URN (per spec 007 ID-or-URN dispatch). URN inputs MUST be fully qualified (org:agent) per spec 022 — relative-form URNs are rejected as GraphQL errors with extensions.code "URN_NOT_QUALIFIED".
enabled Boolean!

SetAiModelPriceInput

Field Type Description
provider String!
model String!
tier Int
inputMicroCentsPerMTok String!
outputMicroCentsPerMTok String!
markupBasisPoints Int
effectiveAt String

SetQuotaLimitInput

Field Type Description
orgRef String! Org - ref: PK or URN.
appRef String Optional app scope - ref: PK or URN; must belong to the org. Omit to set the org-level limit.
action String! run.execute, llm.tokens, sms.send, or email.send.
limit Int! Non-negative integer; 0 pauses the scope (every launch denies QUOTA_EXCEEDED).

TriggerAppRunInput

Field Type Description
appRef String! App — ref: PK or fully-qualified URN.
entryNodeUrn String!
eventData JSON
runAsSelf Boolean
aiConfigName String

UpdateAgentScheduleInput

Field Type Description
name String
cron String Providing cron switches the schedule to recurring (clears runAt).
runAt String Providing runAt switches the schedule to one-shot (clears cron). At most one of cron / runAt per call.
timezone String
entryNodeUrn String
agentRef String Agent — ref: PK or URN; must be installed in the App.
runAsSelf Boolean
eventData JSON
policy JSON
aiConfigName String
enabled Boolean

UpdateNodeInput

Input for updateNode. Identify the target by 'id' (PK or fully-qualified node URN) XOR ('memoryId' + 'loc') — both selectors, or neither, is an error (spec 039 Phase 0 D2). updateNode never creates and never moves (D3). Every content field is optional: omitted = preserved (D4).

Field Type Description
id String The node to change: PK (CUID / 32-char hex) or fully-qualified node URN (hrn:node:<root>:<memory>:<loc>). XOR with memoryId+loc.
memoryId String Selector, with 'loc': the target's memory (ID or fully-qualified URN). XOR with 'id'.
loc String Selector, with 'memoryId': the target's current loc. Not writable here — moveNode relocates.
name String Omit to preserve (D4).
nodeType String
objectType String #725 — collection discriminator (e.g. "competitor"). Omit to preserve; null to clear.
isRunnable Boolean Whether this node can be run as a task by hadron_run_task (cor:api:060). Omit to preserve.
alias String
description String
abstract String Paragraph-length summary of this node — see Node.abstract for the surfacing contract. Omit to preserve; null to clear; string to replace. Empty + whitespace-only normalize to null. Cap is 2000 characters.
content String
contentType String MIME type of content (#476/#488, spec cor:cnv:010:01): 'text/markdown' (default) stores as-is; 'text/html' converts captured DOM to Markdown; 'application/pdf' extracts a PDF's text layer to Markdown (send 'content' as raw base64 — a PDF is binary; scanned/image-only PDFs error). The conversion runs before storage and fills properties.title from the extracted title when not supplied. Consumed at write time — never persisted. Any other value is rejected.
seq Int
tags [String!] Omit to preserve existing tags (issue #235); supply to replace the set.
properties JSON
data JSON
ownerRepo String
llmModel String
aiAgent String
edges [NodeEdgeInput!]
reason String Why this change was made — recorded on the revision-history snapshot (NodeRevision.revLabel, #620; historically it squatted in editedBy), mirroring hadron_update_node's reason arg so CLI and MCP edits leave equally-traceable history.

UsageEventInput

Field Type Description
type String!
nodeLoc String
actionArgs JSON
sessionId String
model String
tokensIn Int
tokensOut Int

UserFilter

Filter for the uniform users() list (#473). For a non-platform-admin caller 'query' is REQUIRED (a blank/omitted query returns an empty page) and matching is enumeration-safe per cor:acl:070:02: public identifiers (handle, githubUsername) match by substring, email by exact equality, and name only where the viewer may see it (self/admin/co-member). Platform ADMIN/OWNER may omit 'query' for the full user list.

Field Type Description
query String

Enums

AccessSource

issue #323: where a single grant in an EffectiveAccess result comes from.

Value Description
PLATFORM_ROLE Platform ADMIN/OWNER.
ORG_ROLE ADMIN/OWNER (or, for org-readable knowledge, any Role) of the owning org.
MEMORY_PRINCIPAL personal/private memory owner (Memory.userId).
MEMORY_MEMBER group-class team membership row (MemoryMember).
MEMORY_SHARE personal-class cross-user grant (MemoryShare).
PRINCIPAL_GRANT individual action grant (PrincipalGrant, cor:acl:040:06) - clone/delete capabilities on top of the role bundle.
NODE_INHERITED node inherits its memory's access.
APP_MEMBER AppMember row.
AGENT_SUBSCRIPTION active AgentSubscription, or an org-level AgentOrgGrant the user inherits.
AICONFIG_OWNER admin of the AI config's owning entity.
PUBLIC_VISIBILITY resource is publicly / universally visible.

AgentType

Value Description
ASSISTANT
CHATBOT

AgentVisibility

035-visibility-enum-cleanup: agents have their own visibility enum, decoupled from MemoryVisibility. PERSONAL is the creator-only draft state.

Value Description
PUBLIC
ORGANIZATION
PERSONAL

AiConfigOwnerType

036-ai-service-config: which entity owns an AiServiceConfig. Exactly one owner per config (DB-enforced).

Value Description
HADRON_SERVER
ORGANIZATION
APP
AGENT

AppMembershipRole

Value Description
OWNER
ADMIN
CONTRIBUTOR
READER

AppMemoryKind

Value Description
shared
user
none

AppRunSortField

Orderable columns on the appRuns list (#833). Reuses the shared SortDirection enum. Default createdAt desc — existing callers depend on newest-first.

startedAt / finishedAt are NULLABLE (a PENDING run has neither); nulls sort LAST in both directions, so unstarted runs never crowd out the rows an operator asked to see. Every sort carries an id tiebreak so offset paging is deterministic.

Duration (finishedAt - startedAt) is deliberately absent: it has no stored column and Prisma cannot order by a computed expression, so it needs a generated column of its own - tracked separately rather than half-shipped.

Value Description
createdAt
startedAt
finishedAt
status

AppRunStatus

Value Description
PENDING
RUNNING
COMPLETED
FAILED
TIMED_OUT
CANCELLED

AppRunTriggerKind

Value Description
SCHEDULE
WEBHOOK
MANUAL
INTEGRATION
SPAWN

AppType

Value Description
WORKSTATION
CHATBOT
AGENT
AUTOMATION
CLOUD
IOT

AssetScanStatus

Value Description
PENDING
CLEAN
BLOCKED

CalendarEventResponse

Provider-neutral attendee response. NONE = invited, not yet answered.

Value Description
ACCEPTED
DECLINED
TENTATIVE
NONE

ChatScope

Value Description
private
shared

CreateUserPermission

Value Description
DENY
EXPLICIT
IMPLICIT

DashboardWidgetType

772 — the kinds of widget placeable on a user's /app/dashboard grid.

Value Description
MEMORY_STATS
AGENT_STATS
USAGE_ACTIVITY

DriveExportFormat

Text representation a drive export can request.

Value Description
MARKDOWN
TEXT
HTML

DriveFileKind

Provider-neutral file kind (native document types vs plain files).

Value Description
FOLDER
DOCUMENT
SPREADSHEET
PRESENTATION
FILE

EmailFlag

Value Description
FLAGGED
NONE
COMPLETE

EmbeddingSource

Value Description
abstract
contentChunks
both

FindNodesMode

Retrieval modes for findNodes (cor:api:090:01). keyword is stemmed FTS; vector/hybrid need the memory's vector index; regex is a POSIX pattern match.

Value Description
keyword
vector
hybrid
regex

IdentifyUserMethod

Value Description
USER_ID
SECRET

ImportNodeStatus

importNode outcome. Sync v1 always returns STORED with the stored node; FETCH_PENDING + jobId are RESERVED for the future async url path (same API shape, no breaking change when it lands).

Value Description
STORED
FETCH_PENDING

MemoryClass

Value Description
system
app
knowledge
personal
group 023-app-shape US4: team-shared memory with symmetric membership. Governed by a list of MemoryMember rows (each with reader/writer/ owner role) — no single owner field on Memory. Closes the Company Brain gap that wasn't covered by the four legacy classes.
private Single-owner, owner-only memory — no MemoryShare path (not shareable), no ADMIN/OWNER bypass. Spec 034 (hadron-server #242) made it user-creatable via createMemory: free-standing (no app/agent) or app-scoped. May opt into encrypt-at-rest (the private CLASS marks it; visibility is NULL), but the encryption implementation itself is a deferred follow-up — do NOT rely on at-rest encryption for secret material yet.

MemoryMemberRole

023-app-shape US4: role on a MemoryMember row. Symmetric team membership for group-class memory. - reader: read access. - writer: read + write (the member can add/edit/delete nodes within the memory). - owner: read + write + management — add/remove other members, change roles, delete the Memory itself. Subject to the last-owner protection rule (FR-038): the platform refuses to remove or demote the sole remaining owner; the path to fully empty a group memory is to delete it.

Value Description
reader
writer
owner

MemoryShareRole

023-app-shape US3: role on a MemoryShare row. Asymmetric grant for personal-class memory. - reader: read access only. - writer: read + write (the grantee can add/edit/delete nodes within the memory).

Value Description
reader
writer

MemoryValidationCheck

One health check the validator runs (#819).

Value Description
BROKEN_REF An edge whose target node is missing OR soft-deleted. A hard-deleted target cannot occur - Edge.target is FK-enforced with onDelete: Cascade - so in practice this means a dangling edge to a tombstone.
SPARSE A node with no description, content, or abstract.
STALE_ABSTRACT The abstract no longer reflects current content (spec 032 FR-011).
EMBED_FAILED embedding_failed_at is set - a retryable failure awaiting its backoff, or the permanent class (deterministic 4xx, dimension mismatch, #206 encrypted-no-plaintext) recoverable via retryFailedEmbeddings (spec 033 / #882). Such a node is absent from vector search, which from outside looks identical to no hits matching.
SCHEMA objectType/properties violate the memory declared schema (#725).

MemoryVisibility

035-visibility-enum-cleanup: meaningful only for knowledge (PUBLIC/ORGANIZATION) and group (GROUP); null otherwise. PERSONAL/PRIVATE were dropped — privacy is the personal/private memory CLASS now.

Value Description
PUBLIC
ORGANIZATION
GROUP 023-app-shape US4: team-shared visibility. Bound bidirectionally to MemoryClass.group by the chk_memory_group_visibility CHECK constraint — a memory has class=group iff visibility=GROUP.

NodeExportEncoding

How the rendered payload is encoded. TEXT for MD/JSON; BASE64 for PDF.

Value Description
TEXT
BASE64

NodeExportFormat

Value Description
MD
JSON
PDF

NodeExportSection

Selectable sections for a presentation (full: false) export.

Value Description
METADATA
CONTENT
ABSTRACT
DATA
PROPERTIES
EDGES

NodeField

Node fields a lexical (keyword/regex) query matches and weights. Weight-mask, NOT a hard filter: naming a subset zeroes the excluded fields in scoring but does not strictly exclude them from matching (cor:api:090:03). Ignored by mode:vector (the index source is a per-memory config, not a query param).

Value Description
name
alias
loc
tags
description
abstract
content
properties
data

NodeMergeField

A node field that mergeNodes can fold from the source into the target.

Value Description
CONTENT Concatenate source content after target content (blank-line separated).
ABSTRACT Concatenate source abstract after target abstract (2000-char cap enforced).
DESCRIPTION Concatenate source description after target description.
TAGS Union the tag sets (target order first, then new source tags).
DATA Shallow-merge the encrypted 'data' JSON; target wins on key collisions.
PROPERTIES Shallow-merge the 'properties' JSON; target wins on key collisions.
EDGES Re-point the source's incoming and outgoing edges onto the target. Each re-homed edge's loc is recomputed from its new endpoints (deriveEdgeLoc); a re-homed edge whose recomputed (loc, memoryId) collides with one the target already holds is dropped rather than duplicated — so an equivalent edge with an endpoint-derived loc is de-duplicated — as are self-loops.

NodeSort

Result ordering for findNodes. Default relevance; the rest suppress scoring (browse order).

Value Description
relevance
loc
seq
updatedAt

NodeTextField

Text-bearing Node fields that searchReplaceInNodes may rewrite. JSON fields (data, properties) and the structural 'loc' are intentionally excluded in v1.

Value Description
content
name
alias
description
abstract
tags

NodeWhereCast

How a NodeWhere leaf's extracted value is typed before comparison (#719). Default text.

Value Description
text
number
datetime
boolean

NodeWhereColumn

JSONB column a NodeWhere leaf reads (#719). Defaults to properties.

Value Description
properties
data

PrincipalType

Value Description
USER
APP
AGENT

Role

Value Description
OWNER
ADMIN
CONTRIBUTOR
READER

SearchEntityType

Entity types the cross-entity global search (globalSearch) can return. Mirrors the SearchEntityType union in src/lib/global-search.

Value Description
organization
memory
node
agent
app
aiServiceConfig
user

SearchField

Fields globalSearch can match against. Omit fields to let the server smart-sniff the query shape (PK → URN → name); explicit fields override the sniff. pk is exact-match; the rest are case-insensitive substring. content (node bodies) is opt-in and skips encrypted memories.

Value Description
urn
name
description
pk
content

SearchGranularity

Result granularity for findNodes (cor:api:090). Spec 033.

  • node: one entry per matching node (default).
  • chunk: passage-level entries with offsets into the parent node's content (vector mode only; chunk hits collapse to node-level when granularity is node).
Value Description
node
chunk

SortDirection

Sort direction for a findNodes property-path sort (#719). Default asc.

Value Description
asc
desc

SubscriptionType

Value Description
READ_ONLY
READ_WRITE

SyncStatus

Value Description
PENDING
SYNCING
OK
ERROR

UploadIntent

Value Description
USER
AGENT_REQUEST

UsageActivityBucketSize

Bucket width for usageActivity (#796).

Value Description
DAY
WEEK
MONTH

Scalars

Boolean

The Boolean scalar type represents true or false.

DateTime

A timestamp string, e.g. '2026-07-30T12:34:56.789Z'.

Guaranteed parseable by Date.parse / new Date(). Values Hadron mints are ISO 8601 UTC; a value passed through from an external provider (calendar, mail, drive) keeps that provider's representation, which may carry a non-UTC offset — so compare instants, don't compare these as strings.

Issue #205: date fields used to be declared String and fed a Prisma Date, which graphql-js coerced through Date.valueOf() into epoch milliseconds ('1716943200000') — a value new Date() parses as Invalid Date. This scalar makes that shape unrepresentable, so no client needs to sniff the format.

Output-only today: date-valued arguments remain String.

Float

The Float scalar type represents signed double-precision fractional values as specified by IEEE 754.

ID

The ID scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as "4") or integer (such as 4) input value will be accepted as an ID.

Int

The Int scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.

JSON

String

The String scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.