@productbrain/mcp 0.0.1-beta.8423 → 0.0.1-beta.8425
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.
|
@@ -5033,7 +5033,7 @@ var contextSchema = z15.object({
|
|
|
5033
5033
|
),
|
|
5034
5034
|
direction: z15.enum(["outgoing", "incoming"]).default("outgoing").optional().describe("For 'chain' action: traversal direction. 'outgoing' follows relations from source, 'incoming' follows relations to source. Default: outgoing."),
|
|
5035
5035
|
relationType: z15.string().max(200).optional().describe(
|
|
5036
|
-
"Relation type filter. For 'chain': optional filter to traverse only this relation type. For 'cross-cut': required \u2014 scans all relations of this type across the workspace. Examples: 'part_of', 'informs', 'governs', '
|
|
5036
|
+
"Relation type filter. For 'chain': optional filter to traverse only this relation type. For 'cross-cut': required \u2014 scans all relations of this type across the workspace. Examples: 'part_of', 'informs', 'governs', 'depends_on'."
|
|
5037
5037
|
),
|
|
5038
5038
|
mode: z15.enum(["search", "graph"]).default("search").optional().describe("For gather: 'search' (default) or 'graph' (enhanced with provenance paths). Ignored when mapEntryId is provided."),
|
|
5039
5039
|
maxHops: z15.number().min(1).max(4).default(2).describe("Relation traversal depth (1=direct only, 2=default, 3=wide net, 4=deep chain walk)"),
|
|
@@ -8677,14 +8677,11 @@ async function _handleOrient({ mode = "full", tier, task, startupSignals, invoca
|
|
|
8677
8677
|
const fmt = (e) => {
|
|
8678
8678
|
const type = e.canonicalKey ?? "generic";
|
|
8679
8679
|
const stratum = e.stratum ?? "?";
|
|
8680
|
-
const confidencePart = e.confidence ? ` [confidence: ${e.confidence}]` : "";
|
|
8681
|
-
const reviewOverdue = e.reviewAt && new Date(e.reviewAt).getTime() < Date.now();
|
|
8682
|
-
const overduePart = reviewOverdue ? " [review overdue]" : "";
|
|
8683
8680
|
const originPart = e.origin ? ` (origin: ${e.origin})` : "";
|
|
8684
8681
|
const mark = provenanceMark(e.provenance);
|
|
8685
8682
|
const anchorSuffix = e.anchoredBy ? ` (${e.anchoredBy})` : "";
|
|
8686
8683
|
const coherencyPart = coherencyCheckTag(e.coherencyCheckStatus);
|
|
8687
|
-
return `- ${mark}\`${e.entryId ?? e._id}\` [${type} \xB7 ${stratum}] ${e.name}${anchorSuffix}${originPart}${
|
|
8684
|
+
return `- ${mark}\`${e.entryId ?? e._id}\` [${type} \xB7 ${stratum}] ${e.name}${anchorSuffix}${originPart}${coherencyPart}`;
|
|
8688
8685
|
};
|
|
8689
8686
|
const fullCoherence = await buildCoherenceSection();
|
|
8690
8687
|
if (fullCoherence) {
|
|
@@ -10729,9 +10726,9 @@ var auditSchema = z21.object({
|
|
|
10729
10726
|
"'run': run the hygiene audit for a work package entry."
|
|
10730
10727
|
),
|
|
10731
10728
|
entryId: z21.string().describe("Work package entry ID to audit, e.g. '<PREFIX>-<n>'"),
|
|
10732
|
-
// Chain: WP-770 K2, DEC-1796 — doneWhen
|
|
10729
|
+
// Chain: WP-770 K2, DEC-1796 — doneWhen runs unconditionally (DEC-1852) in both phases.
|
|
10733
10730
|
phase: z21.enum(["shaping", "handoff"]).default("shaping").optional().describe(
|
|
10734
|
-
"'shaping': run the core hygiene gates only. 'handoff': also runs the outcome-coupling gates (KR linkage, verification window). doneWhen
|
|
10731
|
+
"'shaping': run the core hygiene gates only. 'handoff': also runs the outcome-coupling gates (KR linkage, verification window). doneWhen is checked unconditionally either way. Default: shaping."
|
|
10735
10732
|
)
|
|
10736
10733
|
});
|
|
10737
10734
|
async function handleAuditRun(entryId, phase) {
|
|
@@ -11015,9 +11012,9 @@ var qualitySchema = z22.object({
|
|
|
11015
11012
|
context: z22.enum(["capture", "commit", "review"]).default("review").optional().describe("For re-evaluate: evaluation context"),
|
|
11016
11013
|
collection: z22.string().max(200).optional().describe("For 'verify-chain': collection slug to verify (default: glossary)."),
|
|
11017
11014
|
mode: z22.enum(["report", "fix"]).optional().describe("For 'verify-chain': 'report' = read-only trust report (default). 'fix' = also update drifted codeMapping statuses."),
|
|
11018
|
-
// Chain: WP-770 K2, DEC-1796 — doneWhen
|
|
11015
|
+
// Chain: WP-770 K2, DEC-1796 — doneWhen runs unconditionally (DEC-1852) in both phases.
|
|
11019
11016
|
phase: z22.enum(["shaping", "handoff"]).optional().describe(
|
|
11020
|
-
"For 'audit': 'shaping' runs the core hygiene gates only (default). 'handoff' also runs the outcome-coupling gates (KR linkage, verification window). doneWhen
|
|
11017
|
+
"For 'audit': 'shaping' runs the core hygiene gates only (default). 'handoff' also runs the outcome-coupling gates (KR linkage, verification window). doneWhen is checked unconditionally either way."
|
|
11021
11018
|
),
|
|
11022
11019
|
story: z22.boolean().optional().describe("For 'spine-check': also run the on-demand one-story LLM judgment (never scheduled; result labelled [unvalidated])."),
|
|
11023
11020
|
refresh: z22.boolean().optional().describe(
|
|
@@ -13797,6 +13794,83 @@ import { dirname, join, resolve as resolve4 } from "path";
|
|
|
13797
13794
|
import { fileURLToPath } from "url";
|
|
13798
13795
|
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
13799
13796
|
|
|
13797
|
+
// src/lib/relationTypes.ts
|
|
13798
|
+
var ALLOWED_RELATION_TYPES_LIST = [
|
|
13799
|
+
// Core semantic types (in RELATION_TYPE_REGISTRY)
|
|
13800
|
+
"informs",
|
|
13801
|
+
"governs",
|
|
13802
|
+
"surfaces_tension_in",
|
|
13803
|
+
"defines_term_for",
|
|
13804
|
+
"belongs_to",
|
|
13805
|
+
"references",
|
|
13806
|
+
"related_to",
|
|
13807
|
+
"fills_slot",
|
|
13808
|
+
"commits_to",
|
|
13809
|
+
"informed_by",
|
|
13810
|
+
"depends_on",
|
|
13811
|
+
"conflicts_with",
|
|
13812
|
+
"confused_with",
|
|
13813
|
+
// WP-449: Glossary Foundation — negative assertion for agents (spec §4.5)
|
|
13814
|
+
"do_not_confuse_with",
|
|
13815
|
+
"replaces",
|
|
13816
|
+
"part_of",
|
|
13817
|
+
"constrains",
|
|
13818
|
+
// Epistemic types — evidence linking
|
|
13819
|
+
"validates",
|
|
13820
|
+
"invalidates",
|
|
13821
|
+
// Extended types (used in codebase, not in RELATION_TYPE_REGISTRY yet)
|
|
13822
|
+
"governed_by",
|
|
13823
|
+
"alternative_to",
|
|
13824
|
+
"has_proposal",
|
|
13825
|
+
"requests_promotion_of",
|
|
13826
|
+
"resolves",
|
|
13827
|
+
// WP-228 Slice 0: Playing Field relation types
|
|
13828
|
+
"experiences",
|
|
13829
|
+
"addresses",
|
|
13830
|
+
// Tier 1 Hierarchy: DEC-401 (experiments prereqs), DEC-402 (risk views)
|
|
13831
|
+
"threatens",
|
|
13832
|
+
"tests",
|
|
13833
|
+
"produces",
|
|
13834
|
+
// WP-274: Capability tier relation types
|
|
13835
|
+
"realizes",
|
|
13836
|
+
"requires",
|
|
13837
|
+
"invests_in",
|
|
13838
|
+
"enables",
|
|
13839
|
+
// PARKED (park note, 2026-08-23) — these 5 verbs are untouched by a separate
|
|
13840
|
+
// governance-verb-ownership review: no delete, no lock, no whitelist, no picker change,
|
|
13841
|
+
// and no relation of this note to that review. Live source-canonicalKey row counts, from
|
|
13842
|
+
// a read-only pass over an uncapped, exhaustive census of a real workspace (measured
|
|
13843
|
+
// 2026-08-23): follows = 11 rows (decision 2, milestone 5, work_package 4);
|
|
13844
|
+
// extracted_from = 4 rows (decision 1, insight 1, tension 1, work_package 1);
|
|
13845
|
+
// part_of_workstream = 0 rows; stated_by = 0 rows; discussed_in = 0 rows. Whether any of
|
|
13846
|
+
// these should be retired, merged, or promoted is a founder call, deliberately deferred —
|
|
13847
|
+
// not decided here, and not decided by silence either. Re-verify the counts before acting
|
|
13848
|
+
// on them; they will drift.
|
|
13849
|
+
// WP-344 S0a: Evolve-First Ingestion relation types
|
|
13850
|
+
"follows",
|
|
13851
|
+
// sequential/derived — new entry follows/continues from another
|
|
13852
|
+
"extracted_from",
|
|
13853
|
+
// provenance — this entry was extracted from a source document
|
|
13854
|
+
// WP-353 S0: scope-propagated commit relation types (DEC-A captured as exploring per RULE-187)
|
|
13855
|
+
"part_of_workstream",
|
|
13856
|
+
// entry belongs to a workstream anchor confirmed at scope step
|
|
13857
|
+
"stated_by",
|
|
13858
|
+
// entry was stated by a speaker in the source document
|
|
13859
|
+
"discussed_in",
|
|
13860
|
+
// entry was discussed within a particular meeting/doc context
|
|
13861
|
+
// Specification types — WP-363 E2: precision alternatives to governs for decision→governance relations
|
|
13862
|
+
"specializes",
|
|
13863
|
+
// DEC narrows or refines a broader STD/PRI — more specific application of the parent
|
|
13864
|
+
"implements",
|
|
13865
|
+
// DEC/WP realizes a BR/STD in concrete operational form
|
|
13866
|
+
// WP-641 S2a (WP-647): belongs_to vocabulary split — the strategy-scope successor.
|
|
13867
|
+
// The other two successors (authority_domain, domain_routed_to) and `blocks` are no longer
|
|
13868
|
+
// legal to write: a new workspace carries none of them (DEC-1845, TASK-331, TASK-425).
|
|
13869
|
+
"anchored_to"
|
|
13870
|
+
// strategy-scope anchor: a raw strategy entry belongs_to a product (DEC-1523)
|
|
13871
|
+
];
|
|
13872
|
+
var ALLOWED_RELATION_TYPES = new Set(ALLOWED_RELATION_TYPES_LIST);
|
|
13873
|
+
|
|
13800
13874
|
// src/resources/agentCheatsheet.ts
|
|
13801
13875
|
var DATA_HANDLING_SECTION = "### How PB Handles Your Data\n- **The reply is the source of truth**: every reply carries `ok`; on failure it carries `code` and guidance. Read the reply, never an expectation.\n- **Empty-workspace safe**: the orientation resource and this cheatsheet render on a workspace with no entries and no collections.\n- **Workspace-agnostic**: PB is one product used by many teams. Nothing in these instructions is specific to your workspace; your own principles, standards and rules arrive through `productbrain://orientation`.\n- **Served, not installed**: these instructions, `productbrain://orientation` and `productbrain://agent-cheatsheet` are served over MCP.";
|
|
13802
13876
|
var AGENT_CHEATSHEET = `# Product Brain \u2014 Agent Cheatsheet
|
|
@@ -13828,12 +13902,8 @@ DEC (decisions), STR (strategy), TEN (tensions), FEAT (features),
|
|
|
13828
13902
|
BET (bets), INS (insights), ARCH (architecture), TEAM (teams),
|
|
13829
13903
|
ROL (roles), MTRC (tracking-events), ST (semantic-types)
|
|
13830
13904
|
|
|
13831
|
-
## Valid Relation Types (
|
|
13832
|
-
|
|
13833
|
-
references, related_to, fills_slot, commits_to, informed_by, depends_on,
|
|
13834
|
-
conflicts_with, confused_with, replaces, part_of, constrains,
|
|
13835
|
-
governed_by, alternative_to, has_proposal, requests_promotion_of, resolves,
|
|
13836
|
-
anchored_to, authority_domain, domain_routed_to
|
|
13905
|
+
## Valid Relation Types (${ALLOWED_RELATION_TYPES_LIST.length})
|
|
13906
|
+
${ALLOWED_RELATION_TYPES_LIST.join(", ")}
|
|
13837
13907
|
|
|
13838
13908
|
## Lifecycle Status
|
|
13839
13909
|
Write via \`update\`: \`draft\` | \`archived\` (\`accepted\` via \`commit\`, never \`update\`). \`active\`/\`deprecated\` are legacy: readable, refused on write.
|
|
@@ -13872,7 +13942,7 @@ function buildOrientationMarkdown(collections, standards, businessRules, princip
|
|
|
13872
13942
|
wsRules.push({ id: s.entryId ?? "", name: s.name, severity: s.data?.severity ?? void 0, source: "standards" });
|
|
13873
13943
|
}
|
|
13874
13944
|
for (const r of businessRules ?? []) {
|
|
13875
|
-
wsRules.push({ id: r.entryId ?? "", name: r.name, severity: r.data?.severity ?? void 0, source: "
|
|
13945
|
+
wsRules.push({ id: r.entryId ?? "", name: r.name, severity: r.data?.severity ?? void 0, source: "rules" });
|
|
13876
13946
|
}
|
|
13877
13947
|
if (wsRules.length > 0) {
|
|
13878
13948
|
const ruleLines2 = wsRules.map((r) => {
|
|
@@ -13887,7 +13957,7 @@ These are principles, standards, and rules your team has accepted onto the Chain
|
|
|
13887
13957
|
);
|
|
13888
13958
|
} else {
|
|
13889
13959
|
sections.push(
|
|
13890
|
-
"## Your Workspace Principles & Rules\nNo active principles, standards, or
|
|
13960
|
+
"## Your Workspace Principles & Rules\nNo active principles, standards, or rules on the Chain yet.\nUse `capture` with collection `principles`, `standards`, or `rules` to add your team's guardrails.\nOnce accepted, they appear here at orient time \u2014 so every agent session starts with your rules visible."
|
|
13891
13961
|
);
|
|
13892
13962
|
}
|
|
13893
13963
|
sections.push(
|
|
@@ -13916,14 +13986,14 @@ Tags for filtering (e.g. \`severity:high\`), relations via \`entryRelations\`, v
|
|
|
13916
13986
|
}
|
|
13917
13987
|
const rulesCount = businessRules ? `${businessRules.length} entries` : "not loaded \u2014 collection may not exist yet";
|
|
13918
13988
|
sections.push(
|
|
13919
|
-
`##
|
|
13920
|
-
Collection: \`
|
|
13921
|
-
Find rules: \`entries action=search\` for text search, \`entries action=list collection=
|
|
13989
|
+
`## Rules
|
|
13990
|
+
Collection: \`rules\` (${rulesCount}).
|
|
13991
|
+
Find rules: \`entries action=search\` for text search, \`entries action=list collection=rules\` to browse.
|
|
13922
13992
|
Check compliance: use the \`review-against-rules\` prompt (pass a domain).
|
|
13923
13993
|
Draft a new rule: use the \`draft-rule-from-context\` prompt.`
|
|
13924
13994
|
);
|
|
13925
13995
|
sections.push(
|
|
13926
|
-
"## 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
|
|
13996
|
+
"## 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."
|
|
13927
13997
|
);
|
|
13928
13998
|
sections.push(
|
|
13929
13999
|
`## Creating Knowledge
|
|
@@ -13955,7 +14025,7 @@ async function buildOrientationResourceText(kernelQuery2, agentSessionId) {
|
|
|
13955
14025
|
const [collectionsResult, standardsResult, rulesResult, principlesResult, orientViewResult] = await Promise.allSettled([
|
|
13956
14026
|
kernelQuery2("chain.listCollections"),
|
|
13957
14027
|
kernelQuery2("chain.listEntries", { collectionSlug: "standards" }),
|
|
13958
|
-
kernelQuery2("chain.listEntries", { collectionSlug: "
|
|
14028
|
+
kernelQuery2("chain.listEntries", { collectionSlug: "rules" }),
|
|
13959
14029
|
kernelQuery2("chain.listEntries", { collectionSlug: "principles" }),
|
|
13960
14030
|
kernelQuery2("chain.getOrientView", {
|
|
13961
14031
|
tier: "summary",
|
|
@@ -14345,8 +14415,8 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
|
|
|
14345
14415
|
// src/prompts/index.ts
|
|
14346
14416
|
import { z as z34 } from "zod/v3";
|
|
14347
14417
|
async function buildReviewAgainstRulesPrompt(domain) {
|
|
14348
|
-
const entries = await kernelQuery("chain.listEntries", { collectionSlug: "
|
|
14349
|
-
const rules = entries.
|
|
14418
|
+
const entries = await kernelQuery("chain.listEntries", { collectionSlug: "rules" });
|
|
14419
|
+
const rules = entries.slice(0, 50);
|
|
14350
14420
|
if (rules.length === 0) {
|
|
14351
14421
|
return {
|
|
14352
14422
|
messages: [
|
|
@@ -14354,7 +14424,7 @@ async function buildReviewAgainstRulesPrompt(domain) {
|
|
|
14354
14424
|
role: "user",
|
|
14355
14425
|
content: {
|
|
14356
14426
|
type: "text",
|
|
14357
|
-
text: `No
|
|
14427
|
+
text: `No rules found. Use \`entries action=list collection=rules\` to see available rules.`
|
|
14358
14428
|
}
|
|
14359
14429
|
}
|
|
14360
14430
|
]
|
|
@@ -14362,12 +14432,10 @@ async function buildReviewAgainstRulesPrompt(domain) {
|
|
|
14362
14432
|
}
|
|
14363
14433
|
const rulesText = rules.map(
|
|
14364
14434
|
(r) => `### ${r.entryId ?? ""}: ${r.name}
|
|
14365
|
-
Status: ${r.status} |
|
|
14366
|
-
|
|
14367
|
-
|
|
14368
|
-
|
|
14369
|
-
` + (r.data?.conflictWith ? `CONFLICT: ${r.data.conflictWith.rule} \u2014 ${r.data.conflictWith.nature}
|
|
14370
|
-
` : "")
|
|
14435
|
+
Status: ${r.status} | Applies: ${r.data?.applies ?? "unspecified"}
|
|
14436
|
+
Body: ${readEntryBody(r.data, "body") ?? ""}
|
|
14437
|
+
Why: ${r.data?.why ?? ""}
|
|
14438
|
+
`
|
|
14371
14439
|
).join("\n---\n\n");
|
|
14372
14440
|
return {
|
|
14373
14441
|
messages: [
|
|
@@ -14375,14 +14443,14 @@ Platforms: ${(r.data?.platforms ?? []).join(", ")}
|
|
|
14375
14443
|
role: "user",
|
|
14376
14444
|
content: {
|
|
14377
14445
|
type: "text",
|
|
14378
|
-
text: `Review the current code or design against the following
|
|
14446
|
+
text: `Review the current code or design against the following rules, focusing on the "${domain}" area.
|
|
14379
14447
|
|
|
14380
14448
|
For each rule, assess:
|
|
14381
14449
|
1. Is the current implementation compliant?
|
|
14382
14450
|
2. Are there potential violations or edge cases?
|
|
14383
14451
|
3. What specific changes would be needed for compliance?
|
|
14384
14452
|
|
|
14385
|
-
|
|
14453
|
+
Rules (up to 50):
|
|
14386
14454
|
|
|
14387
14455
|
${rulesText}
|
|
14388
14456
|
|
|
@@ -14426,7 +14494,7 @@ Format as a table: Name | Status | Canonical Form | Action Needed`
|
|
|
14426
14494
|
function registerPrompts(server) {
|
|
14427
14495
|
server.prompt(
|
|
14428
14496
|
"review-against-rules",
|
|
14429
|
-
"Review code or a design decision against
|
|
14497
|
+
"Review code or a design decision against the rules, focused on a given area. Fetches the rules and asks you to do a structured compliance review.",
|
|
14430
14498
|
{ domain: z34.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
|
|
14431
14499
|
async ({ domain }) => buildReviewAgainstRulesPrompt(domain)
|
|
14432
14500
|
);
|
|
@@ -14440,38 +14508,7 @@ function registerPrompts(server) {
|
|
|
14440
14508
|
"draft-decision-record",
|
|
14441
14509
|
"Draft a structured decision record from a description of what was decided. Includes context from recent decisions and relevant rules.",
|
|
14442
14510
|
{ context: z34.string().describe("Description of the decision (e.g. 'We decided to use MRSL v3.1 as the conformance baseline because...')") },
|
|
14443
|
-
async ({ context }) =>
|
|
14444
|
-
const recentDecisions = await kernelQuery("chain.listEntries", { collectionSlug: "decisions" });
|
|
14445
|
-
const sorted = [...recentDecisions].sort((a, b) => (b.data?.date ?? "") > (a.data?.date ?? "") ? 1 : -1).slice(0, 5);
|
|
14446
|
-
const recentContext = sorted.length > 0 ? sorted.map((d) => `- [${d.status}] ${d.name} (${d.data?.date ?? "no date"})`).join("\n") : "No previous decisions recorded.";
|
|
14447
|
-
return {
|
|
14448
|
-
messages: [
|
|
14449
|
-
{
|
|
14450
|
-
role: "user",
|
|
14451
|
-
content: {
|
|
14452
|
-
type: "text",
|
|
14453
|
-
text: `Draft a structured decision record from the following context:
|
|
14454
|
-
|
|
14455
|
-
"${context}"
|
|
14456
|
-
|
|
14457
|
-
Recent decisions for reference:
|
|
14458
|
-
${recentContext}
|
|
14459
|
-
|
|
14460
|
-
Structure the decision record with:
|
|
14461
|
-
1. **Title**: Concise decision statement
|
|
14462
|
-
2. **Decided by**: Who made or approved this decision
|
|
14463
|
-
3. **Date**: When it was decided
|
|
14464
|
-
4. **Status**: decided / proposed / revisited
|
|
14465
|
-
5. **Rationale**: Why this decision was made, including trade-offs considered
|
|
14466
|
-
6. **Alternatives considered**: What else was on the table
|
|
14467
|
-
7. **Related rules or tensions**: Any business rules or tensions this connects to
|
|
14468
|
-
|
|
14469
|
-
After drafting, I can log it using the capture tool with collection "decisions".`
|
|
14470
|
-
}
|
|
14471
|
-
}
|
|
14472
|
-
]
|
|
14473
|
-
};
|
|
14474
|
-
}
|
|
14511
|
+
async ({ context }) => buildDraftDecisionRecordPrompt(context)
|
|
14475
14512
|
);
|
|
14476
14513
|
server.prompt(
|
|
14477
14514
|
"draft-rule-from-context",
|
|
@@ -14483,35 +14520,62 @@ After drafting, I can log it using the capture tool with collection "decisions".
|
|
|
14483
14520
|
async ({ observation, domain }) => buildDraftRuleFromContextPrompt(observation, domain)
|
|
14484
14521
|
);
|
|
14485
14522
|
}
|
|
14523
|
+
async function buildDraftDecisionRecordPrompt(context) {
|
|
14524
|
+
const recentDecisions = await kernelQuery("chain.listEntries", { collectionSlug: "decisions" });
|
|
14525
|
+
const created = (d) => d.createdAt ?? 0;
|
|
14526
|
+
const sorted = [...recentDecisions].sort((a, b) => created(b) - created(a)).slice(0, 5);
|
|
14527
|
+
const recentContext = sorted.length > 0 ? sorted.map((d) => `- [${d.status}] ${d.name}`).join("\n") : "No previous decisions recorded.";
|
|
14528
|
+
return {
|
|
14529
|
+
messages: [
|
|
14530
|
+
{
|
|
14531
|
+
role: "user",
|
|
14532
|
+
content: {
|
|
14533
|
+
type: "text",
|
|
14534
|
+
text: `Draft a structured decision record from the following context:
|
|
14535
|
+
|
|
14536
|
+
"${context}"
|
|
14537
|
+
|
|
14538
|
+
Recent decisions for reference:
|
|
14539
|
+
${recentContext}
|
|
14540
|
+
|
|
14541
|
+
Structure the decision record with:
|
|
14542
|
+
1. **Title**: Concise decision statement
|
|
14543
|
+
2. **Body**: What was decided, including the alternatives considered and the trade-offs
|
|
14544
|
+
3. **Why**: The reason behind the decision
|
|
14545
|
+
4. **Related rules or tensions**: Any business rules or tensions this connects to
|
|
14546
|
+
|
|
14547
|
+
Who decided it and when are recorded by the Chain itself; do not add them as fields. After drafting, I can log it using the capture tool with collection "decisions".`
|
|
14548
|
+
}
|
|
14549
|
+
}
|
|
14550
|
+
]
|
|
14551
|
+
};
|
|
14552
|
+
}
|
|
14486
14553
|
async function buildDraftRuleFromContextPrompt(observation, domain) {
|
|
14487
|
-
const allRules = await kernelQuery("chain.listEntries", { collectionSlug: "
|
|
14488
|
-
const existingRules = allRules.
|
|
14489
|
-
const existingContext = existingRules.length > 0 ? existingRules.map((r) => `${r.entryId ?? ""}: ${r.name} [${r.status}] \u2014 ${readEntryBody(r.data, "
|
|
14554
|
+
const allRules = await kernelQuery("chain.listEntries", { collectionSlug: "rules" });
|
|
14555
|
+
const existingRules = allRules.slice(0, 25);
|
|
14556
|
+
const existingContext = existingRules.length > 0 ? existingRules.map((r) => `${r.entryId ?? ""}: ${r.name} [${r.status}] \u2014 ${readEntryBody(r.data, "body") ?? ""}`).join("\n") : "No existing rules for this domain.";
|
|
14490
14557
|
return {
|
|
14491
14558
|
messages: [
|
|
14492
14559
|
{
|
|
14493
14560
|
role: "user",
|
|
14494
14561
|
content: {
|
|
14495
14562
|
type: "text",
|
|
14496
|
-
text: `Draft a
|
|
14563
|
+
text: `Draft a rule based on this observation:
|
|
14497
14564
|
|
|
14498
14565
|
"${observation}"
|
|
14499
14566
|
|
|
14500
14567
|
Domain: ${domain}
|
|
14501
14568
|
|
|
14502
|
-
Existing rules
|
|
14569
|
+
Existing rules (up to 25):
|
|
14503
14570
|
${existingContext}
|
|
14504
14571
|
|
|
14505
|
-
Draft the rule with these fields (do not specify entryId \u2014 Convex assigns sequential IDs automatically, e.g.
|
|
14572
|
+
Draft the rule with these fields (do not specify entryId \u2014 Convex assigns sequential IDs automatically, e.g. RULE-<n>):
|
|
14506
14573
|
1. **name**: Concise rule title
|
|
14507
|
-
2. **data.
|
|
14508
|
-
3. **data.
|
|
14509
|
-
4. **data.
|
|
14510
|
-
|
|
14511
|
-
|
|
14512
|
-
7. **data.relatedRules**: Any related existing rules
|
|
14513
|
-
|
|
14514
|
-
Make sure the rule is consistent with existing rules and doesn't contradict them. After drafting, I can create it using the capture tool with collection "business-rules".`
|
|
14574
|
+
2. **data.body**: What the rule states, and whether it is an enforced invariant or a belief you reason from
|
|
14575
|
+
3. **data.why**: Why this rule matters
|
|
14576
|
+
4. **data.applies**: everyone / team / role (optional)
|
|
14577
|
+
|
|
14578
|
+
Make sure the rule is consistent with existing rules and doesn't contradict them. After drafting, I can create it using the capture tool with collection "rules".`
|
|
14515
14579
|
}
|
|
14516
14580
|
}
|
|
14517
14581
|
]
|
|
@@ -14638,4 +14702,4 @@ export {
|
|
|
14638
14702
|
createProductBrainServer,
|
|
14639
14703
|
initFeatureFlags
|
|
14640
14704
|
};
|
|
14641
|
-
//# sourceMappingURL=chunk-
|
|
14705
|
+
//# sourceMappingURL=chunk-BIHHHC2H.js.map
|