twining_what_changed
Track changes in decisions and entries since a specific timestamp to catch up on updates in the Twining MCP Server's coordination system.
Instructions
Report what changed since a given point in time. Returns new decisions, new entries, overridden decisions, and reconsidered decisions. Use this to catch up on changes since you last checked.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| since | Yes | ISO 8601 timestamp (e.g., 2024-01-15T10:00:00Z) | |
| scope | No | Optional scope filter |
Implementation Reference
- src/engine/context-assembler.ts:539-595 (handler)The actual implementation of the twining_what_changed logic inside the ContextAssembler class.
async whatChanged( since: string, scope?: string, ): Promise<WhatChangedResult> { // Get new entries since timestamp const readOpts: { since: string; scope?: string } = { since }; if (scope) readOpts.scope = scope; const { entries } = await this.blackboardStore.read(readOpts); const newEntries = entries.map((e) => ({ id: e.id, entry_type: e.entry_type, summary: e.summary, })); // Get decisions since timestamp const index = await this.decisionStore.getIndex(); let filteredIndex = index.filter((e) => e.timestamp >= since); if (scope) { filteredIndex = filteredIndex.filter( (e) => e.scope.startsWith(scope) || scope.startsWith(e.scope), ); } const newDecisions = filteredIndex .filter((e) => e.status === "active" || e.status === "provisional") .map((e) => ({ id: e.id, summary: e.summary })); // Find overridden decisions since timestamp const overriddenDecisions: WhatChangedResult["overridden_decisions"] = []; const allOverridden = index.filter((e) => e.status === "overridden"); for (const entry of allOverridden) { const decision = await this.decisionStore.get(entry.id); if (decision && decision.timestamp >= since) { if (!scope || decision.scope.startsWith(scope) || scope.startsWith(decision.scope)) { overriddenDecisions.push({ id: decision.id, summary: decision.summary, reason: decision.override_reason ?? "No reason provided", }); } } } // Find reconsidered (provisional) decisions since timestamp const reconsideredDecisions = filteredIndex .filter((e) => e.status === "provisional") .map((e) => ({ id: e.id, summary: e.summary })); return { new_decisions: newDecisions, new_entries: newEntries, overridden_decisions: overriddenDecisions, reconsidered_decisions: reconsideredDecisions, }; } - src/tools/context-tools.ts:86-118 (registration)The tool registration and request handler for twining_what_changed in context-tools.ts.
server.registerTool( "twining_what_changed", { description: "Report what changed since a given point in time. Returns new decisions, new entries, overridden decisions, and reconsidered decisions. Use this to catch up on changes since you last checked.", inputSchema: { since: z .string() .refine((val) => !isNaN(Date.parse(val)), { message: "Must be a valid ISO 8601 timestamp", }) .describe("ISO 8601 timestamp (e.g., 2024-01-15T10:00:00Z)"), scope: z.string().optional().describe("Optional scope filter"), }, }, async (args) => { try { const result = await contextAssembler.whatChanged( args.since, args.scope, ); return toolResult(result); } catch (e) { if (e instanceof TwiningError) { return toolError(e.message, e.code); } return toolError( e instanceof Error ? e.message : "Unknown error", "INTERNAL_ERROR", ); } }, );