@tpsdev-ai/flair 0.52.0 → 0.54.1

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 (99) hide show
  1. package/README.md +4 -1
  2. package/dist/build-info.json +3 -3
  3. package/dist/cli.js +1914 -15328
  4. package/dist/commands/agent.js +453 -0
  5. package/dist/commands/attention.js +121 -0
  6. package/dist/commands/backup.js +115 -0
  7. package/dist/commands/bootstrap.js +91 -0
  8. package/dist/commands/bridge.js +608 -0
  9. package/dist/commands/deploy.js +180 -0
  10. package/dist/commands/doctor.js +1654 -0
  11. package/dist/commands/export.js +110 -0
  12. package/dist/commands/federation.js +1575 -0
  13. package/dist/commands/fleet.js +73 -0
  14. package/dist/commands/grant.js +109 -0
  15. package/dist/commands/hook.js +193 -0
  16. package/dist/commands/idp.js +193 -0
  17. package/dist/commands/import.js +134 -0
  18. package/dist/commands/init.js +1203 -0
  19. package/dist/commands/inspect.js +45 -0
  20. package/dist/commands/keys.js +187 -0
  21. package/dist/commands/mcp.js +707 -0
  22. package/dist/commands/memory.js +501 -0
  23. package/dist/commands/migrate-harness-memory.js +270 -0
  24. package/dist/commands/orgevent.js +138 -0
  25. package/dist/commands/presence.js +76 -0
  26. package/dist/commands/principal.js +338 -0
  27. package/dist/commands/quality.js +1164 -0
  28. package/dist/commands/reembed.js +296 -0
  29. package/dist/commands/relationship.js +76 -0
  30. package/dist/commands/rem.js +1048 -0
  31. package/dist/commands/restore.js +130 -0
  32. package/dist/commands/search.js +244 -0
  33. package/dist/commands/service.js +315 -0
  34. package/dist/commands/session.js +184 -0
  35. package/dist/commands/soul.js +155 -0
  36. package/dist/commands/status.js +914 -0
  37. package/dist/commands/test.js +93 -0
  38. package/dist/commands/uninstall.js +143 -0
  39. package/dist/commands/upgrade.js +1592 -0
  40. package/dist/commands/workspace.js +114 -0
  41. package/dist/deploy.js +24 -0
  42. package/dist/fabric-npm-install.js +87 -0
  43. package/dist/federation-verify.js +498 -0
  44. package/dist/fleet-verify.js +144 -21
  45. package/dist/install/clients.js +167 -0
  46. package/dist/lib/auth-resolve.js +76 -1
  47. package/dist/lib/daemon-liveness.js +131 -2
  48. package/dist/lib/doctor-config-path.js +61 -0
  49. package/dist/lib/doctor-federation-driver.js +189 -0
  50. package/dist/lib/doctor-run.js +40 -0
  51. package/dist/lib/entity-vocab-cli.js +3 -3
  52. package/dist/lib/federation-pair-identity.js +47 -0
  53. package/dist/lib/launchd-repair.js +199 -0
  54. package/dist/lib/ops-api-bind.js +115 -0
  55. package/dist/lib/owned-pins.js +219 -0
  56. package/dist/lib/stabilize-mqtt-network.js +123 -0
  57. package/dist/lib/uninstall-purge.js +218 -0
  58. package/dist/rem/restore.js +8 -10
  59. package/dist/resources/AgentReadPosition.js +74 -0
  60. package/dist/resources/Federation.js +8 -2
  61. package/dist/resources/Memory.js +4 -3
  62. package/dist/resources/MemoryBootstrap.js +41 -25
  63. package/dist/resources/MemoryCandidate.js +5 -6
  64. package/dist/resources/OrgEventCatchup.js +126 -47
  65. package/dist/resources/agent-read-position-lib.js +83 -0
  66. package/dist/resources/agent-read-position.js +120 -0
  67. package/dist/resources/embeddings-boot.js +32 -0
  68. package/dist/resources/federation-peer-liveness.js +73 -0
  69. package/dist/resources/health.js +68 -19
  70. package/dist/resources/mcp-tools.js +43 -279
  71. package/dist/resources/memory-visibility.js +3 -3
  72. package/dist/resources/migration-boot.js +59 -18
  73. package/dist/resources/migrations/embedding-stamp.js +20 -1
  74. package/dist/resources/migrations/recheck.js +43 -0
  75. package/dist/resources/migrations/runner.js +6 -1
  76. package/dist/resources/migrations/stamp-outstanding.js +171 -0
  77. package/dist/resources/migrations/visibility-backfill.js +2 -2
  78. package/dist/resources/org-event-catchup-lib.js +47 -0
  79. package/dist/resources/record-owner-guard.js +1 -0
  80. package/dist/stamp-migration-verify.js +163 -0
  81. package/dist/stamp-outstanding.js +144 -0
  82. package/docs/api-reference.md +4 -2
  83. package/docs/deploying-on-fabric.md +11 -10
  84. package/docs/deployment.md +3 -1
  85. package/docs/federation.md +19 -0
  86. package/docs/hosted-on-fabric.md +3 -3
  87. package/docs/quickstart.md +2 -1
  88. package/docs/releasing.md +15 -7
  89. package/docs/spoke-bringup.md +10 -5
  90. package/docs/standalone-local.md +3 -1
  91. package/docs/upgrade.md +25 -6
  92. package/node_modules/@tpsdev-ai/flair-tool-descriptors/LICENSE +19 -0
  93. package/node_modules/@tpsdev-ai/flair-tool-descriptors/README.md +22 -0
  94. package/node_modules/@tpsdev-ai/flair-tool-descriptors/dist/index.d.ts +70 -0
  95. package/node_modules/@tpsdev-ai/flair-tool-descriptors/dist/index.js +665 -0
  96. package/node_modules/@tpsdev-ai/flair-tool-descriptors/package.json +46 -0
  97. package/package.json +9 -4
  98. package/schemas/agent.graphql +15 -0
  99. package/templates/launchd/start-flair-with-admin-pass.sh +73 -0
@@ -0,0 +1,665 @@
1
+ /**
2
+ * Transport-agnostic MCP tool descriptors (flair#1580).
3
+ *
4
+ * Pure data + types: name, description, inputSchema, output shape, and
5
+ * reviewed surface flags. No Harper, no FlairClient, no Zod, no HTTP.
6
+ *
7
+ * The server TOOLS registry binds each native descriptor to its Harper impl.
8
+ * The flair-mcp stdio adapter binds each stdio descriptor to a FlairClient
9
+ * call. Both tool sets are DERIVED from this list — a new descriptor appears
10
+ * on every surface that lists it, with zero hand-wiring.
11
+ */
12
+ export function isNativeTool(d) {
13
+ return d.native !== false;
14
+ }
15
+ export function isStdioTool(d) {
16
+ return d.stdio !== false;
17
+ }
18
+ export function toMcpToolDef(d) {
19
+ return {
20
+ name: d.name,
21
+ description: d.description,
22
+ inputSchema: d.inputSchema,
23
+ ...(d.annotations ? { annotations: d.annotations } : {}),
24
+ };
25
+ }
26
+ /** Native tools/list def, minus reviewed stdio-only omissions. */
27
+ export function toStdioMcpToolDef(d) {
28
+ const omit = new Set(d.stdioOmitProperties ?? []);
29
+ const properties = { ...d.inputSchema.properties, ...(d.stdioExtraProperties ?? {}) };
30
+ for (const key of omit)
31
+ delete properties[key];
32
+ const required = (d.inputSchema.required ?? []).filter((k) => !omit.has(k));
33
+ return {
34
+ name: d.name,
35
+ description: d.stdioDescription ?? d.description,
36
+ inputSchema: {
37
+ type: "object",
38
+ properties,
39
+ ...(required.length > 0 ? { required } : {}),
40
+ },
41
+ ...(d.annotations ? { annotations: d.annotations } : {}),
42
+ };
43
+ }
44
+ export function descriptorNames(descriptors) {
45
+ return descriptors.map((d) => d.name);
46
+ }
47
+ export const TOOL_DESCRIPTORS = [
48
+ {
49
+ "name": "memory_search",
50
+ "description": "Search memories by meaning. Understands temporal queries like 'what happened today'. Scoped to your agent's own + granted memories.",
51
+ "inputSchema": {
52
+ "type": "object",
53
+ "properties": {
54
+ "query": {
55
+ "type": "string",
56
+ "description": "Search query — natural language, semantic matching"
57
+ },
58
+ "limit": {
59
+ "type": "number",
60
+ "description": "Max results (default 5)"
61
+ },
62
+ "includeTrust": {
63
+ "type": "boolean",
64
+ "description": "Attach a per-result trust-evidence block (provenance, author, usage, freshness, supersession). Default false."
65
+ },
66
+ "abstain": {
67
+ "type": "boolean",
68
+ "description": "Opt into first-class abstention: when the best match is below a global confidence threshold, return { abstained: true, reason, bestScore } with no weak matches instead of the N weakest results. Default false."
69
+ },
70
+ "includeArchived": {
71
+ "type": "boolean",
72
+ "description": "Include basemented (archived) memories in results. Default false — archived memories are excluded from normal search. When true, archived memories are returned under the SAME read-scope gate as a normal search (never a wider scope)."
73
+ }
74
+ },
75
+ "required": [
76
+ "query"
77
+ ]
78
+ },
79
+ "outputShape": "{ results: MemoryRecord[] } — semantic hits scoped to the caller's own + granted memories; each hit carries content, never the raw embedding.",
80
+ "annotations": {
81
+ "readOnlyHint": true
82
+ },
83
+ "stdioOmitProperties": [
84
+ "includeTrust",
85
+ "abstain",
86
+ "includeArchived"
87
+ ]
88
+ },
89
+ {
90
+ "name": "memory_store",
91
+ "description": "Save information to persistent memory. Use for lessons, decisions, preferences, facts. Attributed to your authenticated agent.",
92
+ "inputSchema": {
93
+ "type": "object",
94
+ "properties": {
95
+ "content": {
96
+ "type": "string",
97
+ "description": "What to remember"
98
+ },
99
+ "type": {
100
+ "type": "string",
101
+ "enum": [
102
+ "session",
103
+ "lesson",
104
+ "decision",
105
+ "preference",
106
+ "fact",
107
+ "goal"
108
+ ],
109
+ "description": "Memory type (default session)"
110
+ },
111
+ "durability": {
112
+ "type": "string",
113
+ "enum": [
114
+ "permanent",
115
+ "persistent",
116
+ "standard",
117
+ "ephemeral"
118
+ ],
119
+ "description": "permanent > persistent > standard > ephemeral (default standard)"
120
+ },
121
+ "tags": {
122
+ "type": "array",
123
+ "items": {
124
+ "type": "string"
125
+ },
126
+ "description": "Tag strings"
127
+ },
128
+ "visibility": {
129
+ "type": "string",
130
+ "enum": [
131
+ "private",
132
+ "shared"
133
+ ],
134
+ "description": "Writer-controlled sharing intent. Omit to use the server's durability-keyed default: permanent/persistent -> shared, standard/ephemeral -> private. private — owner-only, never visible to another agent, even one holding a memory grant. shared — visible to the owner and every other agent on this instance. The visibility the write actually landed on is returned in the result."
135
+ },
136
+ "usedMemoryIds": {
137
+ "type": "array",
138
+ "items": {
139
+ "type": "string"
140
+ },
141
+ "description": "IDs of memories that informed this write (citation-on-write). Credited via the same deduped usage ledger as record_usage. Optional."
142
+ }
143
+ },
144
+ "required": [
145
+ "content"
146
+ ]
147
+ },
148
+ "outputShape": "Write echo { id, written:true, deduplicated } — the new id + confirmation. No internal embedding fields; round-trips via memory_get."
149
+ },
150
+ {
151
+ "name": "skill_store",
152
+ "description": "Write a skill (a reusable capability/procedure) as a skill-tagged memory. The `trigger` text is what the skill embeds from (the recall signal — 'when to use this'), and `content` is the full procedure. Skills are forced durability=persistent and are SkillScan-gated before the embed (a dangerous shell/network payload is rejected).",
153
+ "inputSchema": {
154
+ "type": "object",
155
+ "properties": {
156
+ "content": {
157
+ "type": "string",
158
+ "description": "The full procedure (markdown body of the SKILL.md)"
159
+ },
160
+ "trigger": {
161
+ "type": "string",
162
+ "description": "The 'when to use' text — the recall signal the skill embeds from"
163
+ },
164
+ "name": {
165
+ "type": "string",
166
+ "description": "Skill name (SKILL.md frontmatter; stored in metadata)"
167
+ },
168
+ "description": {
169
+ "type": "string",
170
+ "description": "Skill description (SKILL.md frontmatter; stored in metadata)"
171
+ },
172
+ "tags": {
173
+ "type": "array",
174
+ "items": {
175
+ "type": "string"
176
+ },
177
+ "description": "Additional tags (the 'skill' tag is added automatically)"
178
+ }
179
+ },
180
+ "required": [
181
+ "content"
182
+ ]
183
+ },
184
+ "outputShape": "Write echo { id, written:true, deduplicated } for the skill-tagged memory. No internal embedding fields; round-trips via memory_get."
185
+ },
186
+ {
187
+ "name": "skill_search",
188
+ "description": "Find skills (reusable capabilities/procedures) that apply to a task. Ranks skill-tagged memories by their `trigger` ('when to use') against your task text. Returns a lightweight CATALOG — id, name, trigger, description, tags, agentId — NOT the full procedure (fetch that with skill_get). Scoped to your own + shared skills; another agent's private skill is never returned.",
189
+ "inputSchema": {
190
+ "type": "object",
191
+ "properties": {
192
+ "task": {
193
+ "type": "string",
194
+ "description": "The task/context to match skills against — natural language; ranked against each skill's trigger"
195
+ },
196
+ "limit": {
197
+ "type": "number",
198
+ "description": "Max skills to return (default 5)"
199
+ }
200
+ },
201
+ "required": [
202
+ "task"
203
+ ]
204
+ },
205
+ "outputShape": "{ results: SkillCard[] } — the skill catalog (lightweight id/name/trigger/description/tags/agentId, ranked by trigger match); the full procedure and the raw embedding are never on a card. Scoped to the caller's own + non-private skills; another agent's private skill is never returned.",
206
+ "annotations": {
207
+ "readOnlyHint": true
208
+ }
209
+ },
210
+ {
211
+ "name": "skill_get",
212
+ "description": "Retrieve a full skill by ID — the complete procedure (`content`) plus trigger and metadata. The disclosure step after skill_search's catalog. Read-scoped: you can only get your own or a shared skill, never another agent's private skill. A non-skill id returns not-found. The raw embedding vector is never returned.",
213
+ "inputSchema": {
214
+ "type": "object",
215
+ "properties": {
216
+ "id": {
217
+ "type": "string",
218
+ "description": "Skill (memory) ID"
219
+ }
220
+ },
221
+ "required": [
222
+ "id"
223
+ ]
224
+ },
225
+ "outputShape": "The full skill record { id, agentId, content, trigger, tags, durability, metadata, createdAt, ... } for a skill readable under the caller's read-scope — embedding + embeddingModel always stripped. A non-owner cannot read another agent's private skill, and a readable non-skill id is not found (both 404).",
226
+ "annotations": {
227
+ "readOnlyHint": true
228
+ }
229
+ },
230
+ {
231
+ "name": "memory_update",
232
+ "description": "Update an existing memory by ID. Dedup-bypassed (this is an intentional overwrite, not a new write). Default: overwrites the same id in place. Pass preserveHistory=true to instead write a new version linked via `supersedes`, closing the old one's validity window.",
233
+ "inputSchema": {
234
+ "type": "object",
235
+ "properties": {
236
+ "id": {
237
+ "type": "string",
238
+ "description": "ID of the memory to update"
239
+ },
240
+ "content": {
241
+ "type": "string",
242
+ "description": "New content"
243
+ },
244
+ "preserveHistory": {
245
+ "type": "boolean",
246
+ "description": "Write a new version (supersedes-linked) instead of overwriting in place (default false)"
247
+ }
248
+ },
249
+ "required": [
250
+ "id",
251
+ "content"
252
+ ]
253
+ },
254
+ "outputShape": "Write echo { id, written:true } for the in-place overwrite (or supersede). No internal embedding fields; the change round-trips via memory_get.",
255
+ "stdioExtraProperties": {
256
+ "usedMemoryIds": {
257
+ "type": "array",
258
+ "items": {
259
+ "type": "string"
260
+ },
261
+ "description": "IDs of memories that informed this update (citation-on-write). Credited via the same deduped usage ledger as record_usage. Optional."
262
+ }
263
+ }
264
+ },
265
+ {
266
+ "name": "memory_basement",
267
+ "description": "Send a memory to the basement (archive it). Sets archived=true and stamps archivedAt. The memory is removed from bootstrap and default search but remains retrievable via memory_get and memory_search(includeArchived:true). Deliberate and GLOBAL — this is a visibility flag, not a deletion: provenance and history are untouched. Scoped to your own memories only.",
268
+ "inputSchema": {
269
+ "type": "object",
270
+ "properties": {
271
+ "id": {
272
+ "type": "string",
273
+ "description": "ID of the memory to basement (archive)"
274
+ }
275
+ },
276
+ "required": [
277
+ "id"
278
+ ]
279
+ },
280
+ "outputShape": "Write echo of the archived record { id, archived:true, archivedAt, ... }. No internal embedding fields; the flip round-trips via memory_get.",
281
+ "stdio": false
282
+ },
283
+ {
284
+ "name": "memory_restore",
285
+ "description": "Restore a basemented (archived) memory. Clears archived and archivedAt. Deliberate and GLOBAL — this un-retires the memory for EVERY session, not a session-local view (per-session reuse is drawers, which do not exist yet). Scoped to your own memories only.",
286
+ "inputSchema": {
287
+ "type": "object",
288
+ "properties": {
289
+ "id": {
290
+ "type": "string",
291
+ "description": "ID of the memory to restore (un-archive)"
292
+ }
293
+ },
294
+ "required": [
295
+ "id"
296
+ ]
297
+ },
298
+ "outputShape": "Write echo of the restored record { id, archived:false, ... }. No internal embedding fields; the flip round-trips via memory_get.",
299
+ "stdio": false
300
+ },
301
+ {
302
+ "name": "memory_get",
303
+ "description": "Retrieve a specific memory by ID. The record's raw embedding vector is omitted by default (it is large and not useful to a caller); pass includeEmbedding=true to include it.",
304
+ "inputSchema": {
305
+ "type": "object",
306
+ "properties": {
307
+ "id": {
308
+ "type": "string",
309
+ "description": "Memory ID"
310
+ },
311
+ "includeTrust": {
312
+ "type": "boolean",
313
+ "description": "Attach a trust-evidence block (provenance, author, usage, freshness, supersession) to the record. Default false."
314
+ },
315
+ "includeEmbedding": {
316
+ "type": "boolean",
317
+ "description": "Include the raw embedding vector (hundreds of floats) in the returned record. Omitted by default because it is large and rarely useful to a caller. Default false."
318
+ }
319
+ },
320
+ "required": [
321
+ "id"
322
+ ]
323
+ },
324
+ "outputShape": "The full memory record { id, agentId, content, durability, createdAt, ... } for the caller's own id — embedding + embeddingModel stripped by default.",
325
+ "annotations": {
326
+ "readOnlyHint": true
327
+ },
328
+ "stdioOmitProperties": [
329
+ "includeTrust",
330
+ "includeEmbedding"
331
+ ]
332
+ },
333
+ {
334
+ "name": "memory_delete",
335
+ "description": "Delete a memory by ID. You can only delete your own memories.",
336
+ "inputSchema": {
337
+ "type": "object",
338
+ "properties": {
339
+ "id": {
340
+ "type": "string",
341
+ "description": "Memory ID to delete"
342
+ }
343
+ },
344
+ "required": [
345
+ "id"
346
+ ]
347
+ },
348
+ "outputShape": "Deletes the caller's own memory at any durability tier (success echo is thin). Cross-owner deletion returns { error, status:403 } for a non-admin; a deleted row round-trips as gone via memory_get.",
349
+ "annotations": {
350
+ "destructiveHint": true
351
+ }
352
+ },
353
+ {
354
+ "name": "relationship_store",
355
+ "description": "Record that <subject> <predicate> <object> — an explicit entity-to-entity relationship triple (e.g. 'nathan manages flair', 'flint reviews cli'), distinct from a free-text memory. ASSERT/UPSERT semantics: writing the SAME triple again (same subject/predicate/object) updates the existing row in place (confidence/validTo/source refresh) rather than creating a duplicate — safe to re-assert. Predicate is free text (no fixed enum) but prefer a small, consistent vocabulary so the graph stays queryable: manages, works_on, reviews, depends_on, replaces, owns, reports_to, advises. TO CONTRADICT a prior relationship: (a) re-asserting the identical triple just updates it — fine. (b) changing validTo on the SAME subject/predicate/object overwrites the old validTo (the graph tracks current state, not full history). (c) changing the PREDICATE (e.g. 'nathan manages flair' -> 'nathan advises flair') creates a SEPARATE relationship — it does NOT automatically close the old one. Close it yourself first: re-assert the OLD triple with a validTo set to now (or call relationship's delete), THEN store the new one.",
356
+ "inputSchema": {
357
+ "type": "object",
358
+ "properties": {
359
+ "subject": {
360
+ "type": "string",
361
+ "description": "Source entity — a person, project, or service (e.g. 'nathan')"
362
+ },
363
+ "predicate": {
364
+ "type": "string",
365
+ "description": "Relationship type, free text. Recommended vocabulary: manages, works_on, reviews, depends_on, replaces, owns, reports_to, advises — consistency helps recall, but any short verb phrase works."
366
+ },
367
+ "object": {
368
+ "type": "string",
369
+ "description": "Target entity — a person, project, or service (e.g. 'flair')"
370
+ },
371
+ "confidence": {
372
+ "type": "number",
373
+ "description": "0.0-1.0, how certain (default 1.0 = explicitly stated)"
374
+ },
375
+ "validFrom": {
376
+ "type": "string",
377
+ "description": "ISO timestamp this relationship became true (default: now)"
378
+ },
379
+ "validTo": {
380
+ "type": "string",
381
+ "description": "ISO timestamp this relationship ended. Leave unset for an active relationship; set it (via a re-assert of this SAME subject/predicate/object) to close out a relationship you're contradicting with a new predicate."
382
+ },
383
+ "source": {
384
+ "type": "string",
385
+ "description": "Where this was learned from (a memory ID, conversation, etc.)"
386
+ }
387
+ },
388
+ "required": [
389
+ "subject",
390
+ "predicate",
391
+ "object"
392
+ ]
393
+ },
394
+ "outputShape": "Write echo { id, subject, predicate, object, written:true } for the asserted triple. Persistence is verified in storage.",
395
+ "native": false
396
+ },
397
+ {
398
+ "name": "bootstrap",
399
+ "description": "Get session context: soul + memories + predicted context. Run at session start. Pass subjects for predictive loading.",
400
+ "inputSchema": {
401
+ "type": "object",
402
+ "properties": {
403
+ "maxTokens": {
404
+ "type": "number",
405
+ "description": "Content-selection budget in tokens (default 4000): the hard cap on how much soul/memory/finding CONTENT is selected. The actual serialized response (reported by tokenEstimate) may exceed this by the structured-container JSON scaffolding — maxTokens bounds what is selected, not the raw output size. Raise it to include more content."
406
+ },
407
+ "currentTask": {
408
+ "type": "string",
409
+ "description": "Current task — enables semantic search for relevant memories"
410
+ },
411
+ "channel": {
412
+ "type": "string",
413
+ "description": "Channel name (discord, tps-mail, claude-code)"
414
+ },
415
+ "surface": {
416
+ "type": "string",
417
+ "description": "Surface name (tps-build, tps-review, cli-session)"
418
+ },
419
+ "subjects": {
420
+ "type": "array",
421
+ "items": {
422
+ "type": "string"
423
+ },
424
+ "description": "Entity names to preload context for"
425
+ },
426
+ "entities": {
427
+ "type": "array",
428
+ "items": {
429
+ "type": "string"
430
+ },
431
+ "description": "Your declared attention-plane vocabulary strings (e.g. \"issue:owner/repo#123\") for collision surfacing's 'Others in the room' block — teammates with overlapping active work. Falls back to your own most-recent workspace-state entities when omitted."
432
+ },
433
+ "includeTrust": {
434
+ "type": "boolean",
435
+ "description": "Also return a `trust` array with a per-included-memory trust-evidence block (provenance, author, usage, freshness, supersession). Default false."
436
+ },
437
+ "abstain": {
438
+ "type": "boolean",
439
+ "description": "Opt into a task-relevance abstention verdict: also return an `abstention` object ({ abstained, bestScore, threshold }) reporting whether any memory covered `currentTask` above a global confidence threshold. Default false."
440
+ },
441
+ "includeContext": {
442
+ "type": "boolean",
443
+ "description": "Also return the prose `context` string — a human-readable mirror of the structured soul/memories/predicted/teammateFindings containers (which are the canonical payload). Default false here: the structured fields already carry everything, so shipping the prose too would double the payload."
444
+ },
445
+ "maxEvents": {
446
+ "type": "number",
447
+ "description": "Display cap on how many org events to return (default 10). Not a silent drop: leftover events set eventsHasMore/eventsRemaining so the caller can page GET /OrgEventCatchup. Counted against maxTokens like every other content section."
448
+ },
449
+ "includeEventDetail": {
450
+ "type": "boolean",
451
+ "description": "Also include each org event's verbose `detail` JSON (migration internals, etc.). Default false: bootstrap ships lean events (id/kind/summary/createdAt/targetIds/scope); `detail` mostly restates the summary and is pure bloat for a connector."
452
+ }
453
+ }
454
+ },
455
+ "outputShape": "Session context: { agentId, soul, memories, predicted, teammateFindings, events, sections, tokenEstimate, memoriesIncluded, ..., context, flairVersion }. Structured containers are canonical and always present; prose `context` is a pointer at the /mcp default (includeContext opt-in).",
456
+ "annotations": {
457
+ "readOnlyHint": true
458
+ },
459
+ "stdioOmitProperties": [
460
+ "entities",
461
+ "includeTrust",
462
+ "abstain",
463
+ "includeContext",
464
+ "maxEvents",
465
+ "includeEventDetail"
466
+ ]
467
+ },
468
+ {
469
+ "name": "soul_set",
470
+ "description": "Soul changes require operator credentials through the REST API or CLI; runtime tool calls are refused.",
471
+ "inputSchema": {
472
+ "type": "object",
473
+ "properties": {
474
+ "key": {
475
+ "type": "string",
476
+ "description": "Entry key (e.g. 'role', 'standards', 'project')"
477
+ },
478
+ "value": {
479
+ "type": "string",
480
+ "description": "Entry value"
481
+ }
482
+ },
483
+ "required": [
484
+ "key",
485
+ "value"
486
+ ]
487
+ },
488
+ "outputShape": "Refuses runtime Soul writes, including admin-agent delegation, with { error, status:403 }. Operators use the authenticated REST or CLI path.",
489
+ "stdioDescription": "Set a personality or project context entry. Included in every bootstrap."
490
+ },
491
+ {
492
+ "name": "soul_get",
493
+ "description": "Get a personality or project context entry.",
494
+ "inputSchema": {
495
+ "type": "object",
496
+ "properties": {
497
+ "key": {
498
+ "type": "string",
499
+ "description": "Entry key"
500
+ }
501
+ },
502
+ "required": [
503
+ "key"
504
+ ]
505
+ },
506
+ "outputShape": "The soul entry { id, agentId, key, value, createdAt } for the caller's own `${agentId}:${key}`.",
507
+ "annotations": {
508
+ "readOnlyHint": true
509
+ }
510
+ },
511
+ {
512
+ "name": "flair_workspace_set",
513
+ "description": "Set your agent's current workspace state in the Office Space coordination layer. Attributed to you — you can only write your own state.",
514
+ "inputSchema": {
515
+ "type": "object",
516
+ "properties": {
517
+ "ref": {
518
+ "type": "string",
519
+ "description": "Workspace ref — branch, worktree, or task ref"
520
+ },
521
+ "label": {
522
+ "type": "string",
523
+ "description": "Human-readable label"
524
+ },
525
+ "provider": {
526
+ "type": "string",
527
+ "description": "Provider/runtime (default mcp)"
528
+ },
529
+ "task": {
530
+ "type": "string",
531
+ "description": "Task/issue id"
532
+ },
533
+ "phase": {
534
+ "type": "string",
535
+ "description": "Current phase (design, implement, review)"
536
+ },
537
+ "summary": {
538
+ "type": "string",
539
+ "description": "Short summary of current state"
540
+ }
541
+ },
542
+ "required": [
543
+ "ref"
544
+ ]
545
+ },
546
+ "outputShape": "Writes the caller's workspace state keyed `${agentId}:${ref}`, attributed to the caller (never the body). The echo is thin; persistence is verified in storage."
547
+ },
548
+ {
549
+ "name": "flair_orgevent",
550
+ "description": "Publish an org-wide coordination event (claim/release/status) to the Office Space. Attributed to you — you cannot publish as another agent.",
551
+ "inputSchema": {
552
+ "type": "object",
553
+ "properties": {
554
+ "kind": {
555
+ "type": "string",
556
+ "description": "Event kind (coord.claim, coord.release, status)"
557
+ },
558
+ "summary": {
559
+ "type": "string",
560
+ "description": "Short summary of the event"
561
+ },
562
+ "detail": {
563
+ "type": "string",
564
+ "description": "Longer detail payload"
565
+ },
566
+ "scope": {
567
+ "type": "string",
568
+ "description": "Scope (an agent id, repo, or 'org')"
569
+ },
570
+ "targets": {
571
+ "type": "array",
572
+ "items": {
573
+ "type": "string"
574
+ },
575
+ "description": "Recipient agent ids"
576
+ }
577
+ },
578
+ "required": [
579
+ "kind",
580
+ "summary"
581
+ ]
582
+ },
583
+ "outputShape": "Publishes an org event attributed to the caller (authorId from identity, never the body). The echo is thin; persistence is verified in storage."
584
+ },
585
+ {
586
+ "name": "flair_catchup",
587
+ "description": "Drain YOUR OWN catch-up feed — org events directed to you (or broadcast) after your durable watermark. Returns a page plus a `nextAfter` cursor: page with `after`, then advance the watermark with `ack`. Owner-scoped: the participant is your signed identity, so you can only ever read your own feed — there is no agentId parameter and any other feed is refused (403). At-least-once: an event may arrive twice (re-delivery is safe), an acked event does not re-deliver, and an un-acked event survives a restart.",
588
+ "inputSchema": {
589
+ "type": "object",
590
+ "properties": {
591
+ "after": {
592
+ "type": "string",
593
+ "description": "Exclusive position cursor to read from. Omit to start at your durable watermark. Pass a prior page's `nextAfter` to continue a drain WITHOUT advancing the watermark."
594
+ },
595
+ "limit": {
596
+ "type": "number",
597
+ "description": "Max events per page (server default 50, max 500)."
598
+ },
599
+ "ack": {
600
+ "type": "string",
601
+ "description": "Position to acknowledge — advances your durable watermark, monotonically (never rewinds). Pass the last event position you processed, or `nextAfter` once a page is drained. Omit to read without advancing: events stay queued and survive a restart. Re-acking is safe."
602
+ }
603
+ }
604
+ },
605
+ "outputShape": "{ events: OrgEvent[], after, nextAfter, watermark, hasMore, pageSize, acked? } — the caller's own directed + broadcast events after its durable watermark, paged; `ack` advances the watermark monotonically (at-least-once — re-delivery is safe).",
606
+ "native": false
607
+ },
608
+ {
609
+ "name": "attention",
610
+ "description": "What's touching entity E in the last N days? A unified, grouped-by-source view across memories, relationships, active work (WorkspaceState), teammate presence, and org events. Entity must be a vocabulary string (e.g. 'repo:owner/name', 'issue:owner/repo#123', 'subsystem:embeddings').",
611
+ "inputSchema": {
612
+ "type": "object",
613
+ "properties": {
614
+ "entity": {
615
+ "type": "string",
616
+ "description": "Vocabulary string, exact match (type:value — e.g. 'repo:tpsdev-ai/flair')"
617
+ },
618
+ "days": {
619
+ "type": "number",
620
+ "description": "Window size in days (default 7)"
621
+ }
622
+ },
623
+ "required": [
624
+ "entity"
625
+ ]
626
+ },
627
+ "outputShape": "Grouped-by-source view { entity, windowDays, since, groups:{memory,relationship,workspaceState,presence,orgEvent}, counts } for entity E over N days.",
628
+ "annotations": {
629
+ "readOnlyHint": true
630
+ },
631
+ "stdio": false
632
+ },
633
+ {
634
+ "name": "record_usage",
635
+ "description": "Report that one or more memories were actually USED — cited or relied on to ground an answer or decision. Distinct from search (surfacing a memory is not usage). Drives the recall-quality usage signal; dedup'd (you can only count once per memory) and rate-limited. When both memoryId and memoryIds are supplied they are merged (union, then deduped) — a caller who passes both means both.",
636
+ "inputSchema": {
637
+ "type": "object",
638
+ "properties": {
639
+ "memoryIds": {
640
+ "type": "array",
641
+ "items": {
642
+ "type": "string"
643
+ },
644
+ "description": "IDs of the memories that were used (max 20 per call). Merged with memoryId when both are supplied."
645
+ },
646
+ "memoryId": {
647
+ "type": "string",
648
+ "description": "Convenience alias for a single memory id. Merged with memoryIds when both are supplied — not dropped."
649
+ },
650
+ "attribution": {
651
+ "type": "string",
652
+ "description": "Optional free-text note on what used it (opaque — stored for audit only, max 500 chars)"
653
+ }
654
+ }
655
+ },
656
+ "outputShape": "Invariant acknowledgement { recorded:true } — byte-identical regardless of how many ids counted (no id enumeration, Sherlock)."
657
+ },
658
+ ];
659
+ export const NATIVE_TOOL_DESCRIPTORS = TOOL_DESCRIPTORS.filter(isNativeTool);
660
+ export const STDIO_TOOL_DESCRIPTORS = TOOL_DESCRIPTORS.filter(isStdioTool);
661
+ /** Derived #1578 exemption list — one-sided by construction, not hand-synced. */
662
+ export const SURFACE_EXEMPTIONS = {
663
+ registryOnly: descriptorNames(TOOL_DESCRIPTORS.filter((d) => isNativeTool(d) && !isStdioTool(d))),
664
+ adapterOnly: descriptorNames(TOOL_DESCRIPTORS.filter((d) => isStdioTool(d) && !isNativeTool(d))),
665
+ };