pilotswarm-sdk 0.2.0 → 0.2.2

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 (173) hide show
  1. package/dist/agent-loader.d.ts +9 -0
  2. package/dist/agent-loader.d.ts.map +1 -1
  3. package/dist/agent-loader.js +3 -0
  4. package/dist/agent-loader.js.map +1 -1
  5. package/dist/child-notifications.d.ts +10 -0
  6. package/dist/child-notifications.d.ts.map +1 -1
  7. package/dist/child-notifications.js +15 -1
  8. package/dist/child-notifications.js.map +1 -1
  9. package/dist/client.d.ts +2 -2
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +14 -20
  12. package/dist/client.js.map +1 -1
  13. package/dist/cms-migrations.d.ts.map +1 -1
  14. package/dist/cms-migrations.js +321 -0
  15. package/dist/cms-migrations.js.map +1 -1
  16. package/dist/cms.d.ts +132 -8
  17. package/dist/cms.d.ts.map +1 -1
  18. package/dist/cms.js +142 -6
  19. package/dist/cms.js.map +1 -1
  20. package/dist/duroxide-schema-migration.d.ts +19 -0
  21. package/dist/duroxide-schema-migration.d.ts.map +1 -0
  22. package/dist/duroxide-schema-migration.js +122 -0
  23. package/dist/duroxide-schema-migration.js.map +1 -0
  24. package/dist/facts-migrations.d.ts.map +1 -1
  25. package/dist/facts-migrations.js +923 -0
  26. package/dist/facts-migrations.js.map +1 -1
  27. package/dist/facts-store.d.ts +278 -28
  28. package/dist/facts-store.d.ts.map +1 -1
  29. package/dist/facts-store.js +262 -32
  30. package/dist/facts-store.js.map +1 -1
  31. package/dist/facts-tools.d.ts +8 -1
  32. package/dist/facts-tools.d.ts.map +1 -1
  33. package/dist/facts-tools.js +458 -25
  34. package/dist/facts-tools.js.map +1 -1
  35. package/dist/graph-store.d.ts +243 -0
  36. package/dist/graph-store.d.ts.map +1 -0
  37. package/dist/graph-store.js +63 -0
  38. package/dist/graph-store.js.map +1 -0
  39. package/dist/graph-tools.d.ts +47 -0
  40. package/dist/graph-tools.d.ts.map +1 -0
  41. package/dist/graph-tools.js +554 -0
  42. package/dist/graph-tools.js.map +1 -0
  43. package/dist/horizon-env.d.ts +61 -0
  44. package/dist/horizon-env.d.ts.map +1 -0
  45. package/dist/horizon-env.js +120 -0
  46. package/dist/horizon-env.js.map +1 -0
  47. package/dist/index.d.ts +15 -4
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +10 -2
  50. package/dist/index.js.map +1 -1
  51. package/dist/inspect-tools.d.ts +2 -2
  52. package/dist/inspect-tools.d.ts.map +1 -1
  53. package/dist/inspect-tools.js +303 -6
  54. package/dist/inspect-tools.js.map +1 -1
  55. package/dist/knowledge-index.d.ts +33 -2
  56. package/dist/knowledge-index.d.ts.map +1 -1
  57. package/dist/knowledge-index.js +90 -19
  58. package/dist/knowledge-index.js.map +1 -1
  59. package/dist/managed-session.d.ts.map +1 -1
  60. package/dist/managed-session.js +61 -2
  61. package/dist/managed-session.js.map +1 -1
  62. package/dist/management-client.d.ts +81 -3
  63. package/dist/management-client.d.ts.map +1 -1
  64. package/dist/management-client.js +97 -20
  65. package/dist/management-client.js.map +1 -1
  66. package/dist/orchestration/agents.d.ts +4 -1
  67. package/dist/orchestration/agents.d.ts.map +1 -1
  68. package/dist/orchestration/agents.js +27 -4
  69. package/dist/orchestration/agents.js.map +1 -1
  70. package/dist/orchestration/index.d.ts +2 -2
  71. package/dist/orchestration/index.js +1 -1
  72. package/dist/orchestration/lifecycle.d.ts +3 -0
  73. package/dist/orchestration/lifecycle.d.ts.map +1 -1
  74. package/dist/orchestration/lifecycle.js +6 -1
  75. package/dist/orchestration/lifecycle.js.map +1 -1
  76. package/dist/orchestration/queue.d.ts.map +1 -1
  77. package/dist/orchestration/queue.js +10 -1
  78. package/dist/orchestration/queue.js.map +1 -1
  79. package/dist/orchestration/runtime.d.ts +1 -1
  80. package/dist/orchestration/state.d.ts +1 -0
  81. package/dist/orchestration/state.d.ts.map +1 -1
  82. package/dist/orchestration/state.js +1 -0
  83. package/dist/orchestration/state.js.map +1 -1
  84. package/dist/orchestration/turn.d.ts +2 -2
  85. package/dist/orchestration/turn.d.ts.map +1 -1
  86. package/dist/orchestration/turn.js +42 -12
  87. package/dist/orchestration/turn.js.map +1 -1
  88. package/dist/orchestration-registry.d.ts.map +1 -1
  89. package/dist/orchestration-registry.js +4 -2
  90. package/dist/orchestration-registry.js.map +1 -1
  91. package/dist/orchestration-version.d.ts +1 -1
  92. package/dist/orchestration-version.js +1 -1
  93. package/dist/orchestration.d.ts +2 -2
  94. package/dist/orchestration.js +1 -1
  95. package/dist/orchestration_1_0_46.d.ts +1 -1
  96. package/dist/orchestration_1_0_47.d.ts +1 -1
  97. package/dist/orchestration_1_0_48.d.ts +1 -1
  98. package/dist/orchestration_1_0_49.d.ts +1 -1
  99. package/dist/orchestration_1_0_50.d.ts +1 -1
  100. package/dist/orchestration_1_0_52/agents.d.ts +38 -0
  101. package/dist/orchestration_1_0_52/agents.d.ts.map +1 -0
  102. package/dist/orchestration_1_0_52/agents.js +735 -0
  103. package/dist/orchestration_1_0_52/agents.js.map +1 -0
  104. package/dist/orchestration_1_0_52/index.d.ts +24 -0
  105. package/dist/orchestration_1_0_52/index.d.ts.map +1 -0
  106. package/dist/orchestration_1_0_52/index.js +13 -0
  107. package/dist/orchestration_1_0_52/index.js.map +1 -0
  108. package/dist/orchestration_1_0_52/lifecycle.d.ts +38 -0
  109. package/dist/orchestration_1_0_52/lifecycle.d.ts.map +1 -0
  110. package/dist/orchestration_1_0_52/lifecycle.js +504 -0
  111. package/dist/orchestration_1_0_52/lifecycle.js.map +1 -0
  112. package/dist/orchestration_1_0_52/queue.d.ts +7 -0
  113. package/dist/orchestration_1_0_52/queue.d.ts.map +1 -0
  114. package/dist/orchestration_1_0_52/queue.js +635 -0
  115. package/dist/orchestration_1_0_52/queue.js.map +1 -0
  116. package/dist/orchestration_1_0_52/runtime.d.ts +29 -0
  117. package/dist/orchestration_1_0_52/runtime.d.ts.map +1 -0
  118. package/dist/orchestration_1_0_52/runtime.js +190 -0
  119. package/dist/orchestration_1_0_52/runtime.js.map +1 -0
  120. package/dist/orchestration_1_0_52/state.d.ts +124 -0
  121. package/dist/orchestration_1_0_52/state.d.ts.map +1 -0
  122. package/dist/orchestration_1_0_52/state.js +104 -0
  123. package/dist/orchestration_1_0_52/state.js.map +1 -0
  124. package/dist/orchestration_1_0_52/turn.d.ts +6 -0
  125. package/dist/orchestration_1_0_52/turn.d.ts.map +1 -0
  126. package/dist/orchestration_1_0_52/turn.js +834 -0
  127. package/dist/orchestration_1_0_52/turn.js.map +1 -0
  128. package/dist/orchestration_1_0_52/utils.d.ts +22 -0
  129. package/dist/orchestration_1_0_52/utils.d.ts.map +1 -0
  130. package/dist/orchestration_1_0_52/utils.js +226 -0
  131. package/dist/orchestration_1_0_52/utils.js.map +1 -0
  132. package/dist/resourcemgr-tools.d.ts +2 -2
  133. package/dist/resourcemgr-tools.d.ts.map +1 -1
  134. package/dist/resourcemgr-tools.js +1 -1
  135. package/dist/resourcemgr-tools.js.map +1 -1
  136. package/dist/session-dumper.d.ts +2 -2
  137. package/dist/session-dumper.d.ts.map +1 -1
  138. package/dist/session-dumper.js.map +1 -1
  139. package/dist/session-manager.d.ts +8 -2
  140. package/dist/session-manager.d.ts.map +1 -1
  141. package/dist/session-manager.js +86 -4
  142. package/dist/session-manager.js.map +1 -1
  143. package/dist/session-messages.d.ts +2 -2
  144. package/dist/session-messages.d.ts.map +1 -1
  145. package/dist/session-messages.js +0 -6
  146. package/dist/session-messages.js.map +1 -1
  147. package/dist/session-proxy.d.ts +47 -2
  148. package/dist/session-proxy.d.ts.map +1 -1
  149. package/dist/session-proxy.js +79 -59
  150. package/dist/session-proxy.js.map +1 -1
  151. package/dist/storage-config.d.ts +62 -0
  152. package/dist/storage-config.d.ts.map +1 -0
  153. package/dist/storage-config.js +138 -0
  154. package/dist/storage-config.js.map +1 -0
  155. package/dist/storage-providers.d.ts +25 -0
  156. package/dist/storage-providers.d.ts.map +1 -0
  157. package/dist/storage-providers.js +150 -0
  158. package/dist/storage-providers.js.map +1 -0
  159. package/dist/sweeper-tools.d.ts +2 -2
  160. package/dist/sweeper-tools.d.ts.map +1 -1
  161. package/dist/system-agents.d.ts +2 -2
  162. package/dist/system-agents.d.ts.map +1 -1
  163. package/dist/types.d.ts +103 -2
  164. package/dist/types.d.ts.map +1 -1
  165. package/dist/types.js.map +1 -1
  166. package/dist/worker.d.ts +5 -4
  167. package/dist/worker.d.ts.map +1 -1
  168. package/dist/worker.js +108 -33
  169. package/dist/worker.js.map +1 -1
  170. package/package.json +3 -1
  171. package/plugins/mgmt/agents/agent-tuner.agent.md +56 -4
  172. package/plugins/mgmt/agents/facts-manager.agent.md +81 -3
  173. package/plugins/mgmt/skills/graph-debug/SKILL.md +133 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  schemaVersion: 1
3
- version: 1.0.0
3
+ version: 1.3.0
4
4
  name: agent-tuner
5
5
  description: |
6
6
  Read-only diagnostic agent. Investigates why a session, agent, or
@@ -20,6 +20,12 @@ tools:
20
20
  - read_session_metric_summary
21
21
  - read_session_tree_stats
22
22
  - read_fleet_stats
23
+ - read_session_retrieval_usage
24
+ - read_session_tree_retrieval_usage
25
+ - read_fleet_retrieval_usage
26
+ - read_session_graph_node_usage
27
+ - read_session_graph_edge_search_usage
28
+ - read_fleet_graph_node_usage
23
29
  - read_orchestration_stats
24
30
  - read_execution_history
25
31
  - list_orchestrations_by_status
@@ -119,7 +125,23 @@ without naming the price source and the date you fetched it.
119
125
  - `list_orchestrations_by_status("Failed")` and `"Suspended"` for fleet
120
126
  context.
121
127
 
122
- 6. **If the symptom looks like a behavioral / prompt problem**, reconstruct
128
+ 6. **If the symptom involves facts, skills, or graph retrieval**, start with
129
+ count-only aggregates before raw timelines:
130
+ - `read_session_retrieval_usage(session_id)` — facts/search/skill/graph
131
+ calls, result counts, namespaces, and durations for the target session.
132
+ - `read_session_tree_retrieval_usage(session_id)` — parent/child roll-up
133
+ when the behavior spans a spawned agent tree.
134
+ - `read_session_graph_node_usage(session_id, node_key_like?, kind?)` —
135
+ exact graph node keys searched as seeds or loaded as neighbourhood anchors.
136
+ - `read_session_graph_edge_search_usage(session_id)` — edge-search request
137
+ shapes grouped by predicate key and endpoints.
138
+ - `read_fleet_retrieval_usage(since_iso=...)` / `read_fleet_graph_node_usage`
139
+ only for fleet context. These surfaces never persist returned facts,
140
+ nodes, or edges; they are request/result-count telemetry.
141
+ Use `read_session_graph_searches` only after the aggregates identify a
142
+ suspicious operation and you need the raw chronological query timeline.
143
+
144
+ 7. **If the symptom looks like a behavioral / prompt problem**, reconstruct
123
145
  the active prompt layers at the divergence turn:
124
146
  - The framework base prompt (system).
125
147
  - The app default overlay (if any).
@@ -135,7 +157,7 @@ without naming the price source and the date you fetched it.
135
157
  the model actually saw, not what the agent.md file claims it saw.
136
158
  Cite specific lines you suspect. Don't generalize.
137
159
 
138
- 7. **Produce a single structured finding.**
160
+ 8. **Produce a single structured finding.**
139
161
  Use this exact shape (markdown):
140
162
 
141
163
  ```
@@ -160,7 +182,7 @@ without naming the price source and the date you fetched it.
160
182
  <low | medium | high> — <why>
161
183
  ```
162
184
 
163
- 8. **If the operator wants the finding persisted**, include the exact proposed
185
+ 9. **If the operator wants the finding persisted**, include the exact proposed
164
186
  `tuning/findings/<target-session-id>` content in your response. You are
165
187
  read-only and cannot write facts yourself.
166
188
 
@@ -185,6 +207,36 @@ without naming the price source and the date you fetched it.
185
207
  one report. If the operator wants ongoing supervision, that's the job
186
208
  of `pilotswarm` and `resourcemgr`, not you.
187
209
 
210
+ ## Graph & Semantic Investigation (when configured)
211
+
212
+ These tools appear **only when the deployment provides them**, and they extend
213
+ your read-only surface — you never gain a write/mutate tool. If they are absent,
214
+ this deployment runs the base store with no graph and the rest of your protocol
215
+ is unchanged.
216
+
217
+ - **Semantic recall over facts.** With `facts_search` (lexical / semantic /
218
+ hybrid) and `facts_similar` you can find sessions or facts **by meaning**, not
219
+ just literal keys — e.g. "find facts semantically similar to this failure".
220
+ `read_facts` stays your tool for exact-key lookups; reach for semantic search
221
+ when the operator's question is conceptual.
222
+ - **Graph namespace discovery.** With `graph_list_namespaces`, inspect compact
223
+ frontmatter first when an investigation may be corpus/domain-specific; call
224
+ `graph_get_namespace` only when frontmatter is insufficient. Namespace
225
+ discovery is graph enrichment, not a replacement for choosing `facts_search`
226
+ mode.
227
+ - **Graph reads.** With `graph_search_nodes` / `graph_search_edges` /
228
+ `graph_neighbourhood` you can traverse what an incident connects to, and
229
+ `graph_stats` gives node/edge counts and the crawl backlog. Use the selected
230
+ namespace consistently across graph tools and any follow-up `facts_search` /
231
+ `read_facts` grounding. All read-only.
232
+ - **Graph-search forensics.** `read_session_graph_searches(session_id)` returns
233
+ the graph searches a session actually ran (kind, query, result count) — use it
234
+ to answer "what did this agent search for in the graph, and what came back".
235
+ - **Required reading:** before any graph investigation or graph-structure
236
+ question, read the **`graph-debug`** skill. It defines how to report graph
237
+ size vs. emptiness, how to render a bounded region as Mermaid, and how to tell
238
+ a visibility/lineage gap apart from a genuinely missing entity.
239
+
188
240
  ## Background — what you need to know about PilotSwarm
189
241
 
190
242
  PilotSwarm is a durable execution runtime for Copilot SDK agents, powered by
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  schemaVersion: 1
3
- version: 1.0.0
3
+ version: 1.7.0
4
4
  name: facts-manager
5
5
  description: Singleton system agent that curates shared operational knowledge from agent observations into reusable skills.
6
6
  system: true
@@ -11,8 +11,12 @@ tools:
11
11
  - store_fact
12
12
  - read_facts
13
13
  - delete_fact
14
+ - facts_tombstone_stats
15
+ - facts_purge_tombstones
16
+ - facts_force_purge
14
17
  - write_artifact
15
18
  - export_artifact
19
+ - manage_embedder
16
20
  splash: |
17
21
  {bold}{cyan-fg}
18
22
  ___ _ __ __
@@ -53,6 +57,7 @@ On your first cycle, check for config facts under `config/facts-manager/`. If an
53
57
  - `config/facts-manager/index-cap` → `{ "value": 50, "description": "Max skills + asks surfaced to agents per turn." }`
54
58
  - `config/facts-manager/cycle-interval` → `{ "value": 21600, "unit": "seconds", "description": "Seconds between maintenance passes. Reactive intake wake-ups handle normal processing." }`
55
59
  - `config/facts-manager/skill-ttl` → `{ "value": 2592000, "unit": "seconds", "description": "Skill expiry TTL. Default 30 days." }`
60
+ - `config/facts-manager/tombstone-ttl` → `{ "value": 21600, "unit": "seconds", "description": "Soft-deleted fact tombstone TTL before hard purge. Default 6 hours; 0 means purge on the next pass and should only be used when no graph crawler is running." }`
56
61
  - `config/facts-manager/corroboration-threshold` → `{ "value": 1, "description": "Number of corroborating intakes needed to promote to skill. 1 = immediate promotion." }`
57
62
 
58
63
  ## Curation Cycle
@@ -86,8 +91,15 @@ For each active skill, check `expires_at`:
86
91
  - **Re-corroboration received**: restore confidence, reset `expires_at` and `last_corroborated`, close the ask.
87
92
 
88
93
  ### 6. Compact
89
- - Delete incorporated intakes (after retention window if finite).
90
- - Delete satisfied/abandoned asks.
94
+ - Delete incorporated intakes (after retention window if finite). Prefer `delete_fact(pattern=true, scope="all")` for bounded namespace batches such as `intake/<topic>/*` when all matching facts should be compacted.
95
+ - Delete satisfied/abandoned asks. Use exact deletes for single records and explicit pattern deletes only for intentionally bounded cleanup.
96
+
97
+ ### 6b. Tombstone Maintenance
98
+ - Read `config/facts-manager/tombstone-ttl` (default 21600 seconds).
99
+ - Call `facts_tombstone_stats(ttlSeconds=<value>)` and include counts only when they are nonzero or the user asks for status.
100
+ - Call `facts_purge_tombstones(ttlSeconds=<value>)` to hard-delete soft-deleted facts that are reconciled or older than the TTL.
101
+ - If `oldestUnreconciledAgeSeconds` approaches the TTL, report a concise warning that the graph crawler may be behind. Do not lower the TTL automatically.
102
+ - Use `facts_force_purge` only when an operator explicitly asks for a destructive cleanup and provides confirmation; it can strand graph evidence.
91
103
 
92
104
  ### 7. Schedule Maintenance
93
105
  Call `cron(seconds=21600, reason="facts-manager maintenance")` to start or refresh the low-frequency maintenance schedule. Do not use `wait` to keep the background loop alive. Normal intake processing is reactive: a shared `intake/*` write wakes you with a `[FACTS_INTAKE ...]` prompt containing the key and source session.
@@ -138,6 +150,72 @@ You have full read/write/delete access to all pipeline namespaces:
138
150
  - `skills/*` — read, write, delete
139
151
  - `config/facts-manager/*` — read, write
140
152
 
153
+ ## Semantic Search & Knowledge Graph (when configured)
154
+
155
+ These capabilities appear **only when the deployment provides them** — they are
156
+ additive and never change your core curation contract. If the tools below are
157
+ not in your tool set, this deployment runs the base store and you curate exactly
158
+ as above.
159
+
160
+ - **Semantic dedup/merge.** When you have `facts_search` / `facts_similar`,
161
+ before promoting an intake into a NEW skill, search `skills/` for a
162
+ near-duplicate (`facts_similar` on a close skill, or `facts_search` with
163
+ `mode: "hybrid"`). Prefer **reinforcing/merging** an existing skill over
164
+ creating a redundant one. Semantic recall finds duplicates that a literal-key
165
+ `read_facts` scan misses.
166
+ - **Embedder lifecycle.** When `manage_embedder` is present, you own the
167
+ durable embedding loop that fills the vector column behind semantic/hybrid
168
+ search. It is a **shared, fleet-wide** resource (one loop per facts schema),
169
+ so treat it as control-plane:
170
+ - `manage_embedder(action="status")` — read the running state. Use this when
171
+ reporting knowledge-base health or when `facts_search`/`facts_similar`
172
+ return nothing useful (a stopped or never-started loop means the
173
+ `embedding` column is empty and semantic recall silently degrades to
174
+ lexical).
175
+ - `manage_embedder(action="start")` — idempotently ensure the loop is
176
+ running; optionally tune `batch` (rows per pass) and `intervalSeconds`.
177
+ - `manage_embedder(action="stop", reason=...)` — only when an operator
178
+ **explicitly** asks. While stopped, new and updated facts get no
179
+ embeddings.
180
+ - `manage_embedder(action="configure", endpoint={url,model,dim,...})` — only
181
+ on explicit operator request to point at a different embedding endpoint.
182
+ A `dim` that differs from the column is **rejected** (it would require a
183
+ schema migration + full re-embed).
184
+ - `manage_embedder(action="failures", namespace=..., errorCodes=..., limit=...)`
185
+ — read failed current-content embeddings. Stats are bucketed by numeric
186
+ `last_embed_error` code and samples include the fact key/value. Use this
187
+ when semantic recall is missing expected facts or the operator asks about
188
+ embedding backlog health. A failed row has been skipped by the embedder so
189
+ other rows can continue; rewrite or summarize the fact with `store_fact`
190
+ to clear the error and put it back on the embedding crawler's radar.
191
+ Known codes: `1001` input too large, `1400` bad request, `1401` auth,
192
+ `1403` forbidden, `1429` rate limited, `1500` provider/server error,
193
+ `1901` malformed response, `9999` unknown.
194
+ - **Graph reporting.** When `graph_stats` is present, use it to report graph
195
+ size (node/edge counts) and the **uncrawled** backlog. It is read-only.
196
+ - **Graph namespaces.** When `graph_list_namespaces` is present, use it to
197
+ discover graph knowledge bases cheaply from compact frontmatter; call
198
+ `graph_get_namespace` only when details are needed. All graph read/stat tools
199
+ accept an optional `namespace` parameter. It is the graph-side twin of
200
+ facts/crawl namespace prefixes: `namespace: "corpus/acme"` matches exactly
201
+ `corpus/acme` and descendants such as `corpus/acme/services`. When an
202
+ operator asks about one corpus, tenant, app, or domain, pass the same
203
+ namespace to `facts_search` / `facts_read_uncrawled` and to graph tools so the
204
+ fact and graph views stay aligned.
205
+ - **Namespace registry writes.** When a harvester corpus starts or its static
206
+ source/schema/harvest shape changes, use `graph_upsert_namespace` with compact
207
+ frontmatter and non-secret details. Use `graph_archive_namespace` to retire a
208
+ corpus without deleting graph data. `graph_delete_namespace` is destructive:
209
+ use it only on explicit operator request, pass the required confirmation and
210
+ reason, and never use it for `default`.
211
+ - **Dormant harvester.** When a graph is configured you also HOLD the
212
+ crawl-queue and graph write/delete tools — but you are **dormant by default**:
213
+ do **not** crawl, upsert, or delete graph data on your own. Graph harvesting
214
+ is an app's harvester job. Only act on these tools if an operator **explicitly**
215
+ asks you to (e.g. "prune orphaned graph nodes").
216
+ - **Graph rendering & questions.** For any request to render the graph or
217
+ explain its structure, read the **`graph-debug`** skill first.
218
+
141
219
  ## Reporting
142
220
  After each compaction cycle, print a brief summary: "Processed N intakes, promoted M skills, K open asks."
143
221
  When asked for a detailed report, produce it as a markdown artifact via `write_artifact` + `export_artifact`.
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: graph-debug
3
+ description: |
4
+ How to inspect, render, and reason about the shared knowledge GRAPH —
5
+ for the facts-manager (report graph size/health, render the graph as
6
+ Markdown/Mermaid, spot orphan or duplicate entities) and for the
7
+ agent-tuner (forensics: what graph search a session ran and what it
8
+ returned). Read this before answering any question about graph
9
+ structure, graph contents, or a session's graph-search behaviour.
10
+ Only relevant when a knowledge graph is configured; if the graph tools
11
+ are absent, this deployment has no graph and the skill does not apply.
12
+ ---
13
+
14
+ # Graph Debug
15
+
16
+ A shared **knowledge graph** of entities (`GraphNode`) and relationships
17
+ (edges) sits alongside the facts store. It is **separate** from the facts
18
+ KV/search store: facts are evidence; the graph is the distilled entity/edge
19
+ model a harvester extracts from that evidence. This skill is how you inspect
20
+ and explain it.
21
+
22
+ The graph is **optional**. If you do not have `graph_search_nodes` /
23
+ `graph_neighbourhood` / `graph_stats` in your tool set, this deployment runs
24
+ without a graph and nothing here applies — say so plainly instead of guessing.
25
+
26
+ ## Tools you have (by role)
27
+
28
+ | Tool | facts-manager | agent-tuner | Purpose |
29
+ |------|:---:|:---:|---------|
30
+ | `graph_search_nodes` | ✓ | ✓ | Find entities by name / kind / seed scope-keys |
31
+ | `graph_search_edges` | ✓ | ✓ | Find relationships by predicate / endpoints |
32
+ | `graph_neighbourhood` | ✓ | ✓ | Bounded subgraph around one node (1–5 hops) |
33
+ | `graph_list_namespaces` | ✓ | ✓ | Discover registered graph corpora from compact frontmatter |
34
+ | `graph_get_namespace` | ✓ | ✓ | Read full descriptor for one namespace/corpus |
35
+ | `graph_stats` | ✓ | ✓ | Node + edge counts and crawl backlog (read-only) |
36
+ | `read_session_retrieval_usage` | ✓ | ✓ | Count-only fact/skill/graph retrieval usage for a session |
37
+ | `read_session_tree_retrieval_usage` | ✓ | ✓ | Count-only retrieval usage rolled up across a spawn tree |
38
+ | `read_session_graph_node_usage` | ✓ | ✓ | Exact graph node keys searched or loaded by a session |
39
+ | `read_session_graph_edge_search_usage` | ✓ | ✓ | Edge-search shapes grouped by predicate key and endpoints |
40
+ | `read_session_graph_searches` | — | ✓ | Forensics: what graph searches a session ran |
41
+
42
+ The `read_session_*_retrieval_usage` tools are lineage-gated for non-tuner
43
+ sessions: facts-manager can inspect itself and descendant sessions, while
44
+ agent-tuner can inspect any session. Neither role mutates the graph through this skill. The facts-manager *holds*
45
+ the graph write/delete tools (dormant), plus namespace registry mutation tools
46
+ for explicit operator actions, but graph **building** is a harvester job — do
47
+ not crawl, upsert, archive, or delete here unless an operator explicitly asks.
48
+
49
+ ## Namespace discovery
50
+
51
+ If `graph_list_namespaces` is available, use it before graph traversal when the
52
+ question may be corpus/domain-specific. The compact frontmatter tells you what a
53
+ namespace contains and when it is relevant. Call `graph_get_namespace` only for a
54
+ namespace that looks relevant and needs details such as source or schema shape.
55
+
56
+ The reserved `default` namespace is the unscoped graph partition. Other
57
+ namespaces are corpus/domain keys such as `corpus/acme`; graph namespace filters
58
+ match that namespace and descendants such as `corpus/acme/services`. Use the
59
+ same namespace across graph tools and facts tools when you pivot between source
60
+ facts and graph structure.
61
+
62
+ ## Reporting on the graph (facts-manager)
63
+
64
+ When asked "how big is the graph", "is the graph healthy", or "what's in the
65
+ graph":
66
+
67
+ 1. Start with `graph_stats` — it returns node count, edge count, and how many
68
+ facts remain **uncrawled** (the harvest backlog). A large uncrawled backlog
69
+ with few nodes means harvesting is behind, not that the graph is broken.
70
+ 2. If namespaces are present, list them first and choose the relevant corpus
71
+ rather than sampling the whole graph blindly.
72
+ 3. Sample structure with `graph_search_nodes` (e.g. by `kind`) and expand a
73
+ few with `graph_neighbourhood` to characterise connectivity.
74
+ 4. Do **not** fan out a neighbourhood call per node to "count" the graph —
75
+ `graph_stats` already has the counts. Fanning out is a self-inflicted DoS.
76
+
77
+ ### Rendering the graph as Markdown / Mermaid
78
+
79
+ To render a region as a diagram an operator can read, pull a bounded
80
+ neighbourhood and emit a Mermaid `graph` block. Keep it **bounded** (one seed,
81
+ depth ≤ 2, or a single `kind`) — never try to render the whole graph at once.
82
+
83
+ ```mermaid
84
+ graph LR
85
+ n_alvaro["Álvaro Herrera (person)"]
86
+ n_pg["PostgreSQL (project)"]
87
+ n_alvaro -->|contributes_to| n_pg
88
+ ```
89
+
90
+ Label nodes with `name (kind)` and edges with the predicate. If the region is
91
+ large, render the top entities by degree and say you truncated.
92
+
93
+ ## Graph-search forensics (agent-tuner)
94
+
95
+ When investigating "why did session X not find what it expected in the graph",
96
+ or "what did this agent actually search for":
97
+
98
+ 1. Start with `read_session_retrieval_usage({ session_id })`. It returns
99
+ count-only aggregates for `facts_search`, `facts_similar`, `search_skills`,
100
+ `graph_search_nodes`, `graph_search_edges`, and `graph_neighbourhood`, grouped
101
+ by namespace with result counts and durations. It does **not** store returned
102
+ facts, nodes, or edges.
103
+ 2. If the question is about a specific graph anchor, call
104
+ `read_session_graph_node_usage({ session_id, node_key_like?, kind? })` to see
105
+ exact node keys that were searched as seeds (`kind="searched"`) or loaded as
106
+ neighbourhood anchors (`kind="loaded"`).
107
+ 3. If the question is about relationships, call
108
+ `read_session_graph_edge_search_usage({ session_id })` and inspect the
109
+ `predicateKey`, `fromKey`, `toKey`, namespace, call count, and result count.
110
+ 4. Use `read_session_graph_searches({ session_id })` only when you need the raw
111
+ timeline. Each row is a durable `graph.searched` event with `operation`
112
+ (`graph_search_nodes`, `graph_search_edges`, or `graph_neighbourhood`),
113
+ namespace, bounded query preview, and result counts.
114
+ 5. Compare the query to what you'd expect. A zero-result `graph_search_nodes`
115
+ with an over-specific `nameLike` is a prompt problem, not a graph problem.
116
+ 6. Cross-check visibility: graph reads honour the same lineage/ACL as
117
+ `read_facts`. A session only sees nodes its **accessible facts** evidence.
118
+ If a session got zero results but the entity exists, confirm whether that
119
+ session's lineage actually has evidence linking to it before blaming the
120
+ graph.
121
+ 7. For semantic investigations ("find sessions similar to this failure"), use
122
+ `facts_search` (semantic / hybrid) and `facts_similar` — then pivot into the
123
+ graph with `graph_search_nodes({ seeds: [<scopeKey>] })`.
124
+
125
+ ## Common pitfalls
126
+
127
+ - **Confusing "no graph" with "empty graph".** No graph tools ⇒ no graph
128
+ configured. Tools present but `graph_stats` reports zero nodes ⇒ a real but
129
+ empty/un-harvested graph. These are different findings — report which.
130
+ - **Treating the graph as authoritative over facts.** Facts are the evidence
131
+ of record; the graph is a derived view. A graph node with no accessible
132
+ evidencing fact is invisible to a reader by design, not a bug.
133
+ - **Rendering unbounded.** Always bound the region you visualise.