@productbrain/mcp 0.0.1-beta.8849 → 0.0.1-beta.8872

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.
@@ -42,7 +42,7 @@ import {
42
42
  trackSessionCaptureRate,
43
43
  trackZeroCaptureAuditFired,
44
44
  validateCallerSession
45
- } from "./chunk-NT3NE6V5.js";
45
+ } from "./chunk-VZNA24SX.js";
46
46
 
47
47
  // src/server.ts
48
48
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -357,7 +357,6 @@ var TOOL_NAME_MIGRATIONS = /* @__PURE__ */ new Map([
357
357
  ["relate-entries", 'relations action="create"'],
358
358
  ["batch-relate", 'relations action="batch-create"'],
359
359
  ["find-related", 'relations action="find"'],
360
- ["suggest-links", 'relations action="suggest"'],
361
360
  ["gather-context", 'context action="gather"'],
362
361
  ["get-build-context", 'context action="build"'],
363
362
  ["list-collections", 'collections action="list"'],
@@ -405,7 +404,7 @@ var TOOL_NAME_MIGRATIONS = /* @__PURE__ */ new Map([
405
404
  ["move-entry", 'entries action="move"'],
406
405
  ["session-wrapup", 'session action="wrapup-review|wrapup-commit" (review \u2192 wrapup-review, commit-all \u2192 wrapup-commit)'],
407
406
  ["facilitate", 'session action="resume|commit-constellation" (same action names)'],
408
- ["graph", 'relations action="find|suggest" (same action names)'],
407
+ ["graph", 'relations action="find" (same action name)'],
409
408
  ["documents", 'context action="last-verified-brief"'],
410
409
  ["labels", 'collections action="label-*" (list/create/update/delete/apply/remove \u2192 label-<same>)'],
411
410
  ["health", 'workspace action="check|whoami|status|audit|self-test" (same action names)'],
@@ -2302,7 +2301,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2302
2301
  if (isBetOrGoal && !hasStrategyLink) {
2303
2302
  lines.push("");
2304
2303
  lines.push(
2305
- `**Strategy link:** This ${isWorkPackageOrBetCapture ? "work package" : "goal"} doesn't connect to any strategy entry. Consider linking before accepting. Use \`relations action=suggest entryId="${finalEntryId}"\` to find strategy entries to connect to.`
2304
+ `**Strategy link:** This ${isWorkPackageOrBetCapture ? "work package" : "goal"} doesn't connect to any strategy entry. Consider linking before accepting. Find one with \`entries action=search\` and link it with \`relations action=create\`.`
2306
2305
  );
2307
2306
  await recordSessionActivity({ strategyLinkWarnedForEntryId: internalId });
2308
2307
  }
@@ -2334,13 +2333,13 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2334
2333
  lines.push("## Next Steps");
2335
2334
  const eid = finalEntryId || "(check entry ID)";
2336
2335
  if (finalStatus === "committed") {
2337
- lines.push(`1. **Connect it:** \`relations action=suggest entryId="${eid}"\` \u2014 discover additional links`);
2336
+ lines.push(`1. **Connect it:** find related entries with \`entries action=search\`, then \`relations action=create from="${eid}" to="<ID>" type="<verb>"\``);
2338
2337
  if (hasQualityGaps) {
2339
2338
  lines.push(`2. **Improve quality:** \`entries action=update entryId="${eid}"\` \u2014 fill missing fields`);
2340
2339
  }
2341
2340
  } else {
2342
2341
  if (userLinkResults.length === 0) {
2343
- lines.push(`1. **Connect it:** \`relations action=suggest entryId="${eid}"\` \u2014 discover what this should link to`);
2342
+ lines.push(`1. **Connect it:** find related entries with \`entries action=search\`, then \`relations action=create from="${eid}" to="<ID>" type="<verb>"\``);
2344
2343
  }
2345
2344
  lines.push(`${userLinkResults.length === 0 ? "2" : "1"}. **Review the possibility:** Keep this visible draft while it is an alternative. Accept only when commitment is intended and your role is authorized. Types reserved for human acceptance require human ratification. An audit advisory is not a reason to accept it.`);
2346
2345
  if (hasQualityGaps) {
@@ -2363,11 +2362,8 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2363
2362
  }
2364
2363
  const next = [];
2365
2364
  if (finalStatus === "committed") {
2366
- next.push({ tool: "relations", description: "Discover connections", parameters: { action: "suggest", entryId: finalEntryId } });
2365
+ next.push({ tool: "relations", description: "See its connections", parameters: { action: "find", entryId: finalEntryId } });
2367
2366
  } else {
2368
- if (userLinkResults.length === 0) {
2369
- next.push({ tool: "relations", description: "Discover links", parameters: { action: "suggest", entryId: finalEntryId } });
2370
- }
2371
2367
  next.push({ tool: "entries", description: "Review the draft alternative", parameters: { action: "get", entryId: finalEntryId } });
2372
2368
  next.push({ tool: "entries", description: "Accept onto Chain", parameters: { action: "commit", entryId: finalEntryId } });
2373
2369
  }
@@ -2925,7 +2921,7 @@ No DB writes \u2014 call without \`preview:true\` to accept for real.` }],
2925
2921
  } catch {
2926
2922
  }
2927
2923
  const next = [
2928
- { tool: "relations", description: "Discover connections", parameters: { action: "suggest", entryId } },
2924
+ { tool: "relations", description: "See its connections", parameters: { action: "find", entryId } },
2929
2925
  { tool: "entries", description: "View accepted entry", parameters: { action: "get", entryId } }
2930
2926
  ];
2931
2927
  const summary = `Accepted ${entryId} (${entry.name}) onto the Chain.`;
@@ -3832,7 +3828,7 @@ async function handleGet(entryId) {
3832
3828
  `Found ${entryId}: ${String(e.name)} [${String(e.collectionSlug ?? "")}].`,
3833
3829
  entryData,
3834
3830
  [
3835
- { tool: "relations", description: "Explore connections", parameters: { action: "suggest", entryId } },
3831
+ { tool: "relations", description: "See its connections", parameters: { action: "find", entryId } },
3836
3832
  { tool: "context", description: "Gather related context", parameters: { action: "gather", entryId } }
3837
3833
  ]
3838
3834
  )
@@ -4080,15 +4076,13 @@ import { z as z13 } from "zod/v3";
4080
4076
 
4081
4077
  // src/tools/graph.ts
4082
4078
  import { z as z12 } from "zod/v3";
4083
- var GRAPH_ACTIONS = ["find", "suggest"];
4079
+ var GRAPH_ACTIONS = ["find"];
4084
4080
  var graphSchema = z12.object({
4085
4081
  action: z12.enum(GRAPH_ACTIONS).describe(
4086
- "'find': traverse relations from an entry (graph walk). 'suggest': discover potential connections for an entry."
4082
+ "'find': traverse relations from an entry (graph walk)."
4087
4083
  ),
4088
4084
  entryId: z12.string().max(200).describe("Entry ID, e.g. '<PREFIX>-<n>'"),
4089
- direction: z12.enum(["incoming", "outgoing", "both"]).default("both").optional().describe("For find: 'incoming' = what references this, 'outgoing' = what this references"),
4090
- limit: z12.number().min(1).max(20).default(10).optional().describe("For suggest: max suggestions to return"),
4091
- depth: z12.number().min(1).max(3).default(2).optional().describe("For suggest: graph traversal depth")
4085
+ direction: z12.enum(["incoming", "outgoing", "both"]).default("both").optional().describe("For find: 'incoming' = what references this, 'outgoing' = what this references")
4092
4086
  });
4093
4087
  var graphFindOutputSchema = z12.object({
4094
4088
  entryId: z12.string(),
@@ -4100,18 +4094,6 @@ var graphFindOutputSchema = z12.object({
4100
4094
  })),
4101
4095
  total: z12.number()
4102
4096
  });
4103
- var graphSuggestOutputSchema = z12.object({
4104
- entryId: z12.string(),
4105
- suggestions: z12.array(z12.object({
4106
- targetEntryId: z12.string().optional(),
4107
- targetName: z12.string(),
4108
- relationType: z12.string(),
4109
- direction: z12.string(),
4110
- confidence: z12.number(),
4111
- reason: z12.string()
4112
- })),
4113
- total: z12.number()
4114
- });
4115
4097
  async function handleFind(entryId, direction) {
4116
4098
  const relations = await kernelQuery("chain.listEntryRelations", { entryId });
4117
4099
  if (relations.length === 0) {
@@ -4121,8 +4103,7 @@ async function handleFind(entryId, direction) {
4121
4103
  `No relations found for '${entryId}'.`,
4122
4104
  { entryId, relations: [], nodes: [], edges: [], total: 0 },
4123
4105
  [
4124
- { tool: "relations", description: "Create a relation", parameters: { action: "create", from: entryId } },
4125
- { tool: "relations", description: "Get suggestions", parameters: { action: "suggest", entryId } }
4106
+ { tool: "relations", description: "Create a relation", parameters: { action: "create", from: entryId } }
4126
4107
  ]
4127
4108
  )
4128
4109
  };
@@ -4210,97 +4191,9 @@ async function handleFind(entryId, direction) {
4210
4191
  )
4211
4192
  };
4212
4193
  }
4213
- async function handleSuggest(entryId, limit, depth) {
4214
- const result2 = await kernelQuery("chain.graphSuggestLinks", {
4215
- entryId,
4216
- maxHops: depth,
4217
- limit
4218
- });
4219
- if (!result2?.suggestions || result2.suggestions.length === 0) {
4220
- return failureResult(
4221
- `No suggestions found for '${entryId}' \u2014 it may already be well-connected, or no similar entries exist.`,
4222
- "NOT_FOUND",
4223
- `No suggestions found for '${entryId}'.`,
4224
- "Entry may already be well-connected.",
4225
- [{ tool: "relations", description: "Check existing relations", parameters: { action: "find", entryId } }]
4226
- );
4227
- }
4228
- const resolved = result2.resolvedEntry;
4229
- const resolvedLabel = resolved ? `\`${resolved.entryId ?? resolved.name}\` (${resolved.name})` : `\`${entryId}\``;
4230
- const suggestions = result2.suggestions;
4231
- const graphCount = suggestions.filter((s) => s.graphDistance > 0).length;
4232
- const textCount = suggestions.filter((s) => s.graphDistance === -1).length;
4233
- const sourceId = resolved?.entryId ?? entryId;
4234
- const lines = [
4235
- `## Suggest Result`,
4236
- "",
4237
- `# Link Suggestions for ${resolvedLabel}`,
4238
- `_${suggestions.length} potential connections (${graphCount} via graph, ${textCount} via text similarity)._`,
4239
- ""
4240
- ];
4241
- const top3 = suggestions.slice(0, 3);
4242
- lines.push("## Quick Wins (top 3)");
4243
- const batchArgs = [];
4244
- for (const s of top3) {
4245
- const tid = s.entryId ?? "(no ID)";
4246
- const relType = s.recommendedRelationType || "related_to";
4247
- lines.push(`- **${tid}**: ${s.name} [${s.collectionSlug}] \u2014 ${s.score}/100 \u2192 \`${relType}\``);
4248
- if (s.entryId) batchArgs.push(`{from:"${sourceId}",to:"${tid}",type:"${relType}"}`);
4249
- }
4250
- lines.push("");
4251
- if (batchArgs.length > 0) {
4252
- lines.push(`**Link all 3:** \`relations action=batch-create relations=[${batchArgs.join(",")}]\``);
4253
- lines.push("");
4254
- }
4255
- if (suggestions.length > 3) {
4256
- lines.push("## All Suggestions");
4257
- for (let i = 0; i < suggestions.length; i++) {
4258
- const s = suggestions[i];
4259
- const scoreBar = "\u2588".repeat(Math.round(s.score / 10)) + "\u2591".repeat(10 - Math.round(s.score / 10));
4260
- const hopLabel = s.graphDistance > 0 ? `${s.graphDistance}-hop` : "text";
4261
- const recType = s.recommendedRelationType !== "related_to" ? ` \u2192 \`${s.recommendedRelationType}\`` : "";
4262
- lines.push(`${i + 1}. **${s.entryId ?? "(no ID)"}**: ${s.name} [${s.collectionSlug}] (${hopLabel})`);
4263
- lines.push(` ${scoreBar} ${s.score}/100${recType}`);
4264
- if (s.preview) lines.push(` ${s.preview}`);
4265
- lines.push(` _${s.reasoning}_`);
4266
- }
4267
- }
4268
- lines.push("");
4269
- lines.push(`**To link one:** \`relations action=create from="${sourceId}" to="{target_id}" type="{type}"\``);
4270
- lines.push(`**To dismiss:** \`relations action=dismiss from="${sourceId}" to="{target_id}" type="{type}"\``);
4271
- const structuredSuggestions = suggestions.map((s) => ({
4272
- targetEntryId: s.entryId,
4273
- targetName: s.name,
4274
- relationType: s.recommendedRelationType || "related_to",
4275
- direction: "outgoing",
4276
- confidence: s.score,
4277
- reason: s.reasoning
4278
- }));
4279
- const nodes = [
4280
- { id: sourceId, name: resolved?.name ?? entryId, collectionName: "" },
4281
- ...suggestions.map((s) => ({
4282
- id: s.entryId ?? String(Math.random()),
4283
- name: s.name,
4284
- collectionName: s.collectionSlug
4285
- }))
4286
- ];
4287
- const edges = suggestions.filter((s) => s.entryId).map((s) => ({
4288
- source: sourceId,
4289
- target: s.entryId,
4290
- type: s.recommendedRelationType || "suggested"
4291
- }));
4292
- return {
4293
- content: [{ type: "text", text: lines.join("\n") }],
4294
- structuredContent: success(
4295
- `Found ${suggestions.length} link suggestions for ${resolvedLabel}.`,
4296
- { entryId: sourceId, suggestions: structuredSuggestions, nodes, edges, total: suggestions.length },
4297
- [{ tool: "relations", description: "Create links", parameters: { action: "batch-create" } }]
4298
- )
4299
- };
4300
- }
4301
4194
 
4302
4195
  // src/tools/relations.ts
4303
- var RELATIONS_ACTIONS = ["create", "batch-create", "dismiss", "delete", "find", "suggest"];
4196
+ var RELATIONS_ACTIONS = ["create", "batch-create", "delete", "find"];
4304
4197
  var relationItemSchema = z13.object({
4305
4198
  from: z13.string().max(200),
4306
4199
  to: z13.string().max(200),
@@ -4308,19 +4201,16 @@ var relationItemSchema = z13.object({
4308
4201
  });
4309
4202
  var relationsSchema = z13.object({
4310
4203
  action: z13.enum(RELATIONS_ACTIONS).describe(
4311
- "'create': link two entries. 'batch-create': create multiple relations (validates every item before writing any). 'dismiss': record that a suggestion was not relevant. 'delete': remove a relation. 'find': traverse relations from an entry (graph walk, absorbs graph action=find). 'suggest': discover potential connections for an entry (absorbs graph action=suggest)."
4204
+ "'create': link two entries. 'batch-create': create multiple relations (validates every item before writing any). 'delete': remove a relation. 'find': traverse relations from an entry (graph walk, absorbs graph action=find)."
4312
4205
  ),
4313
- from: z13.string().max(200).optional().describe("For 'create'/'dismiss'/'delete': source entry ID."),
4314
- to: z13.string().max(200).optional().describe("For 'create'/'dismiss'/'delete': target entry ID."),
4315
- type: z13.string().max(200).optional().describe("For 'create'/'dismiss'/'delete': relation type."),
4316
- score: z13.number().optional().describe("For 'dismiss': suggestion score from action=suggest."),
4206
+ from: z13.string().max(200).optional().describe("For 'create'/'delete': source entry ID."),
4207
+ to: z13.string().max(200).optional().describe("For 'create'/'delete': target entry ID."),
4208
+ type: z13.string().max(200).optional().describe("For 'create'/'delete': relation type."),
4317
4209
  relations: z13.array(relationItemSchema).min(1).max(RELATION_BATCH_MAX).optional().describe("For 'batch-create': array of {from, to, type}."),
4318
4210
  // WP-316 S3: Preview gate — dry-run mode for action=create.
4319
4211
  preview: z13.boolean().optional().describe("For 'create': if true, validates the relation without writing. Returns what would happen. Default false."),
4320
- entryId: z13.string().max(200).optional().describe("For 'find'/'suggest': entry ID, e.g. '<PREFIX>-<n>'."),
4321
- direction: z13.enum(["incoming", "outgoing", "both"]).optional().describe("For 'find': 'incoming' = what references this, 'outgoing' = what this references. Default 'both'."),
4322
- limit: z13.number().min(1).max(20).optional().describe("For 'suggest': max suggestions to return. Default 10."),
4323
- depth: z13.number().min(1).max(3).optional().describe("For 'suggest': graph traversal depth. Default 2.")
4212
+ entryId: z13.string().max(200).optional().describe("For 'find': entry ID, e.g. '<PREFIX>-<n>'."),
4213
+ direction: z13.enum(["incoming", "outgoing", "both"]).optional().describe("For 'find': 'incoming' = what references this, 'outgoing' = what this references. Default 'both'.")
4324
4214
  });
4325
4215
  var relationsCreateVariant = z13.object({
4326
4216
  action: z13.literal("create"),
@@ -4333,13 +4223,6 @@ var relationsBatchCreateVariant = z13.object({
4333
4223
  action: z13.literal("batch-create"),
4334
4224
  relations: z13.array(relationItemSchema).min(1).max(RELATION_BATCH_MAX)
4335
4225
  });
4336
- var relationsDismissVariant = z13.object({
4337
- action: z13.literal("dismiss"),
4338
- from: z13.string().max(200),
4339
- to: z13.string().max(200),
4340
- type: z13.string().max(200).optional(),
4341
- score: z13.number().optional()
4342
- });
4343
4226
  var relationsDeleteVariant = z13.object({
4344
4227
  action: z13.literal("delete"),
4345
4228
  from: z13.string().max(200),
@@ -4351,44 +4234,32 @@ var relationsFindVariant = z13.object({
4351
4234
  entryId: z13.string().max(200),
4352
4235
  direction: z13.enum(["incoming", "outgoing", "both"]).optional().default("both")
4353
4236
  });
4354
- var relationsSuggestVariant = z13.object({
4355
- action: z13.literal("suggest"),
4356
- entryId: z13.string().max(200),
4357
- limit: z13.number().min(1).max(20).optional().default(10),
4358
- depth: z13.number().min(1).max(3).optional().default(2)
4359
- });
4360
4237
  var relationsActionUnion = z13.discriminatedUnion("action", [
4361
4238
  relationsCreateVariant,
4362
4239
  relationsBatchCreateVariant,
4363
- relationsDismissVariant,
4364
4240
  relationsDeleteVariant,
4365
- relationsFindVariant,
4366
- relationsSuggestVariant
4241
+ relationsFindVariant
4367
4242
  ]);
4368
4243
  var RELATIONS_ACTION_SPECS = {
4369
4244
  create: { params: ["from", "to", "type", "preview"], description: "from, to, and type are required." },
4370
4245
  "batch-create": { params: ["relations"], description: "relations (1-20 items) is required." },
4371
- dismiss: { params: ["from", "to", "type", "score"], description: "from and to are required." },
4372
4246
  delete: { params: ["from", "to", "type"], description: "from, to, and type are required." },
4373
- find: { params: ["entryId", "direction"], description: "entryId is required." },
4374
- suggest: { params: ["entryId", "limit", "depth"], description: "entryId is required." }
4247
+ find: { params: ["entryId", "direction"], description: "entryId is required." }
4375
4248
  };
4376
4249
  function registerRelationsTools(server) {
4377
4250
  const relationsHandlers = {
4378
4251
  create: (data) => handleCreate(data.from, data.to, data.type, data.preview),
4379
4252
  "batch-create": (data) => handleBatchCreate(data.relations),
4380
- dismiss: (data) => handleDismiss(data.from, data.to, data.type ?? "related_to", data.score),
4381
4253
  delete: (data) => handleDelete(data.from, data.to, data.type),
4382
- find: (data) => handleFind(data.entryId, data.direction ?? "both"),
4383
- suggest: (data) => handleSuggest(data.entryId, data.limit ?? 10, data.depth ?? 2)
4254
+ find: (data) => handleFind(data.entryId, data.direction ?? "both")
4384
4255
  };
4385
4256
  server.registerTool(
4386
4257
  "relations",
4387
4258
  {
4388
4259
  title: "Relations",
4389
- description: "Create, manage, and discover relations between entries.\n\n- **create**: Link two entries with a typed relation. Use action=suggest to discover connections.\n- **batch-create**: Create multiple relations in one call (validates every item before writing any). Use after action=suggest.\n- **dismiss**: Record that a suggested link was not relevant. Improves future suggestion quality.\n- **delete**: Remove a relation by from, to, and type.\n- **find**: Traverse relations from a specific entry \u2014 shows incoming/outgoing connections. NOT full-text search (use entries action=search).\n- **suggest**: Discover potential relations for an entry using graph-aware intelligence. Returns ranked suggestions with confidence scores.",
4260
+ description: "Create, manage, and read relations between entries. A relation is written only when you ask for it, with exactly the verb you send.\n\n- **create**: Link two entries with a typed relation.\n- **batch-create**: Create multiple relations in one call (validates every item before writing any).\n- **delete**: Remove a relation by from, to, and type.\n- **find**: Traverse relations from a specific entry \u2014 shows incoming/outgoing connections. NOT full-text search (use entries action=search).",
4390
4261
  inputSchema: relationsSchema,
4391
- // Mixed read/write noun (§3 R3): find/suggest are read-only, create/batch-create/dismiss/delete write.
4262
+ // Mixed read/write noun (§3 R3): find is read-only, create/batch-create/delete write.
4392
4263
  annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
4393
4264
  },
4394
4265
  thinWrapper(async (args) => {
@@ -4572,28 +4443,6 @@ async function handleBatchCreate(relations) {
4572
4443
  )
4573
4444
  };
4574
4445
  }
4575
- async function handleDismiss(from, to, type, score) {
4576
- requireWriteAccess();
4577
- const fromEntry = await kernelQuery("chain.getEntry", { entryId: from });
4578
- if (!fromEntry) {
4579
- return notFoundResult(from);
4580
- }
4581
- const toEntry = await kernelQuery("chain.getEntry", { entryId: to });
4582
- if (!toEntry) {
4583
- return notFoundResult(to);
4584
- }
4585
- await kernelMutation("chain.dismissSuggestion", {
4586
- fromEntryId: fromEntry._id,
4587
- suggestedEntryId: toEntry._id,
4588
- recommendedType: type,
4589
- score: score ?? 0
4590
- });
4591
- return successResult(
4592
- `Dismissed suggestion: ${from} \u2192 ${to} (${type}). Feedback recorded for scoring improvements.`,
4593
- `Dismissed suggestion ${from} \u2192 ${to} (${type}). Feedback recorded.`,
4594
- { from, to, type }
4595
- );
4596
- }
4597
4446
  async function handleDelete(from, to, type) {
4598
4447
  requireWriteAccess();
4599
4448
  await kernelMutation("chain.removeEntryRelation", {
@@ -4877,12 +4726,12 @@ async function handleGather(server, entryId, task, mode, maxHops, maxResults, st
4877
4726
 
4878
4727
  _No relations found._ This entry is not yet connected to the knowledge graph.
4879
4728
 
4880
- Use \`relations action=suggest\` to discover potential connections.`
4729
+ Use \`relations action=create\` to link it to the entries it relates to.`
4881
4730
  }],
4882
4731
  structuredContent: success(
4883
4732
  `No relations found for ${root2.entryId}. Entry not yet connected.`,
4884
4733
  { root: root2, context: [], totalFound: 0 },
4885
- [{ tool: "relations", description: "Discover connections", parameters: { action: "suggest", entryId: root2.entryId } }]
4734
+ [{ tool: "relations", description: "Link it", parameters: { action: "create", from: root2.entryId } }]
4886
4735
  )
4887
4736
  };
4888
4737
  }
@@ -5109,12 +4958,12 @@ _This helps future sessions start with better constraints and context._`
5109
4958
 
5110
4959
  _No relations found._ This entry is not yet connected to the knowledge graph.
5111
4960
 
5112
- Use \`relations action=suggest\` to discover potential connections, or \`relations action=create\` to link manually.`
4961
+ Use \`relations action=create\` to link it.`
5113
4962
  }],
5114
4963
  structuredContent: success(
5115
4964
  `No relations found for ${root.entryId}. Entry not yet connected.`,
5116
4965
  { root, related: [], totalRelations: 0 },
5117
- [{ tool: "relations", description: "Discover connections", parameters: { action: "suggest", entryId: root.entryId } }]
4966
+ [{ tool: "relations", description: "Link it", parameters: { action: "create", from: root.entryId } }]
5118
4967
  )
5119
4968
  };
5120
4969
  }
@@ -5297,14 +5146,14 @@ async function handleNeighborhood(entryId) {
5297
5146
  const isEmpty = result2.blockingChain.length === 0 && result2.dependencyChain.length === 0 && !result2.parentContext && result2.relatedTensions.length === 0;
5298
5147
  if (isEmpty) {
5299
5148
  lines.push(`_No neighborhood data found. Entry may not exist or has no graph connections._`);
5300
- lines.push(`Use \`relations action=suggest\` to discover potential connections.`);
5149
+ lines.push(`Use \`relations action=create\` to link it to the entries it relates to.`);
5301
5150
  }
5302
5151
  return {
5303
5152
  content: [{ type: "text", text: lines.join("\n") }],
5304
5153
  structuredContent: success(
5305
5154
  `Neighborhood for ${entryId}: ${result2.blockingChain.length} blocking, ${result2.dependencyChain.length} dependencies, ${result2.relatedTensions.length} tensions.`,
5306
5155
  result2,
5307
- isEmpty ? [{ tool: "relations", description: "Discover connections", parameters: { action: "suggest", entryId } }] : void 0
5156
+ isEmpty ? [{ tool: "relations", description: "Link it", parameters: { action: "create", from: entryId } }] : void 0
5308
5157
  )
5309
5158
  };
5310
5159
  }
@@ -7274,11 +7123,11 @@ function buildOrientBriefingLines(view, opts) {
7274
7123
  lines.splice(pull < 0 ? lines.length : pull, 0, RULE_LISTS_EVERYONE_ONLY_LABEL, "(none currently served)", "");
7275
7124
  return lines;
7276
7125
  }
7277
- async function fetchAndRenderOpenerDirection(kernelQuery2, errors, session) {
7126
+ async function fetchAndRenderOpenerDirection(kernelQuery3, errors, session) {
7278
7127
  let view = null;
7279
7128
  let fetchFailed = false;
7280
7129
  try {
7281
- view = await kernelQuery2("chain.getOrientView", {
7130
+ view = await kernelQuery3("chain.getOrientView", {
7282
7131
  tier: "standard",
7283
7132
  invocationPath: session?.invocationPath ?? "session-start",
7284
7133
  // Stamps this call onto the current session/conversation/task (same as every other
@@ -7293,9 +7142,9 @@ async function fetchAndRenderOpenerDirection(kernelQuery2, errors, session) {
7293
7142
  }
7294
7143
  return { lines: [...buildOrientBriefingLines(view), ...buildRitualsSurfaceLines(view, { fetchFailed: fetchFailed || view?.fetchFailed === true })], view };
7295
7144
  }
7296
- async function buildAlreadyOrientedResult(kernelQuery2, agentSessionId, taskGroundingWarningLines2) {
7145
+ async function buildAlreadyOrientedResult(kernelQuery3, agentSessionId, taskGroundingWarningLines2) {
7297
7146
  const errors = [];
7298
- const { lines, view } = await fetchAndRenderOpenerDirection(kernelQuery2, errors, { agentSessionId, invocationPath: "manual-orient" });
7147
+ const { lines, view } = await fetchAndRenderOpenerDirection(kernelQuery3, errors, { agentSessionId, invocationPath: "manual-orient" });
7299
7148
  return {
7300
7149
  content: [{
7301
7150
  type: "text",
@@ -8964,7 +8813,7 @@ Use \`workflows action=checkpoint\` after each round to persist progress to the
8964
8813
  label: "Capture & Accept",
8965
8814
  type: "close",
8966
8815
  instruction: "Capture the pitch to the Chain. Accept draft entries. Connect the constellation.",
8967
- facilitatorGuidance: "List all draft entries created during shaping (elements, risks, decisions, glossary terms). Ask the user to confirm: 'Ready to accept these onto the Chain?' Call `session action=commit-constellation` to accept the work package and all linked entries \u2014 sequentially, best-effort per entry; check failedIds and conflictIds. Then `relations action=suggest entryId='<betId>'` to discover connections. Create the top 3 suggested relations via `relations action=batch-create`. Thank the user. State: what was shaped, how many constellation entries captured, what the implementer inherits.",
8816
+ facilitatorGuidance: "List all draft entries created during shaping (elements, risks, decisions, glossary terms). Ask the user to confirm: 'Ready to accept these onto the Chain?' Call `session action=commit-constellation` to accept the work package and all linked entries \u2014 sequentially, best-effort per entry; check failedIds and conflictIds. Then link the work package to the entries it relates to via `relations action=batch-create`. Thank the user. State: what was shaped, how many constellation entries captured, what the implementer inherits.",
8968
8817
  outputSchema: {
8969
8818
  field: "capture",
8970
8819
  description: "Final capture summary \u2014 entries accepted, relations created",
@@ -9156,7 +9005,7 @@ This block is the final deliverable of the review. Everything else is supporting
9156
9005
  label: "Capture & Close",
9157
9006
  type: "close",
9158
9007
  instruction: "Finalize the review as an insight draft. Connect new entries from learning extraction. Use session action=wrapup-review. Thank the participant.",
9159
- facilitatorGuidance: "Summarize the review for finalization. Complete the terminal round through `workflows action=checkpoint` with `isFinal=true` so the workflow substrate creates the draft insight record. Include: BET/feature IDs, verdict, key findings, fixes applied, and the structured verdict block from Round 05. The insight description MUST include the 5-item verdict block (verdict Y/N, what shipped, why it matters, user benefit, how to validate). If learnings were captured in Round 04: run relations action=suggest for each new entry, then relations action=batch-create. Run session action=wrapup-review before closing. Thank the participant. State what was fixed, what was captured, what was deferred.",
9008
+ facilitatorGuidance: "Summarize the review for finalization. Complete the terminal round through `workflows action=checkpoint` with `isFinal=true` so the workflow substrate creates the draft insight record. Include: BET/feature IDs, verdict, key findings, fixes applied, and the structured verdict block from Round 05. The insight description MUST include the 5-item verdict block (verdict Y/N, what shipped, why it matters, user benefit, how to validate). If learnings were captured in Round 04: link each new entry to what it relates to with relations action=batch-create. Run session action=wrapup-review before closing. Thank the participant. State what was fixed, what was captured, what was deferred.",
9160
9009
  outputSchema: {
9161
9010
  field: "capture",
9162
9011
  description: "Insight entry created, WP IDs referenced, learnings connected",
@@ -9221,7 +9070,6 @@ var PROCESS_CHANGE_WORKFLOW_DESCRIPTOR = {
9221
9070
  - \`orient\` \u2014 load workspace context (governance, active work packages, stale entries)
9222
9071
  - \`entries action=search\` \u2014 find related entries
9223
9072
  - \`capture\` \u2014 manual fallback only if workflow finalization cannot safely route the entry
9224
- - \`relations action=suggest\` \u2014 discover connections
9225
9073
  - \`relations action=create\` or \`relations action=batch-create\` \u2014 link to related entries
9226
9074
  - \`entries action=commit\` \u2014 promote to SSOT (only on user confirmation)
9227
9075
  - \`workflows action=checkpoint\` \u2014 save progress if needed
@@ -9281,7 +9129,7 @@ var PROCESS_CHANGE_WORKFLOW_DESCRIPTOR = {
9281
9129
  label: "Capture & Close",
9282
9130
  type: "close",
9283
9131
  instruction: "Capture to the Chain. Link to related entries. Confirm with the user.",
9284
- facilitatorGuidance: "Finalize through workflows action=checkpoint with isFinal=true, passing a summaryName when you have a clean title. The workflow substrate will create the primary record as a draft and attach it to the durable run. After finalization, call relations action=suggest to find connections. Create the top 2-3 relevant relations. Show the user what was captured: entry ID, collection it landed in, relations created. Ask if they want to accept now or leave as draft. If they confirm, use entries action=commit. If there are stale entries to reconfirm, mention them. Thank the user briefly and exit \u2014 don't linger.",
9132
+ facilitatorGuidance: "Finalize through workflows action=checkpoint with isFinal=true, passing a summaryName when you have a clean title. The workflow substrate will create the primary record as a draft and attach it to the durable run. After finalization, link the entry to the 2-3 entries it relates to with relations action=create. Show the user what was captured: entry ID, collection it landed in, relations created. Ask if they want to accept now or leave as draft. If they confirm, use entries action=commit. If there are stale entries to reconfirm, mention them. Thank the user briefly and exit \u2014 don't linger.",
9285
9133
  outputSchema: {
9286
9134
  field: "capture",
9287
9135
  description: "Entry captured, relations created, accept status",
@@ -9731,8 +9579,8 @@ async function handleGetRun(runId, workflowId) {
9731
9579
  run.summary ? [
9732
9580
  {
9733
9581
  tool: "relations",
9734
- description: "Discover connections for the summary entry",
9735
- parameters: { action: "suggest", entryId: run.summary.entryId }
9582
+ description: "See the summary entry's connections",
9583
+ parameters: { action: "find", entryId: run.summary.entryId }
9736
9584
  }
9737
9585
  ] : void 0
9738
9586
  )
@@ -9913,7 +9761,7 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
9913
9761
  `Name: ${result2.summary.name}`,
9914
9762
  "",
9915
9763
  `The summary is captured as a draft. Use \`entries action=commit entryId="${result2.summary.entryId}"\` to promote it to the Chain.`,
9916
- `Use \`relations action=suggest entryId="${result2.summary.entryId}"\` to discover connections.`
9764
+ `Use \`relations action=create\` to link it to the entries it relates to.`
9917
9765
  );
9918
9766
  return {
9919
9767
  content: [{ type: "text", text: lines.join("\n") }],
@@ -9936,8 +9784,8 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
9936
9784
  },
9937
9785
  {
9938
9786
  tool: "relations",
9939
- description: "Discover connections",
9940
- parameters: { action: "suggest", entryId: result2.summary.entryId }
9787
+ description: "See its connections",
9788
+ parameters: { action: "find", entryId: result2.summary.entryId }
9941
9789
  }
9942
9790
  ]
9943
9791
  )
@@ -10112,8 +9960,8 @@ async function handleFacilitatedFinalization(wf, descriptor, roundId, normalized
10112
9960
  [
10113
9961
  {
10114
9962
  tool: "relations",
10115
- description: "Discover connections",
10116
- parameters: { action: "suggest", entryId: summaryEntryId }
9963
+ description: "See its connections",
9964
+ parameters: { action: "find", entryId: summaryEntryId }
10117
9965
  }
10118
9966
  ]
10119
9967
  )
@@ -10418,7 +10266,7 @@ function registerQualityTools(server) {
10418
10266
  "quality",
10419
10267
  {
10420
10268
  title: "Quality",
10421
- description: "Assess, re-evaluate, and verify entry/work package quality. Four actions:\n\n- **check**: Read the entry's server quality verdict (tier + criteria) \u2014 it does not re-score. Suggests links when the entry has no relations.\n- **re-evaluate**: Trigger a fresh quality evaluation. Returns heuristic verdict immediately, schedules LLM evaluation in background.\n- **verify-chain**: Verify knowledge entries against the actual codebase (codeMapping drift, cross-references) \u2014 absorbs `verify`. Produces a trust report with a trust score.\n- **spine-check**: Structural completeness of the purpose+vision+strategy spine \u2014 duplicate singletons, connectedness, per-strategy refusal heuristic; story:true also runs the on-demand one-story LLM judgment (never scheduled, result labelled [unvalidated]). Async: a plain call reads back the latest stored verdict and auto-schedules a new run ONLY when none is already in flight AND the stored one is absent/stale/missing the requested story pass \u2014 repeated polling never re-triggers work. Pass refresh:true to force a fresh run regardless.",
10269
+ description: "Assess, re-evaluate, and verify entry/work package quality. Four actions:\n\n- **check**: Read the entry's server quality verdict (tier + criteria) \u2014 it does not re-score.\n- **re-evaluate**: Trigger a fresh quality evaluation. Returns heuristic verdict immediately, schedules LLM evaluation in background.\n- **verify-chain**: Verify knowledge entries against the actual codebase (codeMapping drift, cross-references) \u2014 absorbs `verify`. Produces a trust report with a trust score.\n- **spine-check**: Structural completeness of the purpose+vision+strategy spine \u2014 duplicate singletons, connectedness, per-strategy refusal heuristic; story:true also runs the on-demand one-story LLM judgment (never scheduled, result labelled [unvalidated]). Async: a plain call reads back the latest stored verdict and auto-schedules a new run ONLY when none is already in flight AND the stored one is absent/stale/missing the requested story pass \u2014 repeated polling never re-triggers work. Pass refresh:true to force a fresh run regardless.",
10422
10270
  inputSchema: qualitySchema,
10423
10271
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }
10424
10272
  },
@@ -10433,30 +10281,6 @@ function registerQualityTools(server) {
10433
10281
  })
10434
10282
  );
10435
10283
  }
10436
- async function appendLinkSuggestions(entryId, lines) {
10437
- let relationCount = -1;
10438
- try {
10439
- const relations = await kernelQuery("chain.listEntryRelations", { entryId });
10440
- relationCount = relations?.length ?? 0;
10441
- } catch {
10442
- return;
10443
- }
10444
- if (relationCount !== 0) return;
10445
- try {
10446
- const suggestions = await kernelQuery("chain.graphSuggestLinks", {
10447
- entryId,
10448
- maxHops: 2,
10449
- limit: 3
10450
- });
10451
- if ((suggestions?.suggestions?.length ?? 0) > 0) {
10452
- const linkHints = (suggestions.suggestions ?? []).map((s) => ` \u2192 \`relations action=create from="${entryId}" to="${s.entryId}" type="${s.recommendedRelationType}"\` \u2014 ${s.name} [${s.collectionSlug}] (${s.score}/100)`).join("\n");
10453
- lines.push(`
10454
- ## Suggested Links to Improve Quality
10455
- ${linkHints}`);
10456
- }
10457
- } catch {
10458
- }
10459
- }
10460
10284
  async function handleCheck(entryId) {
10461
10285
  const res = await kernelQuery("quality.getLatestVerdictForEntry", { entryId });
10462
10286
  if (!res || !res.entryFound) {
@@ -10476,7 +10300,6 @@ Entry \`${entryId}\` not found. Use \`search\` to find the right ID.`,
10476
10300
  "",
10477
10301
  `No quality verdict yet for \`${entryId}\`. Run \`quality action=re-evaluate entryId="${entryId}"\` to evaluate it.`
10478
10302
  ];
10479
- await appendLinkSuggestions(entryId, lines2);
10480
10303
  return successResult(
10481
10304
  lines2.join("\n"),
10482
10305
  `No quality verdict yet for ${entryId} \u2014 re-evaluate to produce one.`,
@@ -10497,7 +10320,6 @@ Entry \`${entryId}\` not found. Use \`search\` to find the right ID.`,
10497
10320
  const verdictSection = formatRubricVerdictSection(verdict);
10498
10321
  lines.push(verdictSection || `Verdict tier \`${verdict.tier ?? "unknown"}\` for \`${entryId}\` \u2014 no rubric criteria to report.`);
10499
10322
  }
10500
- await appendLinkSuggestions(entryId, lines);
10501
10323
  try {
10502
10324
  const wsForTracking = await getWorkspaceContext();
10503
10325
  trackQualityCheck(wsForTracking.workspaceId, {
@@ -10526,9 +10348,7 @@ Entry \`${entryId}\` not found. Use \`search\` to find the right ID.`,
10526
10348
  ...res.stale ? {} : { passed: verdict.passed },
10527
10349
  criteria: res.stale ? [] : criteria.map((c) => ({ id: c.id, passed: c.passed, hint: c.hint }))
10528
10350
  },
10529
- [
10530
- { tool: "relations", description: "Suggest connections", parameters: { action: "suggest", entryId } }
10531
- ]
10351
+ []
10532
10352
  );
10533
10353
  }
10534
10354
  async function handleReEvaluate(entryId, context) {
@@ -10617,25 +10437,6 @@ function composeWrapupView(raw) {
10617
10437
  }
10618
10438
 
10619
10439
  // src/tools/wrapup.ts
10620
- async function mapWithConcurrency(items, mapper, concurrency = 3) {
10621
- const results = new Array(items.length);
10622
- let index = 0;
10623
- async function runNext() {
10624
- while (index < items.length) {
10625
- const i = index++;
10626
- try {
10627
- const value = await mapper(items[i]);
10628
- results[i] = { status: "fulfilled", value };
10629
- } catch (reason) {
10630
- results[i] = { status: "rejected", reason };
10631
- }
10632
- }
10633
- }
10634
- await Promise.all(
10635
- Array.from({ length: Math.min(concurrency, items.length) }, () => runNext())
10636
- );
10637
- return results;
10638
- }
10639
10440
  function isValidTopGap(g) {
10640
10441
  if (typeof g !== "object" || g === null) return false;
10641
10442
  const obj = g;
@@ -10657,40 +10458,13 @@ async function fetchSessionCoherenceSnapshot(sessionId) {
10657
10458
  }
10658
10459
  return null;
10659
10460
  }
10660
- async function suggestLinksForEntries(entries) {
10661
- const suggestions = [];
10662
- const results = await mapWithConcurrency(
10663
- entries,
10664
- async (entry) => {
10665
- const result2 = await kernelQuery("chain.graphSuggestLinks", {
10666
- entryId: entry.entryId,
10667
- limit: 3
10668
- });
10669
- return { entry, suggestions: result2.suggestions ?? [] };
10670
- },
10671
- 3
10672
- );
10673
- for (const result2 of results) {
10674
- if (result2.status !== "fulfilled") continue;
10675
- const { entry, suggestions: entrySuggestions } = result2.value;
10676
- for (const s of entrySuggestions.filter((x) => x.entryId != null).slice(0, 2)) {
10677
- suggestions.push({
10678
- fromEntryId: entry.entryId,
10679
- toEntryId: s.entryId,
10680
- type: s.recommendedRelationType,
10681
- label: `${entry.entryId} \u2192 ${s.entryId} (${s.name}) [${s.recommendedRelationType}]`
10682
- });
10683
- }
10684
- }
10685
- return suggestions;
10686
- }
10687
10461
  async function runWrapupReview() {
10688
10462
  const sessionId = getAgentSessionId();
10689
10463
  if (!sessionId) {
10690
- return { text: "No active agent session. Call `session action=start` first.", data: null, suggestions: [], failureCode: "SESSION_REQUIRED" };
10464
+ return { text: "No active agent session. Call `session action=start` first.", data: null, failureCode: "SESSION_REQUIRED" };
10691
10465
  }
10692
10466
  if (getApiKeyScope() === "read") {
10693
- return { text: "Read-only session \u2014 nothing to review.", data: null, suggestions: [], failureCode: "READONLY_SCOPE" };
10467
+ return { text: "Read-only session \u2014 nothing to review.", data: null, failureCode: "READONLY_SCOPE" };
10694
10468
  }
10695
10469
  const { workspaceId } = await getWorkspaceContext();
10696
10470
  const kernelEnvelope = await kernelCallEnvelope("agentKnowledge.wrapupEnvelope", {
@@ -10703,10 +10477,10 @@ async function runWrapupReview() {
10703
10477
  const overflowUnscanned = data.overflowUnscanned ?? 0;
10704
10478
  const loopEmpty = data.drafts.length === 0 && overflowDraftCount === 0 && overflowUnscanned === 0;
10705
10479
  if (data.wrapupCompletedAt && loopEmpty) {
10706
- return { text: "Wrapup already completed this session.", data, suggestions: [], failureCode: "ALREADY_COMPLETED" };
10480
+ return { text: "Wrapup already completed this session.", data, failureCode: "ALREADY_COMPLETED" };
10707
10481
  }
10708
10482
  if (data.drafts.length === 0 && data.committed.length === 0 && overflowDraftCount === 0 && (data.overflowCommitted ?? []).length === 0) {
10709
- return { text: "Empty session \u2014 no entries to review.", data, suggestions: [], failureCode: "NOT_FOUND" };
10483
+ return { text: "Empty session \u2014 no entries to review.", data, failureCode: "NOT_FOUND" };
10710
10484
  }
10711
10485
  const lines = [];
10712
10486
  lines.push(
@@ -10751,17 +10525,6 @@ async function runWrapupReview() {
10751
10525
  }
10752
10526
  lines.push("");
10753
10527
  }
10754
- const lowConnEntries = [...data.drafts, ...data.committed].filter(
10755
- (e) => (data.connectionCounts[e.entryId] ?? 0) < 2
10756
- );
10757
- const suggestions = lowConnEntries.length > 0 ? await suggestLinksForEntries(lowConnEntries.slice(0, 10)) : [];
10758
- if (suggestions.length > 0) {
10759
- lines.push("### Suggested Links (not written; wrapup-commit writes none \u2014 create the ones you want with `relations action=create`)", "");
10760
- for (const s of suggestions) {
10761
- lines.push(`- ${s.label}`);
10762
- }
10763
- lines.push("");
10764
- }
10765
10528
  const topGaps = getTopGaps(5);
10766
10529
  if (topGaps.length > 0) {
10767
10530
  lines.push("### Learning Opportunities", "");
@@ -10860,7 +10623,6 @@ async function runWrapupReview() {
10860
10623
  return {
10861
10624
  text: lines.join("\n"),
10862
10625
  data,
10863
- suggestions,
10864
10626
  gapCount,
10865
10627
  coherenceVerdict,
10866
10628
  persistentGaps,
@@ -10993,7 +10755,7 @@ function createWrapupHandler() {
10993
10755
  commitNext
10994
10756
  );
10995
10757
  }
10996
- const { text, data, suggestions, failureCode, gapCount, coherenceVerdict, persistentGaps, kernelSummary, kernelNext, kernelMeta } = await runWrapupReview();
10758
+ const { text, data, failureCode, gapCount, coherenceVerdict, persistentGaps, kernelSummary, kernelNext, kernelMeta } = await runWrapupReview();
10997
10759
  lastReviewData = data;
10998
10760
  lastReviewSessionId = getAgentSessionId();
10999
10761
  const composed = data ? composeWrapupView(data) : null;
@@ -11010,7 +10772,7 @@ ${text}` : text;
11010
10772
  const persistentSummary = persistentGaps?.length ? `, ${persistentGaps.length} persistent coherence gaps` : "";
11011
10773
  const draftsCount = composed?.drafts.length ?? data.drafts.length;
11012
10774
  const committedCount = composed?.committed.length ?? data.committed.length;
11013
- const summaryText = `Session review: ${draftsCount} uncommitted, ${committedCount} committed, ${suggestions.length} link suggestions${gapsSummary}${coherenceSummary}${persistentSummary}.`;
10775
+ const summaryText = `Session review: ${draftsCount} uncommitted, ${committedCount} committed${gapsSummary}${coherenceSummary}${persistentSummary}.`;
11014
10776
  return {
11015
10777
  content: [{ type: "text", text: fullText }],
11016
10778
  structuredContent: {
@@ -11020,7 +10782,6 @@ ${text}` : text;
11020
10782
  drafts: draftsCount,
11021
10783
  committed: committedCount,
11022
10784
  uncommitted: data.summary.uncommitted,
11023
- suggestedLinks: suggestions.length,
11024
10785
  knowledgeGaps: gapCount ?? 0,
11025
10786
  ...coherenceVerdict ? { coherenceVerdict } : {},
11026
10787
  ...persistentGaps?.length ? { persistentCoherenceGaps: persistentGaps.length } : {}
@@ -11393,7 +11154,7 @@ function registerSessionTools(server) {
11393
11154
  "session",
11394
11155
  {
11395
11156
  title: "Session \u2014 Lifecycle & Facilitation",
11396
- description: "Session lifecycle, wrapup review, and work package facilitation.\n\n- **start**: Begin a tracked write session for attribution. **This is the ONLY call that creates a session** \u2014 write tools (capture, entries action=update/commit, relations) require it. `orient action=start` orients an existing session and loads stage-aware context, but does NOT create one: call `session action=start` first, then `orient action=start`.\n- **close**: End the current session. Records structured data (entries created, modified, relations). Run `session action=wrapup-review` before closing.\n- **status**: Check current session \u2014 active or not, oriented, activity counts.\n- **wrapup-review**: Review uncommitted drafts with quality scores, suggested links. Run before close.\n- **wrapup-commit**: Accept all uncommitted drafts. Writes no relations; create the ones you want with relations action=create.\n- **resume**: Load session state (work package data, constellation, drafts) from an existing work package entry.\n- **commit-constellation**: Atomically accept a work package and all its linked draft entries in one call.",
11157
+ description: "Session lifecycle, wrapup review, and work package facilitation.\n\n- **start**: Begin a tracked write session for attribution. **This is the ONLY call that creates a session** \u2014 write tools (capture, entries action=update/commit, relations) require it. `orient action=start` orients an existing session and loads stage-aware context, but does NOT create one: call `session action=start` first, then `orient action=start`.\n- **close**: End the current session. Records structured data (entries created, modified, relations). Run `session action=wrapup-review` before closing.\n- **status**: Check current session \u2014 active or not, oriented, activity counts.\n- **wrapup-review**: Review uncommitted drafts with quality scores. Run before close.\n- **wrapup-commit**: Accept all uncommitted drafts. Writes no relations; create the ones you want with relations action=create.\n- **resume**: Load session state (work package data, constellation, drafts) from an existing work package entry.\n- **commit-constellation**: Atomically accept a work package and all its linked draft entries in one call.",
11397
11158
  inputSchema: sessionSchema,
11398
11159
  // Mixed read/write noun (§3 R3): wrapup-commit/resume/commit-constellation write.
11399
11160
  annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
@@ -13132,7 +12893,7 @@ var AGENT_CHEATSHEET = `# Product Brain \u2014 Agent Cheatsheet
13132
12893
  | \`orient\` | Workspace context, governance, active work packages, session start | \`action\`: start, task |
13133
12894
  | \`capture\` | Create entry | \`action\`: capture |
13134
12895
  | \`entries\` | Read and write entries | \`action\`: list, get, batch, search, update, commit, history, move, verify, preflight, still-true |
13135
- | \`relations\` | Link entries, dismiss suggestions and delete links, find and suggest | \`action\`: create, batch-create, dismiss, delete, find, suggest |
12896
+ | \`relations\` | Link entries, delete links, find connections | \`action\`: create, batch-create, delete, find |
13136
12897
  | \`context\` | Gather related knowledge, last-verified brief | \`action\`: gather, build, neighborhood, changes, chain, cross-cut, incremental, brief, last-verified-brief |
13137
12898
  | \`collections\` | Browse, describe, audit and export collections; manage labels | \`action\`: list, update, describe, audit, export, label-* |
13138
12899
  | \`quality\` | Score an entry, verify the Chain, spine check | \`action\`: check, re-evaluate, verify-chain, spine-check |
@@ -13169,7 +12930,7 @@ Write via \`update\`: \`draft\` | \`archived\` (\`accepted\` via \`commit\`, nev
13169
12930
  - A rule on no list binds nobody; a full list refuses a new rule until one retires, and a list over its cap is served whole.
13170
12931
 
13171
12932
  ## Key Patterns
13172
- - **Capture flow:** \`capture\` \u2192 \`relations action=suggest\` \u2192 \`relations action=batch-create\` \u2192 \`entries action=commit\`
12933
+ - **Capture flow:** \`capture\` \u2192 \`relations action=batch-create\` \u2192 \`entries action=commit\`
13173
12934
  - Use \`workflowStatus\` (not \`status\`) for domain workflow state
13174
12935
  - \`data\` param is merged (not replaced) \u2014 safe for partial updates
13175
12936
  `;
@@ -13211,13 +12972,13 @@ Tags for filtering (e.g. \`severity:high\`), relations via \`entryRelations\`, v
13211
12972
  '## Rules\nThe rules that bind you are in the briefing above, each with its why. A rule on no list binds nobody.\nOpen one: `entries action=get entryId="<ID>"`. Find one: `entries action=search query="<noun>"`.\nDraft a new rule: use the `draft-rule-from-context` prompt.'
13212
12973
  );
13213
12974
  sections.push(
13214
- "## Knowledge Graph\nEntries are connected via typed relations (`entryRelations` table). Relations are bidirectional and collection-agnostic \u2014 any entry can link to any other entry.\n\n**Recommended relation types** (extensible \u2014 any string accepted):\n- `governs` \u2014 a rule constrains behavior of a feature\n- `defines_term_for` \u2014 a glossary term is canonical vocabulary for a feature/area\n- `belongs_to` \u2014 a feature belongs to a product area or parent concept (typed successor: `anchored_to`)\n- `informs` \u2014 a decision or insight informs a feature\n- `surfaces_tension_in` \u2014 a tension exists within a feature area\n- `related_to`, `depends_on`, `replaces`, `conflicts_with`, `references`, `confused_with`\n\nEach relation type is defined as a glossary entry (prefix `GT-REL-*`) to prevent terminology drift.\n\n**Tools:**\n- `context action=gather` \u2014 get the full context around any entry (multi-hop graph traversal)\n- `relations action=suggest` \u2014 discover potential connections for an entry\n- `relations action=create` \u2014 create a typed link between two entries\n- `relations action=find` \u2014 list direct relations for an entry\n\n**Convention:** When creating or updating entries in governed collections, always use `relations action=suggest` to discover and create relevant relations."
12975
+ "## Knowledge Graph\nEntries are connected via typed relations (`entryRelations` table). Relations are bidirectional and collection-agnostic \u2014 any entry can link to any other entry.\n\n**Recommended relation types** (extensible \u2014 any string accepted):\n- `governs` \u2014 a rule constrains behavior of a feature\n- `defines_term_for` \u2014 a glossary term is canonical vocabulary for a feature/area\n- `belongs_to` \u2014 a feature belongs to a product area or parent concept (typed successor: `anchored_to`)\n- `informs` \u2014 a decision or insight informs a feature\n- `surfaces_tension_in` \u2014 a tension exists within a feature area\n- `related_to`, `depends_on`, `replaces`, `conflicts_with`, `references`, `confused_with`\n\nEach relation type is defined as a glossary entry (prefix `GT-REL-*`) to prevent terminology drift.\n\n**Tools:**\n- `context action=gather` \u2014 get the full context around any entry (multi-hop graph traversal)\n- `relations action=create` \u2014 create a typed link between two entries\n- `relations action=find` \u2014 list direct relations for an entry\n\n**Convention:** A relation is written only when you ask for it, with exactly the verb you send \u2014 link the entries you know are related with `relations action=create`."
13215
12976
  );
13216
12977
  sections.push(
13217
12978
  `## Creating Knowledge
13218
12979
  **Entries:** Use \`capture\` as the primary tool for creating new entries. It handles the full workflow in one call:
13219
12980
  1. Creates the entry with collection-aware defaults (auto-fills dates, infers domains, sets priority)
13220
- 2. Writes the relations you pass in \`links\` \u2014 and no others; use \`relations action=suggest\` then \`relations action=create\` to add more
12981
+ 2. Writes the relations you pass in \`links\` \u2014 and no others; use \`relations action=create\` to add more
13221
12982
  3. Returns the server's quality verdict with improvement hints
13222
12983
 
13223
12984
  **Smart profiles** exist for: ${SMART_PROFILE_COLLECTIONS.map((c) => `\`${c}\``).join(", ")}.
@@ -13234,14 +12995,14 @@ Use \`quality action=check\` to score existing entries retroactively.
13234
12995
  Use \`entries action=update\` for post-creation adjustments (status changes, field updates, deprecation).`
13235
12996
  );
13236
12997
  sections.push(
13237
- "## Where to Go Next\n- **Create entry** \u2192 `capture` tool (entry, the links you pass, and a quality verdict in one call)\n- **Full context** \u2192 `context action=gather` (by entry ID or task description)\n- **Discover links** \u2192 `relations action=suggest`\n- **Quality audit** \u2192 `quality action=check`\n- **Terminology** \u2192 `name-check` prompt or `productbrain://terminology` resource\n- **Schema details** \u2192 `productbrain://collections` resource or `collections action=list`\n- **Labels** \u2192 `productbrain://labels` resource or `collections action=label-list`\n- **Any collection** \u2192 `productbrain://{slug}/entries` resource\n- **Log a decision** \u2192 `draft-decision-record` prompt\n- **Growth funnel** \u2192 `productbrain://growth-funnel` resource or `entries action=list collection=strategy status=draft`\n- **Session identity** \u2192 `workspace action=whoami`\n- **Health check** \u2192 `workspace action=check`\n- **Debug MCP calls** \u2192 `workspace action=audit`"
12998
+ "## Where to Go Next\n- **Create entry** \u2192 `capture` tool (entry, the links you pass, and a quality verdict in one call)\n- **Full context** \u2192 `context action=gather` (by entry ID or task description)\n- **Link entries** \u2192 `relations action=create`\n- **Quality audit** \u2192 `quality action=check`\n- **Terminology** \u2192 `name-check` prompt or `productbrain://terminology` resource\n- **Schema details** \u2192 `productbrain://collections` resource or `collections action=list`\n- **Labels** \u2192 `productbrain://labels` resource or `collections action=label-list`\n- **Any collection** \u2192 `productbrain://{slug}/entries` resource\n- **Log a decision** \u2192 `draft-decision-record` prompt\n- **Growth funnel** \u2192 `productbrain://growth-funnel` resource or `entries action=list collection=strategy status=draft`\n- **Session identity** \u2192 `workspace action=whoami`\n- **Health check** \u2192 `workspace action=check`\n- **Debug MCP calls** \u2192 `workspace action=audit`"
13238
12999
  );
13239
13000
  return sections.join("\n\n---\n\n");
13240
13001
  }
13241
- async function buildOrientationResourceText(kernelQuery2, agentSessionId) {
13002
+ async function buildOrientationResourceText(kernelQuery3, agentSessionId) {
13242
13003
  const [collectionsResult, orientViewResult] = await Promise.allSettled([
13243
- kernelQuery2("chain.listCollections"),
13244
- kernelQuery2("chain.getOrientView", {
13004
+ kernelQuery3("chain.listCollections"),
13005
+ kernelQuery3("chain.getOrientView", {
13245
13006
  tier: "summary",
13246
13007
  invocationPath: "unknown",
13247
13008
  ...agentSessionId ? { sessionId: agentSessionId } : {}
@@ -13822,10 +13583,10 @@ var INSTRUCTIONS = [
13822
13583
  "",
13823
13584
  "## Writing",
13824
13585
  "",
13825
- "Write actions (capture, entries update and commit, relations create, batch-create, dismiss and delete) need an active session and a readwrite key.",
13586
+ "Write actions (capture, entries update and commit, relations create, batch-create and delete) need an active session and a readwrite key.",
13826
13587
  "Pass the `sessionId` that `session action=start` returned on every write: the connection does not remember it.",
13827
13588
  "Use `capture` to create an entry and read its reply: an entry that came back accepted needs no `entries action=commit`.",
13828
- "Link with `relations action=suggest`, then `relations action=create`.",
13589
+ "Link entries with `relations action=create` \u2014 a relation is written only when you ask, with exactly the verb you send.",
13829
13590
  "Finish with `session action=wrapup-review`, then `session action=close`.",
13830
13591
  "If the work falls outside the active work packages, name the gap and ask the user before designing it.",
13831
13592
  "",
@@ -13923,4 +13684,4 @@ export {
13923
13684
  createProductBrainServer,
13924
13685
  initFeatureFlags
13925
13686
  };
13926
- //# sourceMappingURL=chunk-QV6OOBAC.js.map
13687
+ //# sourceMappingURL=chunk-OEONSR7Q.js.map