@unicity-astrid/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +120 -0
  2. package/dist/approval.d.ts +23 -0
  3. package/dist/approval.d.ts.map +1 -0
  4. package/dist/approval.js +29 -0
  5. package/dist/approval.js.map +1 -0
  6. package/dist/capabilities.d.ts +14 -0
  7. package/dist/capabilities.d.ts.map +1 -0
  8. package/dist/capabilities.js +19 -0
  9. package/dist/capabilities.js.map +1 -0
  10. package/dist/capsule.d.ts +39 -0
  11. package/dist/capsule.d.ts.map +1 -0
  12. package/dist/capsule.js +67 -0
  13. package/dist/capsule.js.map +1 -0
  14. package/dist/contracts.d.ts +1104 -0
  15. package/dist/contracts.d.ts.map +1 -0
  16. package/dist/contracts.js +4 -0
  17. package/dist/contracts.js.map +1 -0
  18. package/dist/elicit.d.ts +30 -0
  19. package/dist/elicit.d.ts.map +1 -0
  20. package/dist/elicit.js +103 -0
  21. package/dist/elicit.js.map +1 -0
  22. package/dist/env.d.ts +19 -0
  23. package/dist/env.d.ts.map +1 -0
  24. package/dist/env.js +27 -0
  25. package/dist/env.js.map +1 -0
  26. package/dist/errors.d.ts +46 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +108 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/fs.d.ts +135 -0
  31. package/dist/fs.d.ts.map +1 -0
  32. package/dist/fs.js +257 -0
  33. package/dist/fs.js.map +1 -0
  34. package/dist/http.d.ts +90 -0
  35. package/dist/http.d.ts.map +1 -0
  36. package/dist/http.js +276 -0
  37. package/dist/http.js.map +1 -0
  38. package/dist/identity.d.ts +46 -0
  39. package/dist/identity.d.ts.map +1 -0
  40. package/dist/identity.js +69 -0
  41. package/dist/identity.js.map +1 -0
  42. package/dist/index.d.ts +30 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +27 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/interceptors.d.ts +21 -0
  47. package/dist/interceptors.d.ts.map +1 -0
  48. package/dist/interceptors.js +22 -0
  49. package/dist/interceptors.js.map +1 -0
  50. package/dist/ipc.d.ts +143 -0
  51. package/dist/ipc.d.ts.map +1 -0
  52. package/dist/ipc.js +261 -0
  53. package/dist/ipc.js.map +1 -0
  54. package/dist/kv.d.ts +45 -0
  55. package/dist/kv.d.ts.map +1 -0
  56. package/dist/kv.js +91 -0
  57. package/dist/kv.js.map +1 -0
  58. package/dist/log.d.ts +17 -0
  59. package/dist/log.d.ts.map +1 -0
  60. package/dist/log.js +40 -0
  61. package/dist/log.js.map +1 -0
  62. package/dist/net.d.ts +154 -0
  63. package/dist/net.d.ts.map +1 -0
  64. package/dist/net.js +421 -0
  65. package/dist/net.js.map +1 -0
  66. package/dist/process.d.ts +77 -0
  67. package/dist/process.d.ts.map +1 -0
  68. package/dist/process.js +128 -0
  69. package/dist/process.js.map +1 -0
  70. package/dist/runtime/bridge.d.ts +34 -0
  71. package/dist/runtime/bridge.d.ts.map +1 -0
  72. package/dist/runtime/bridge.js +326 -0
  73. package/dist/runtime/bridge.js.map +1 -0
  74. package/dist/runtime/index.d.ts +3 -0
  75. package/dist/runtime/index.d.ts.map +1 -0
  76. package/dist/runtime/index.js +3 -0
  77. package/dist/runtime/index.js.map +1 -0
  78. package/dist/runtime/registry.d.ts +58 -0
  79. package/dist/runtime/registry.d.ts.map +1 -0
  80. package/dist/runtime/registry.js +129 -0
  81. package/dist/runtime/registry.js.map +1 -0
  82. package/dist/runtime.d.ts +36 -0
  83. package/dist/runtime.d.ts.map +1 -0
  84. package/dist/runtime.js +50 -0
  85. package/dist/runtime.js.map +1 -0
  86. package/dist/time.d.ts +29 -0
  87. package/dist/time.d.ts.map +1 -0
  88. package/dist/time.js +43 -0
  89. package/dist/time.js.map +1 -0
  90. package/dist/tool.d.ts +48 -0
  91. package/dist/tool.d.ts.map +1 -0
  92. package/dist/tool.js +86 -0
  93. package/dist/tool.js.map +1 -0
  94. package/dist/uplink.d.ts +27 -0
  95. package/dist/uplink.d.ts.map +1 -0
  96. package/dist/uplink.js +36 -0
  97. package/dist/uplink.js.map +1 -0
  98. package/package.json +38 -0
  99. package/src/approval.ts +38 -0
  100. package/src/capabilities.ts +22 -0
  101. package/src/capsule.ts +90 -0
  102. package/src/contracts.ts +1189 -0
  103. package/src/elicit.ts +136 -0
  104. package/src/env.ts +31 -0
  105. package/src/errors.ts +122 -0
  106. package/src/fs.ts +357 -0
  107. package/src/http.ts +345 -0
  108. package/src/identity.ts +101 -0
  109. package/src/index.ts +83 -0
  110. package/src/interceptors.ts +25 -0
  111. package/src/ipc.ts +354 -0
  112. package/src/kv.ts +123 -0
  113. package/src/log.ts +43 -0
  114. package/src/net.ts +545 -0
  115. package/src/process.ts +205 -0
  116. package/src/runtime/bridge.ts +374 -0
  117. package/src/runtime/index.ts +11 -0
  118. package/src/runtime/registry.ts +178 -0
  119. package/src/runtime.ts +70 -0
  120. package/src/time.ts +48 -0
  121. package/src/tool.ts +125 -0
  122. package/src/uplink.ts +49 -0
  123. package/src/wit-imports.d.ts +689 -0
  124. package/wit-contracts/astrid-contracts.wit +1266 -0
@@ -0,0 +1,1266 @@
1
+ // AUTO-GENERATED — DO NOT EDIT.
2
+ //
3
+ // Concatenated from contracts/interfaces/*.wit by
4
+ // scripts/sync-contracts-wit.sh.
5
+ //
6
+ // Source of truth: unicity-astrid/wit (git submodule at contracts/).
7
+ // Run `scripts/sync-contracts-wit.sh` after pulling the submodule to
8
+ // regenerate this file.
9
+
10
+ package astrid:contracts@1.0.0;
11
+
12
+ // ── types ──────────────────────────────────────────────────────────
13
+ package astrid-bus:types@1.0.0;
14
+
15
+ /// Shared types used across Astrid interfaces.
16
+ ///
17
+ /// Foundation types for messages, tool calls, and token usage.
18
+ /// Imported by llm, session, prompt, context, and tool interfaces.
19
+ interface types {
20
+ /// A conversation message.
21
+ record message {
22
+ role: message-role,
23
+ content: message-content,
24
+ }
25
+
26
+ enum message-role {
27
+ system,
28
+ user,
29
+ assistant,
30
+ tool,
31
+ }
32
+
33
+ /// Message content — text, tool calls, tool results, or mixed.
34
+ variant message-content {
35
+ text(string),
36
+ tool-calls(list<tool-call>),
37
+ tool-result(tool-call-result),
38
+ multi-part(list<content-part>),
39
+ }
40
+
41
+ variant content-part {
42
+ text(string),
43
+ image(image-data),
44
+ }
45
+
46
+ record image-data {
47
+ data: string,
48
+ media-type: string,
49
+ }
50
+
51
+ /// A tool call requested by the model.
52
+ record tool-call {
53
+ /// Tool call identifier.
54
+ id: string,
55
+ /// Name of the tool to invoke.
56
+ name: string,
57
+ /// JSON-encoded arguments (serde_json::Value in Rust).
58
+ arguments: string,
59
+ }
60
+
61
+ /// Result of executing a tool call.
62
+ record tool-call-result {
63
+ call-id: string,
64
+ content: string,
65
+ is-error: bool,
66
+ }
67
+
68
+ /// A tool definition provided to the model.
69
+ record tool-definition {
70
+ name: string,
71
+ description: option<string>,
72
+ input-schema: string,
73
+ }
74
+
75
+ /// Token usage statistics.
76
+ record usage {
77
+ input-tokens: u64,
78
+ output-tokens: u64,
79
+ }
80
+ }
81
+
82
+ // ── agent ──────────────────────────────────────────────────────────
83
+ package astrid-bus:agent@1.0.0;
84
+
85
+ /// Agent interface — runtime envelopes the agent loop publishes for uplinks.
86
+ ///
87
+ /// The agent capsule publishes `agent.v1.response` with streaming and final
88
+ /// turn output, and `agent.v1.session_changed` whenever the active session
89
+ /// rolls over. Uplink capsules subscribe to surface these to the user.
90
+ interface agent {
91
+ /// A response generated by the agent for the user.
92
+ record response {
93
+ /// The text output (may be a streaming delta or a complete reply).
94
+ text: string,
95
+ /// True if this is the final response in the turn.
96
+ is-final: bool,
97
+ /// Session ID for multi-session attribution.
98
+ session-id: string,
99
+ }
100
+
101
+ /// Notification that the active session has changed (e.g. cleared,
102
+ /// branched, restored). Uplinks use this to refresh their view.
103
+ record session-changed {
104
+ /// The session ID that is now active.
105
+ session-id: string,
106
+ /// Optional ID of the session that was previously active.
107
+ previous-session-id: option<string>,
108
+ /// Reason for the change (e.g. "clear", "restore", "branch").
109
+ reason: string,
110
+ }
111
+ }
112
+
113
+ // ── approval ──────────────────────────────────────────────────────────
114
+ package astrid-bus:approval@1.0.0;
115
+
116
+ /// Approval interface — human-in-the-loop authorization envelopes.
117
+ ///
118
+ /// A capsule publishes `astrid.v1.approval` when it needs user authorization
119
+ /// for a sensitive action that did not match a pre-approved allowance. The
120
+ /// TUI prompts, then publishes the decision on
121
+ /// `astrid.v1.approval.response.<request-id>`. Distinct from the host
122
+ /// `request-approval` syscall (in-capsule API) — these envelopes carry the
123
+ /// same flow over the IPC bus for uplink consumption.
124
+ interface approval {
125
+ /// An interceptor or capsule request for human authorization.
126
+ record required {
127
+ /// Correlation ID matching the response.
128
+ request-id: string,
129
+ /// The action being requested (e.g. `"git push"`).
130
+ action: string,
131
+ /// The resource target (e.g. full command string).
132
+ target-resource: string,
133
+ /// Justification shown to the user.
134
+ reason: string,
135
+ }
136
+
137
+ /// Response to an approval request.
138
+ record response {
139
+ /// Must match the `request-id` from the originating request.
140
+ request-id: string,
141
+ /// The user's decision (e.g. `"approve"`, `"deny"`,
142
+ /// `"approve_session"`, `"approve_always"`, `"allowance"`).
143
+ decision: string,
144
+ /// Optional reason for the decision.
145
+ reason: option<string>,
146
+ }
147
+ }
148
+
149
+ // ── client ──────────────────────────────────────────────────────────
150
+ package astrid-bus:client@1.0.0;
151
+
152
+ /// Client interface — connection lifecycle envelopes for uplinks.
153
+ ///
154
+ /// Uplinks publish `client.v1.connect` on attach and `client.v1.disconnect`
155
+ /// on detach so the kernel can update the active-connection count and
156
+ /// trigger idle-shutdown when the last client disconnects.
157
+ interface client {
158
+ /// A client has connected to an uplink.
159
+ record connect {
160
+ /// Optional client identifier (e.g. process name + PID).
161
+ client-id: option<string>,
162
+ }
163
+
164
+ /// A client is disconnecting gracefully.
165
+ record disconnect {
166
+ /// Optional reason for disconnection (e.g. "quit", "timeout").
167
+ reason: option<string>,
168
+ }
169
+ }
170
+
171
+ // ── context ──────────────────────────────────────────────────────────
172
+ package astrid-bus:context@1.0.0;
173
+
174
+ /// Context interface — conversation compaction and token management.
175
+ ///
176
+ /// A capsule exporting this interface handles `context_engine.v1.*`
177
+ /// requests and publishes compaction responses and hooks for plugin
178
+ /// capsules to influence compaction behaviour.
179
+ interface context {
180
+ use astrid-bus:types/types.{message};
181
+
182
+ /// Request to compact messages within a token budget.
183
+ record compact-request {
184
+ session-id: string,
185
+ messages: list<message>,
186
+ max-tokens: u64,
187
+ target-tokens: u64,
188
+ }
189
+
190
+ /// Result of compaction.
191
+ record compact-response {
192
+ messages: list<message>,
193
+ compacted: bool,
194
+ messages-removed: u32,
195
+ strategy: string,
196
+ }
197
+
198
+ /// Request to estimate token count for messages.
199
+ record estimate-request {
200
+ messages: list<message>,
201
+ }
202
+
203
+ /// Token count estimate.
204
+ record estimate-response {
205
+ estimated-tokens: u64,
206
+ }
207
+
208
+ /// Hook payload sent before compaction (plugins can influence).
209
+ record before-compaction-hook {
210
+ session-id: string,
211
+ messages: list<message>,
212
+ message-count: u32,
213
+ estimated-tokens: u64,
214
+ max-tokens: u64,
215
+ response-topic: string,
216
+ }
217
+
218
+ /// Plugin response to before-compaction hook.
219
+ record before-compaction-hook-response {
220
+ skip: option<bool>,
221
+ pinned-message-ids: list<string>,
222
+ custom-strategy: option<string>,
223
+ }
224
+
225
+ /// Notification after compaction completes.
226
+ record after-compaction-event {
227
+ session-id: string,
228
+ messages-before: u32,
229
+ messages-after: u32,
230
+ tokens-before: u64,
231
+ tokens-after: u64,
232
+ strategy-used: string,
233
+ }
234
+ }
235
+
236
+ // ── elicit ──────────────────────────────────────────────────────────
237
+ package astrid-bus:elicit@1.0.0;
238
+
239
+ /// Elicit interface — interactive user input during a capsule lifecycle hook.
240
+ ///
241
+ /// A capsule publishes `astrid.v1.elicit.<key>` when its install / upgrade
242
+ /// hook needs a value from the user. The TUI prompts, then publishes the
243
+ /// answer on `astrid.v1.elicit.response.<key>`. Distinct from the host
244
+ /// `elicit` syscall (which is the in-capsule API) — these envelopes carry
245
+ /// the same flow over the IPC bus for uplink consumption.
246
+ interface elicit {
247
+ use astrid-bus:onboarding/onboarding.{field};
248
+
249
+ /// A lifecycle hook is requesting user input.
250
+ record request {
251
+ /// Correlation ID matching the response.
252
+ request-id: string,
253
+ /// The capsule requesting input.
254
+ capsule-id: string,
255
+ /// Field descriptor reusing the onboarding schema.
256
+ field: field,
257
+ }
258
+
259
+ /// Response to an elicit request.
260
+ record response {
261
+ /// Must match the `request-id` from the originating request.
262
+ request-id: string,
263
+ /// The user's input. Absent if the user cancelled.
264
+ value: option<string>,
265
+ /// For `array`-type fields, the collected items.
266
+ values: option<list<string>>,
267
+ }
268
+ }
269
+
270
+ // ── hook ──────────────────────────────────────────────────────────
271
+ package astrid-bus:hook@1.0.0;
272
+
273
+ /// Hook interface — maps kernel lifecycle events to semantic hooks.
274
+ ///
275
+ /// A capsule exporting this interface intercepts `astrid.v1.lifecycle.*`
276
+ /// events and publishes `hook.v1.result.*` with merge strategy results.
277
+ /// Plugin capsules subscribe to specific hooks to extend behaviour.
278
+ interface hook {
279
+ /// Lifecycle events emitted by the kernel.
280
+ enum lifecycle-event {
281
+ session-created,
282
+ session-ended,
283
+ tool-call-started,
284
+ tool-call-completed,
285
+ tool-result-persisting,
286
+ message-received,
287
+ message-sending,
288
+ message-sent,
289
+ sub-agent-spawned,
290
+ sub-agent-completed,
291
+ sub-agent-failed,
292
+ sub-agent-cancelled,
293
+ context-compaction-started,
294
+ context-compaction-completed,
295
+ kernel-started,
296
+ kernel-shutdown,
297
+ }
298
+
299
+ /// Merged result from hook fan-out.
300
+ record hook-result {
301
+ /// Whether the operation should be skipped.
302
+ skip: option<bool>,
303
+ /// Merged data from interceptor responses (opaque JSON).
304
+ data: option<string>,
305
+ }
306
+ }
307
+
308
+ // ── llm ──────────────────────────────────────────────────────────
309
+ package astrid-bus:llm@1.0.0;
310
+
311
+ /// LLM interface — streaming text generation with tool use support.
312
+ ///
313
+ /// A capsule exporting this interface handles `llm.v1.request.generate.*`
314
+ /// events and publishes `llm.v1.stream.*` streaming responses.
315
+ interface llm {
316
+ use astrid-bus:types/types.{message, tool-definition, usage};
317
+ use astrid-bus:registry/registry.{provider-entry};
318
+
319
+ /// Request asking an LLM-provider capsule to describe itself.
320
+ /// Topic: `llm.v1.request.describe`. The registry capsule fans this
321
+ /// out to discover available providers and their per-provider
322
+ /// request / stream topics.
323
+ record describe-request {
324
+ /// Correlation ID for the response. The provider replies on
325
+ /// `llm.v1.response.describe.<correlation-id>`.
326
+ correlation-id: string,
327
+ }
328
+
329
+ /// Provider self-description response.
330
+ /// Topic: `llm.v1.response.describe.<correlation-id>`.
331
+ record describe-response {
332
+ /// Must match the `correlation-id` from the originating request.
333
+ correlation-id: string,
334
+ /// Provider entries the capsule offers (one capsule may expose
335
+ /// multiple models — e.g. an OpenAI-compatible front-end serving
336
+ /// several model IDs).
337
+ providers: list<provider-entry>,
338
+ }
339
+
340
+ /// Request to generate a response.
341
+ record generate-request {
342
+ request-id: string,
343
+ model: string,
344
+ messages: list<message>,
345
+ tools: list<tool-definition>,
346
+ /// System prompt.
347
+ system: string,
348
+ }
349
+
350
+ /// A streaming event from the provider.
351
+ variant stream-event {
352
+ text-delta(string),
353
+ tool-call-start(tool-call-start-event),
354
+ tool-call-delta(tool-call-delta-event),
355
+ tool-call-end(tool-call-end-event),
356
+ reasoning-delta(string),
357
+ usage(usage),
358
+ done,
359
+ error(string),
360
+ }
361
+
362
+ record tool-call-start-event {
363
+ id: string,
364
+ name: string,
365
+ }
366
+
367
+ record tool-call-delta-event {
368
+ id: string,
369
+ args-delta: string,
370
+ }
371
+
372
+ record tool-call-end-event {
373
+ id: string,
374
+ }
375
+
376
+ /// Final (non-streaming) response.
377
+ record generate-response {
378
+ message: message,
379
+ has-tool-calls: bool,
380
+ stop-reason: stop-reason,
381
+ usage: usage,
382
+ }
383
+
384
+ enum stop-reason {
385
+ end-turn,
386
+ max-tokens,
387
+ tool-use,
388
+ stop-sequence,
389
+ }
390
+ }
391
+
392
+ // ── onboarding ──────────────────────────────────────────────────────────
393
+ package astrid-bus:onboarding@1.0.0;
394
+
395
+ /// Onboarding interface — env-var collection at install / first-run.
396
+ ///
397
+ /// A capsule publishes `astrid.v1.onboarding.required` when it cannot start
398
+ /// without configuration values that the operator has not yet supplied.
399
+ /// The TUI / installer subscribes, prompts the user per field, and writes
400
+ /// the collected values back to the capsule's `[env]` configuration.
401
+ interface onboarding {
402
+ /// A capsule needs environment variables to be provided by the user.
403
+ record required {
404
+ /// The ID of the capsule requiring onboarding.
405
+ capsule-id: string,
406
+ /// Rich field descriptors for each missing env var.
407
+ fields: list<field>,
408
+ }
409
+
410
+ /// A field descriptor for capsule onboarding.
411
+ record field {
412
+ /// The environment variable key.
413
+ key: string,
414
+ /// The prompt shown to the user.
415
+ prompt: string,
416
+ /// Optional description for additional context.
417
+ description: option<string>,
418
+ /// The input type for this field.
419
+ field-type: field-type,
420
+ /// Optional default value.
421
+ default: option<string>,
422
+ /// Placeholder hint text shown when the input is empty (e.g. `"sk-..."`).
423
+ placeholder: option<string>,
424
+ }
425
+
426
+ /// The type of input expected for an onboarding field.
427
+ variant field-type {
428
+ /// Free-form text input.
429
+ text,
430
+ /// Masked secret input (stored in the SecretStore).
431
+ secret,
432
+ /// Selection from a fixed set of choices.
433
+ choice(list<string>),
434
+ /// Multi-value array input (user adds items one at a time).
435
+ array,
436
+ }
437
+ }
438
+
439
+ // ── prompt ──────────────────────────────────────────────────────────
440
+ package astrid-bus:prompt@1.0.0;
441
+
442
+ /// Prompt interface — assembles LLM prompts with plugin hooks.
443
+ ///
444
+ /// A capsule exporting this interface handles `prompt_builder.v1.assemble`
445
+ /// and publishes assembled prompts, with before/after hooks for context
446
+ /// injection by plugin capsules.
447
+ interface prompt {
448
+ use astrid-bus:types/types.{message, tool-definition};
449
+
450
+ /// Request to assemble a prompt for LLM generation.
451
+ record assemble-request {
452
+ messages: list<message>,
453
+ system-prompt: string,
454
+ request-id: string,
455
+ model: string,
456
+ provider: string,
457
+ session-id: option<string>,
458
+ }
459
+
460
+ /// Assembled prompt ready for LLM.
461
+ record assemble-response {
462
+ system-prompt: string,
463
+ user-context-prefix: string,
464
+ request-id: string,
465
+ session-id: option<string>,
466
+ /// Collected tool schemas from tool-providing capsules.
467
+ tools: list<tool-definition>,
468
+ /// Session conversation history messages.
469
+ messages: list<message>,
470
+ }
471
+
472
+ /// Hook payload sent before prompt build (plugins inject context).
473
+ record before-build-hook {
474
+ messages: list<message>,
475
+ system-prompt: string,
476
+ request-id: string,
477
+ model: string,
478
+ provider: string,
479
+ response-topic: string,
480
+ }
481
+
482
+ /// Plugin response to before-build hook.
483
+ record before-build-hook-response {
484
+ prepend-system-context: option<string>,
485
+ append-system-context: option<string>,
486
+ system-prompt: option<string>,
487
+ prepend-context: option<string>,
488
+ }
489
+
490
+ /// Notification after prompt is built.
491
+ record after-build-event {
492
+ system-prompt: string,
493
+ user-context-prefix: string,
494
+ request-id: string,
495
+ }
496
+ }
497
+
498
+ // ── registry ──────────────────────────────────────────────────────────
499
+ package astrid-bus:registry@1.0.0;
500
+
501
+ /// Registry interface — LLM provider discovery and model management.
502
+ ///
503
+ /// A capsule exporting this interface handles `registry.v1.*` requests,
504
+ /// discovers available LLM providers from loaded capsule metadata, and
505
+ /// manages the active model selection.
506
+ interface registry {
507
+ /// An available LLM provider entry.
508
+ record provider-entry {
509
+ /// Model ID (e.g. "gpt-5.4", "claude-sonnet-4-20250514").
510
+ id: string,
511
+ /// Human-readable description.
512
+ description: string,
513
+ /// IPC topic to publish LLM requests to.
514
+ request-topic: string,
515
+ /// IPC topic the provider streams responses on.
516
+ stream-topic: string,
517
+ /// Model capabilities (e.g. "text", "vision", "tools").
518
+ capabilities: list<string>,
519
+ /// Provider's context window size in tokens.
520
+ context-window: option<u64>,
521
+ /// Provider's max output tokens per request.
522
+ max-output-tokens: option<u64>,
523
+ }
524
+
525
+ /// A single option in a selection picker.
526
+ record selection-option {
527
+ /// Machine-readable identifier sent back on the callback.
528
+ id: string,
529
+ /// Human-readable label shown in the picker.
530
+ label: string,
531
+ /// Optional description shown alongside the label.
532
+ description: option<string>,
533
+ }
534
+
535
+ /// Capsule asking the user to choose from a set of options. Used by
536
+ /// the registry to drive the LLM-provider picker UI in the TUI.
537
+ /// Topic: `registry.v1.selection.required`.
538
+ record selection-required {
539
+ /// Correlation ID for the callback.
540
+ request-id: string,
541
+ /// Title or prompt shown above the list.
542
+ title: string,
543
+ /// The selectable options.
544
+ options: list<selection-option>,
545
+ /// IPC topic to publish the user's choice back on.
546
+ callback-topic: string,
547
+ }
548
+
549
+ /// User's selection sent back to the requesting capsule.
550
+ /// Topic: `registry.v1.selection.callback` (or the `callback-topic`
551
+ /// declared in the matching `selection-required`).
552
+ record selection-callback {
553
+ /// Must match the `request-id` from the originating
554
+ /// `selection-required`.
555
+ request-id: string,
556
+ /// `id` of the chosen `selection-option`.
557
+ selected-id: string,
558
+ }
559
+ }
560
+
561
+ // ── session ──────────────────────────────────────────────────────────
562
+ package astrid-bus:session@1.0.0;
563
+
564
+ /// Session protocol — persistent conversation history management.
565
+ ///
566
+ /// A capsule exporting this interface handles `session.v1.request.*`
567
+ /// events and publishes `session.v1.response.*` replies scoped by
568
+ /// correlation ID.
569
+ interface session {
570
+ use astrid-bus:types/types.{message};
571
+
572
+ /// Request to fetch conversation history.
573
+ record get-messages-request {
574
+ session-id: string,
575
+ correlation-id: string,
576
+ append-before-read: option<list<message>>,
577
+ }
578
+
579
+ /// Response containing conversation history.
580
+ record get-messages-response {
581
+ correlation-id: string,
582
+ messages: list<message>,
583
+ }
584
+
585
+ /// Request to clear a session and start fresh.
586
+ record clear-request {
587
+ session-id: string,
588
+ correlation-id: string,
589
+ }
590
+
591
+ /// Response confirming session cleared.
592
+ record clear-response {
593
+ correlation-id: string,
594
+ new-session-id: string,
595
+ old-session-id: string,
596
+ }
597
+
598
+ /// Fire-and-forget append to conversation history.
599
+ record append-request {
600
+ session-id: string,
601
+ messages: list<message>,
602
+ }
603
+
604
+ /// Broadcast notification that a session was cleared. Distinct from
605
+ /// `clear-request`/`clear-response` (the request/response pair the
606
+ /// session capsule handles): this is a fan-out event the agent loop
607
+ /// publishes after a successful clear so unrelated capsules can drop
608
+ /// any per-session ephemeral state. Topic: `session.v1.clear`.
609
+ record session-cleared {
610
+ /// Session ID that was cleared.
611
+ session-id: string,
612
+ }
613
+ }
614
+
615
+ // ── spark ──────────────────────────────────────────────────────────
616
+ package astrid-bus:spark@1.0.0;
617
+
618
+ /// Spark interface — agent persona and system prompt construction.
619
+ ///
620
+ /// A capsule exporting this interface handles `identity.v1.request.build`
621
+ /// and publishes `identity.v1.response.ready` with the assembled system
622
+ /// prompt for the current workspace and session.
623
+ ///
624
+ /// Named "spark" to distinguish from user identity management (the host
625
+ /// ABI `identity-*` functions for principal/account resolution).
626
+ interface spark {
627
+ /// Request to build the agent's system prompt.
628
+ record build-request {
629
+ workspace-root: string,
630
+ session-id: option<string>,
631
+ }
632
+
633
+ /// Response with the assembled system prompt.
634
+ record build-response {
635
+ prompt: string,
636
+ session-id: option<string>,
637
+ }
638
+ }
639
+
640
+ // ── system ──────────────────────────────────────────────────────────
641
+ package astrid-bus:system@1.0.0;
642
+
643
+ /// System interface — kernel-emitted lifecycle, health, and CLI envelopes.
644
+ ///
645
+ /// The kernel publishes these on the IPC bus so capsules can react to
646
+ /// boot-completion, shutdown, watchdog ticks, bus health warnings, and
647
+ /// inbound CLI slash-commands.
648
+ interface system {
649
+ /// Published once after every capsule has reported ready, signalling
650
+ /// that the agent stack is fully online. Topic: `astrid.v1.capsules_loaded`.
651
+ record capsules-loaded {
652
+ /// IDs of every capsule that successfully loaded.
653
+ capsule-ids: list<string>,
654
+ }
655
+
656
+ /// Periodic kernel watchdog tick, used by long-lived capsules to age
657
+ /// out stale state (timeouts, abandoned correlations, etc.).
658
+ /// Topic: `astrid.v1.watchdog.tick`.
659
+ record watchdog-tick {
660
+ /// Wall-clock time of the tick (UNIX epoch milliseconds).
661
+ timestamp-ms: u64,
662
+ }
663
+
664
+ /// Warning emitted when a subscriber falls behind and the bus had to
665
+ /// drop messages. Subscribers can use this as a signal to drain or
666
+ /// resubscribe. Topic: `astrid.v1.event_bus.lagged`.
667
+ record event-bus-lagged {
668
+ /// Topic that lagged.
669
+ topic: string,
670
+ /// Number of messages dropped.
671
+ dropped: u64,
672
+ }
673
+
674
+ /// Cooperative restart signal — the kernel asks long-lived capsules
675
+ /// to flush ephemeral state and re-arm. Topic: `system.v1.lifecycle.restart`.
676
+ record lifecycle-restart {
677
+ /// Reason for the restart (e.g. `"config-reload"`, `"upgrade"`).
678
+ reason: string,
679
+ }
680
+
681
+ /// A slash-command typed by a human in an uplink. The CLI capsule
682
+ /// publishes this when the user enters `/<command> [args]`. Routed
683
+ /// to the capsule that registered the command name via its manifest.
684
+ /// Topic: `cli.v1.command.execute`.
685
+ record command-execute {
686
+ /// The command name (without the leading slash).
687
+ name: string,
688
+ /// JSON-encoded arguments (parsed by the receiving capsule).
689
+ arguments: string,
690
+ /// Session ID the command was issued in.
691
+ session-id: string,
692
+ }
693
+ }
694
+
695
+ // ── tool ──────────────────────────────────────────────────────────
696
+ package astrid-bus:tool@1.0.0;
697
+
698
+ /// Tool interface — dispatches tool calls to capsule handlers.
699
+ ///
700
+ /// A capsule exporting this interface handles `tool.v1.request.execute`,
701
+ /// routes to the appropriate tool capsule via `tool.v1.execute.<name>`,
702
+ /// and collects results on `tool.v1.execute.*.result`.
703
+ interface tool {
704
+ use astrid-bus:types/types.{tool-call, tool-call-result, tool-definition};
705
+
706
+ /// Request to cancel in-flight tool executions.
707
+ record cancel-request {
708
+ call-ids: list<string>,
709
+ }
710
+
711
+ /// Request asking a tool-providing capsule to enumerate its tools.
712
+ /// Topic: `tool.v1.request.describe`. Empty payload — every responder
713
+ /// returns its full tool list. Routed by the SDK macro from
714
+ /// `#[astrid::tool(...)]` attributes.
715
+ record describe-request {
716
+ /// Correlation ID for the response. The capsule replies on
717
+ /// `tool.v1.response.describe.<correlation-id>`.
718
+ correlation-id: string,
719
+ }
720
+
721
+ /// Response listing the tools a capsule provides.
722
+ /// Topic: `tool.v1.response.describe.<correlation-id>`.
723
+ record describe-response {
724
+ /// Must match the `correlation-id` from the originating request.
725
+ correlation-id: string,
726
+ /// The capsule's exposed tools.
727
+ tools: list<tool-definition>,
728
+ }
729
+ }
730
+
731
+ // ── user ──────────────────────────────────────────────────────────
732
+ package astrid-bus:user@1.0.0;
733
+
734
+ /// User interface — input envelopes from a human via an uplink.
735
+ ///
736
+ /// Uplink capsules (CLI, Telegram, Discord, etc.) publish `user.v1.prompt`
737
+ /// when the human types a message. The agent loop subscribes to drive a
738
+ /// new turn.
739
+ interface user {
740
+ /// A prompt typed by a human via an uplink.
741
+ record prompt {
742
+ /// The raw text input.
743
+ text: string,
744
+ /// Session ID for conversation continuity. Defaults to `"default"`.
745
+ session-id: string,
746
+ /// Optional extra context (JSON-encoded) — e.g. attachments,
747
+ /// metadata, or per-turn flags the uplink wants to forward.
748
+ context: option<string>,
749
+ }
750
+ }
751
+
752
+ // ── users ──────────────────────────────────────────────────────────
753
+ package astrid-bus:users@1.0.0;
754
+
755
+ /// Users interface — within-principal user identity store.
756
+ ///
757
+ /// Owns the cross-platform user identity mapping for a single Astrid
758
+ /// principal. A capsule exporting this interface (the `users` capsule)
759
+ /// handles `users.v1.<op>.request` events and publishes
760
+ /// `users.v1.<op>.response` replies correlated by `correlation-id`.
761
+ ///
762
+ /// This is distinct from the `user` interface (`user.v1.prompt`), which
763
+ /// carries inbound human prompts from uplinks. Naming separation:
764
+ ///
765
+ /// - `user` (singular) — a single human typing into an uplink.
766
+ /// - `users` (plural) — the identity directory that maps platform
767
+ /// IDs to canonical AstridUserIds.
768
+ ///
769
+ /// Kernel-side principal tenancy is unaffected: this interface covers
770
+ /// user identity *within* one principal's KV scope only. Different
771
+ /// principals have independent stores.
772
+ ///
773
+ /// ## Two-layer identity model
774
+ ///
775
+ /// 1. **Identity layer** — `frontend-link` records map a platform's
776
+ /// stable opaque ID (Discord snowflake, Telegram user-id, Nostr
777
+ /// pubkey) to a canonical `astrid-user-id`. Global per
778
+ /// `(platform, platform-instance, platform-user-id)` triple.
779
+ /// 2. **Presentation layer** — `context-identity` records overlay a
780
+ /// per-context display name on a given identity link. `context-id`
781
+ /// is opaque to the capsule — uplinks define their own scheme
782
+ /// (`"guild:123"`, `"room:!abc:matrix.org"`, `"channel:C01234"`).
783
+ /// Used for "how should the agent address this user *right now*"
784
+ /// when the platform supports per-context names (Discord guild
785
+ /// nicknames, Matrix room display names, Slack channel profiles).
786
+ ///
787
+ /// `resolve` is context-aware: it returns a layered `display-name`
788
+ /// in one round-trip — context override > link's platform name >
789
+ /// AstridUser's canonical Astrid name.
790
+ interface users {
791
+ // ── Envelope ──────────────────────────────────────────────────
792
+
793
+ /// Multi-tenant request envelope.
794
+ ///
795
+ /// Carries provenance ("which uplink, on behalf of which end-user")
796
+ /// and a correlation token so the originating uplink can match the
797
+ /// response back to the inflight request among many concurrent
798
+ /// end-users on a single principal.
799
+ ///
800
+ /// Pending the broader admin-API correlation convention (kernel
801
+ /// issue #748), `source` lives on this interface; once that
802
+ /// convention formalizes a shared envelope, this record migrates
803
+ /// to the shared location and the records below import it instead.
804
+ record source {
805
+ /// Originating uplink capsule — e.g. `"cli"`, `"sphere"`,
806
+ /// `"discord"`, `"telegram"`. Identifies the capsule making
807
+ /// the request (for audit and routing); distinct from
808
+ /// `frontend-link.platform`, which identifies the external
809
+ /// service being linked.
810
+ uplink: string,
811
+ /// AstridUserId of the requester when known. `None` for
812
+ /// system flows or pre-login pairing requests.
813
+ user-id: option<string>,
814
+ /// Correlation token. The requester subscribes to the response
815
+ /// topic and filters incoming responses by this string.
816
+ correlation-id: string,
817
+ }
818
+
819
+ // ── Domain records ────────────────────────────────────────────
820
+
821
+ /// Canonical Astrid user identity.
822
+ ///
823
+ /// One record per human within the principal's user directory.
824
+ /// `id` is the stable UUID — every `frontend-link` points at this.
825
+ record astrid-user {
826
+ /// UUID v4 string (lowercase, hyphenated). Stable for the
827
+ /// lifetime of the user; never reused.
828
+ id: string,
829
+ /// Optional ed25519 public key (32 bytes raw). Set via
830
+ /// `set-public-key`; used by future verification flows.
831
+ public-key: option<list<u8>>,
832
+ /// Operator/canonical Astrid-side display name. Mutable via
833
+ /// `set-display-name`. Distinct from any platform-side name.
834
+ display-name: option<string>,
835
+ /// Creation timestamp, RFC 3339 string.
836
+ created-at: string,
837
+ }
838
+
839
+ /// A platform-to-Astrid-user identity link.
840
+ ///
841
+ /// Composite key: `(platform, platform-instance?, platform-user-id)`.
842
+ /// Exactly one link may exist per triple; relinking overwrites.
843
+ record frontend-link {
844
+ /// Normalized platform name (lowercased, trimmed) —
845
+ /// e.g. `"discord"`, `"telegram"`, `"nostr"`, `"slack"`,
846
+ /// `"matrix"`, `"email"`, `"x"`, `"github"`.
847
+ platform: string,
848
+ /// Optional platform instance for federated / multi-tenant
849
+ /// platforms: Slack workspace, IRC network, XMPP server,
850
+ /// Mattermost instance. `None` for globally-scoped platforms
851
+ /// (Discord, Telegram, X) and for federated platforms whose
852
+ /// identifier already embeds the homeserver in the user-id
853
+ /// (Matrix `@alice:server.org`, Mastodon `@a@server.social`).
854
+ platform-instance: option<string>,
855
+ /// Platform-specific stable opaque user identifier
856
+ /// (Discord snowflake, Telegram int64, Slack `U...`, Nostr
857
+ /// npub, email address, E.164 phone). Never the user's
858
+ /// mutable handle.
859
+ platform-user-id: string,
860
+ /// The Astrid user UUID this platform identity maps to.
861
+ astrid-user-id: string,
862
+ /// When this link was created (RFC 3339). Refreshed on
863
+ /// upsert relink.
864
+ linked-at: string,
865
+ /// How this link was established — `"admin"`, `"system"`,
866
+ /// `"chat_command"`, `"passkey"`, `"self_declared"`, etc.
867
+ /// Recorded for audit. Free-form string.
868
+ method: string,
869
+ /// Platform's *global* display name at link time —
870
+ /// e.g. Discord global username `"alice"`, Telegram
871
+ /// `@alice`, X handle. Mutable: re-link to refresh.
872
+ /// Distinct from any per-context override
873
+ /// (see `context-identity`) and from `astrid-user.display-name`
874
+ /// (the operator-set canonical Astrid name).
875
+ display-name: option<string>,
876
+ }
877
+
878
+ /// Per-context display-name overlay on a `frontend-link`.
879
+ ///
880
+ /// One row per `(platform, platform-instance?, platform-user-id, context-id)`
881
+ /// tuple. The capsule does NOT parse `context-id`; uplinks define
882
+ /// per-platform schemes. Common conventions:
883
+ ///
884
+ /// - Discord per-guild nickname: `context-id = "guild:{guild-id}"`
885
+ /// - Matrix per-room display name: `context-id = "room:{room-id}"`
886
+ /// - Slack per-channel profile: `context-id = "channel:{channel-id}"`
887
+ /// (workspace lives in `platform-instance`)
888
+ /// - Mattermost per-team: `context-id = "team:{team-id}"`
889
+ /// - Single-context platforms (X, SMS): no rows ever created
890
+ ///
891
+ /// Per-context attributes beyond `display-name` (roles, custom
892
+ /// fields, preferences) intentionally do NOT live here. They
893
+ /// belong in memory or a future authz capsule.
894
+ record context-identity {
895
+ platform: string,
896
+ platform-instance: option<string>,
897
+ platform-user-id: string,
898
+ /// Opaque per-platform context key.
899
+ context-id: string,
900
+ /// What this user is called *in this context*.
901
+ display-name: string,
902
+ /// Last update timestamp (RFC 3339).
903
+ updated-at: string,
904
+ }
905
+
906
+ // ── Pagination ─────────────────────────────────────────────────
907
+ //
908
+ // Paginated topics use opaque `cursor: option<string>` tokens.
909
+ // Callers treat the value as a black box — pass `None` on the
910
+ // first request, then loop while the response's `next-cursor`
911
+ // is `Some(token)`, passing that token back unchanged. The
912
+ // capsule defines the format. (Modelled as bare `option<string>`
913
+ // rather than a `type cursor = string` alias for codegen
914
+ // portability — wit-bindgen handles aliases but our JS codegen
915
+ // does not.)
916
+
917
+ // ── Resolve (context-aware) ───────────────────────────────────
918
+
919
+ /// Resolve a platform identity to an Astrid user, optionally
920
+ /// scoped to a context for display-name layering.
921
+ /// Topic: `users.v1.resolve.request`.
922
+ record resolve-request {
923
+ source: source,
924
+ platform: string,
925
+ platform-instance: option<string>,
926
+ platform-user-id: string,
927
+ /// Optional context. When set, the response's `display-name`
928
+ /// uses the per-context override if one exists. When None,
929
+ /// only the link-global and canonical fallbacks apply.
930
+ context-id: option<string>,
931
+ }
932
+
933
+ /// Response for resolve.
934
+ /// Topic: `users.v1.resolve.response`.
935
+ ///
936
+ /// A clean "no link exists" is `user = none` with `error = none`.
937
+ /// Validation or storage failures populate `error` and leave the
938
+ /// other success fields empty.
939
+ record resolve-response {
940
+ correlation-id: string,
941
+ user: option<astrid-user>,
942
+ /// The right name to address this user. Resolution order
943
+ /// (first non-empty wins):
944
+ /// 1. `context-identity.display-name` (if `context-id` was
945
+ /// provided in the request and an override exists)
946
+ /// 2. `frontend-link.display-name` (the platform-side name)
947
+ /// 3. `astrid-user.display-name` (the canonical Astrid name)
948
+ /// `None` if none of the three layers carry a name.
949
+ display-name: option<string>,
950
+ /// Which layer produced `display-name`. One of `"context"`,
951
+ /// `"link"`, `"canonical"`. `None` when `display-name` is `None`.
952
+ display-name-source: option<string>,
953
+ error: option<string>,
954
+ }
955
+
956
+ // ── Link ───────────────────────────────────────────────────────
957
+
958
+ /// Link a platform identity to an existing Astrid user. Upsert
959
+ /// semantics: an existing link for the same
960
+ /// `(platform, platform-instance?, platform-user-id)` is overwritten.
961
+ /// Topic: `users.v1.link.request`.
962
+ record link-request {
963
+ source: source,
964
+ platform: string,
965
+ platform-instance: option<string>,
966
+ platform-user-id: string,
967
+ /// Target Astrid user UUID. Must already exist.
968
+ astrid-user-id: string,
969
+ /// Audit string — how this link was established.
970
+ method: string,
971
+ /// Optional platform-side global display name at link time.
972
+ /// Stored on the resulting `frontend-link` for later
973
+ /// resolution / display.
974
+ display-name: option<string>,
975
+ }
976
+
977
+ /// Response for link.
978
+ /// Topic: `users.v1.link.response`.
979
+ record link-response {
980
+ correlation-id: string,
981
+ link: option<frontend-link>,
982
+ error: option<string>,
983
+ }
984
+
985
+ // ── Unlink ─────────────────────────────────────────────────────
986
+
987
+ /// Remove a platform link. Also clears any
988
+ /// `context-identity` overlays attached to it (cascading).
989
+ /// Topic: `users.v1.unlink.request`.
990
+ record unlink-request {
991
+ source: source,
992
+ platform: string,
993
+ platform-instance: option<string>,
994
+ platform-user-id: string,
995
+ }
996
+
997
+ /// Response for unlink.
998
+ /// Topic: `users.v1.unlink.response`.
999
+ record unlink-response {
1000
+ correlation-id: string,
1001
+ /// `true` if a link existed and was removed; `false` for a
1002
+ /// no-op delete (link was already absent).
1003
+ removed: bool,
1004
+ error: option<string>,
1005
+ }
1006
+
1007
+ // ── Create ─────────────────────────────────────────────────────
1008
+
1009
+ /// Create a new Astrid user.
1010
+ /// Topic: `users.v1.create.request`.
1011
+ record create-request {
1012
+ source: source,
1013
+ /// Optional canonical display name. Rejected if it contains
1014
+ /// `/` or `\0`.
1015
+ display-name: option<string>,
1016
+ }
1017
+
1018
+ /// Response for create.
1019
+ /// Topic: `users.v1.create.response`.
1020
+ record create-response {
1021
+ correlation-id: string,
1022
+ user: option<astrid-user>,
1023
+ error: option<string>,
1024
+ }
1025
+
1026
+ // ── Mutate canonical fields on an AstridUser ──────────────────
1027
+
1028
+ /// Change an `AstridUser`'s canonical `display-name` without
1029
+ /// rotating the UUID or breaking any links.
1030
+ /// Topic: `users.v1.set_display_name.request`.
1031
+ ///
1032
+ /// `display-name = None` clears the name. To leave it unchanged,
1033
+ /// don't issue the request.
1034
+ record set-display-name-request {
1035
+ source: source,
1036
+ astrid-user-id: string,
1037
+ display-name: option<string>,
1038
+ }
1039
+
1040
+ /// Response for set-display-name.
1041
+ /// Topic: `users.v1.set_display_name.response`.
1042
+ record set-display-name-response {
1043
+ correlation-id: string,
1044
+ user: option<astrid-user>,
1045
+ error: option<string>,
1046
+ }
1047
+
1048
+ /// Set or clear an `AstridUser`'s `public-key` without rotating
1049
+ /// the UUID.
1050
+ /// Topic: `users.v1.set_public_key.request`.
1051
+ ///
1052
+ /// `public-key = None` clears the key.
1053
+ record set-public-key-request {
1054
+ source: source,
1055
+ astrid-user-id: string,
1056
+ public-key: option<list<u8>>,
1057
+ }
1058
+
1059
+ /// Response for set-public-key.
1060
+ /// Topic: `users.v1.set_public_key.response`.
1061
+ record set-public-key-response {
1062
+ correlation-id: string,
1063
+ user: option<astrid-user>,
1064
+ error: option<string>,
1065
+ }
1066
+
1067
+ // ── Links (list every link for one user) ──────────────────────
1068
+
1069
+ /// List every platform link for one Astrid user.
1070
+ /// Topic: `users.v1.links.request`.
1071
+ record links-request {
1072
+ source: source,
1073
+ astrid-user-id: string,
1074
+ }
1075
+
1076
+ /// Response for links.
1077
+ /// Topic: `users.v1.links.response`.
1078
+ record links-response {
1079
+ correlation-id: string,
1080
+ links: list<frontend-link>,
1081
+ error: option<string>,
1082
+ }
1083
+
1084
+ // ── Get (lookup user by UUID) ─────────────────────────────────
1085
+
1086
+ /// Fetch a user record by UUID.
1087
+ /// Topic: `users.v1.get.request`.
1088
+ record get-request {
1089
+ source: source,
1090
+ astrid-user-id: string,
1091
+ }
1092
+
1093
+ /// Response for get.
1094
+ /// Topic: `users.v1.get.response`.
1095
+ record get-response {
1096
+ correlation-id: string,
1097
+ user: option<astrid-user>,
1098
+ error: option<string>,
1099
+ }
1100
+
1101
+ // ── Delete (admin) ────────────────────────────────────────────
1102
+
1103
+ /// Delete a user, every link pointing at it, and every
1104
+ /// per-context overlay tied to those links.
1105
+ /// Idempotent — deleting an absent UUID returns `deleted = false`.
1106
+ /// Topic: `users.v1.delete.request`.
1107
+ record delete-request {
1108
+ source: source,
1109
+ astrid-user-id: string,
1110
+ }
1111
+
1112
+ /// Response for delete.
1113
+ /// Topic: `users.v1.delete.response`.
1114
+ record delete-response {
1115
+ correlation-id: string,
1116
+ /// `true` when a user record existed and was deleted.
1117
+ deleted: bool,
1118
+ error: option<string>,
1119
+ }
1120
+
1121
+ // ── List users (paginated) ────────────────────────────────────
1122
+
1123
+ /// List every user record in the principal's store. Paginated.
1124
+ /// Topic: `users.v1.list.request`.
1125
+ record list-request {
1126
+ source: source,
1127
+ /// Cursor from a prior `list-response.next-cursor`. `None`
1128
+ /// on the first call.
1129
+ cursor: option<string>,
1130
+ /// Maximum users to return. `None` lets the capsule pick a
1131
+ /// sensible default (current impl: 100).
1132
+ limit: option<u32>,
1133
+ }
1134
+
1135
+ /// Response for list.
1136
+ /// Topic: `users.v1.list.response`.
1137
+ record list-response {
1138
+ correlation-id: string,
1139
+ users: list<astrid-user>,
1140
+ /// Pass back as `list-request.cursor` to get the next page.
1141
+ /// `None` when no more pages remain.
1142
+ next-cursor: option<string>,
1143
+ error: option<string>,
1144
+ }
1145
+
1146
+ // ── Context: per-context display-name overlay ─────────────────
1147
+
1148
+ /// Set (or upsert) a per-context display-name override for a
1149
+ /// linked platform identity. The underlying `frontend-link` must
1150
+ /// already exist — context overlays cannot dangle.
1151
+ /// Topic: `users.v1.context.set.request`.
1152
+ record context-set-request {
1153
+ source: source,
1154
+ platform: string,
1155
+ platform-instance: option<string>,
1156
+ platform-user-id: string,
1157
+ context-id: string,
1158
+ display-name: string,
1159
+ }
1160
+
1161
+ /// Response for context-set.
1162
+ /// Topic: `users.v1.context.set.response`.
1163
+ record context-set-response {
1164
+ correlation-id: string,
1165
+ context-identity: option<context-identity>,
1166
+ error: option<string>,
1167
+ }
1168
+
1169
+ /// Clear a per-context display-name override. Leaves the link
1170
+ /// itself and the global link-level display-name untouched.
1171
+ /// Topic: `users.v1.context.clear.request`.
1172
+ record context-clear-request {
1173
+ source: source,
1174
+ platform: string,
1175
+ platform-instance: option<string>,
1176
+ platform-user-id: string,
1177
+ context-id: string,
1178
+ }
1179
+
1180
+ /// Response for context-clear.
1181
+ /// Topic: `users.v1.context.clear.response`.
1182
+ record context-clear-response {
1183
+ correlation-id: string,
1184
+ /// `true` if an overlay existed and was removed; `false` for
1185
+ /// a no-op clear.
1186
+ removed: bool,
1187
+ error: option<string>,
1188
+ }
1189
+
1190
+ /// Fetch the per-context override for one
1191
+ /// `(link, context-id)` pair. Useful when the caller wants the
1192
+ /// raw override without the `resolve`-style fallback chain.
1193
+ /// Topic: `users.v1.context.get.request`.
1194
+ record context-get-request {
1195
+ source: source,
1196
+ platform: string,
1197
+ platform-instance: option<string>,
1198
+ platform-user-id: string,
1199
+ context-id: string,
1200
+ }
1201
+
1202
+ /// Response for context-get.
1203
+ /// Topic: `users.v1.context.get.response`.
1204
+ record context-get-response {
1205
+ correlation-id: string,
1206
+ context-identity: option<context-identity>,
1207
+ /// The same user resolved through the underlying link, when
1208
+ /// it exists. Saves the caller a separate `resolve` call.
1209
+ astrid-user-id: option<string>,
1210
+ error: option<string>,
1211
+ }
1212
+
1213
+ /// List every context overlay attached to one Astrid user, across
1214
+ /// platforms and contexts. Paginated.
1215
+ /// Topic: `users.v1.context.list_for_user.request`.
1216
+ record context-list-for-user-request {
1217
+ source: source,
1218
+ astrid-user-id: string,
1219
+ cursor: option<string>,
1220
+ limit: option<u32>,
1221
+ }
1222
+
1223
+ /// Response for context-list-for-user.
1224
+ /// Topic: `users.v1.context.list_for_user.response`.
1225
+ record context-list-for-user-response {
1226
+ correlation-id: string,
1227
+ contexts: list<context-identity>,
1228
+ next-cursor: option<string>,
1229
+ error: option<string>,
1230
+ }
1231
+
1232
+ /// List every user known in one specific context (e.g. every
1233
+ /// member of one Discord guild who has a per-guild nickname
1234
+ /// recorded). Returns the context overlay rows plus the resolved
1235
+ /// `astrid-user-id` for each, so the caller can build a member
1236
+ /// roster in one paginated call. Paginated.
1237
+ /// Topic: `users.v1.context.list_in_context.request`.
1238
+ record context-list-in-context-request {
1239
+ source: source,
1240
+ platform: string,
1241
+ platform-instance: option<string>,
1242
+ context-id: string,
1243
+ cursor: option<string>,
1244
+ limit: option<u32>,
1245
+ }
1246
+
1247
+ /// One row of the context-list-in-context response.
1248
+ record context-member {
1249
+ context-identity: context-identity,
1250
+ /// Resolved Astrid user UUID via the underlying link, when
1251
+ /// the link still exists. `None` indicates a stale overlay
1252
+ /// (link was unlinked but overlay wasn't cleared — the
1253
+ /// capsule cleans these on unlink, so this should be rare).
1254
+ astrid-user-id: option<string>,
1255
+ }
1256
+
1257
+ /// Response for context-list-in-context.
1258
+ /// Topic: `users.v1.context.list_in_context.response`.
1259
+ record context-list-in-context-response {
1260
+ correlation-id: string,
1261
+ members: list<context-member>,
1262
+ next-cursor: option<string>,
1263
+ error: option<string>,
1264
+ }
1265
+ }
1266
+