From 270e5e2e7fb217bc7b092d78a3198839c81e2740 Mon Sep 17 00:00:00 2001 From: Turbootzz Date: Tue, 19 May 2026 13:49:12 +0200 Subject: [PATCH 1/2] fix(mcp): name v0.2 schema fields in save/push tool descriptions Agents calling save/push from the tool description alone were producing invalid packets and learning the schema by round-trip rejection. The old save wording ("locked decisions", "failed attempts") mapped to a v0.1 flat shape and was silent on the required ltm_version/id/created_at fields and on attempts[].outcome's closed enum. Rewrite both descriptions to name the required top-level fields verbatim (ltm_version: "0.2", id, created_at, goal, next_step), spell out the nested decisions[]/attempts[] object shapes, list the outcome and confidence enums inline, and point to the 'example' tool as the canonical shape reference. Schema unchanged. Assisted-by: Claude:claude-opus-4-7 --- internal/cli/mcp.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/cli/mcp.go b/internal/cli/mcp.go index 90445ce..4bcb25d 100644 --- a/internal/cli/mcp.go +++ b/internal/cli/mcp.go @@ -222,8 +222,8 @@ func toolDefinitions() []toolDef { }, { Name: "push", - Description: "Send a Core Memory Packet to the configured ltm server. The packet is schema-validated and scanned for secrets/absolute paths before upload. " + - "Pass the packet as a JSON object under 'packet'. Use 'ltm example' via the 'example' tool if you need a valid shape reference.", + Description: "Send a Core Memory Packet to the configured ltm server. The packet is schema-validated and scanned for secrets/absolute paths before upload. Pass the packet as a JSON object under 'packet'. " + + "v0.2 required top-level fields: ltm_version: \"0.2\", id (ULID), created_at (RFC3339), goal, next_step. v0.2 nests decisions/attempts as object arrays — call the 'example' tool for the exact shape before building one from scratch.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{ @@ -241,8 +241,9 @@ func toolDefinitions() []toolDef { }, { Name: "save", - Description: "Save the current session as a Core Memory Packet. Build the packet JSON from the active conversation — goal, locked decisions, failed attempts, open questions, next step — and pass it as 'packet'. " + - "Same validation and redaction as 'push'; use this when the intent is 'persist my session' rather than 'ship a pre-built packet'.", + Description: "Save the current session as a Core Memory Packet (v0.2). Required top-level fields: ltm_version: \"0.2\", id (ULID, 10-64 chars), created_at (RFC3339), goal, next_step. " + + "Nested shape: decisions[] each {what, why, locked?}; attempts[] each {tried, outcome: succeeded|failed|partial, learned?, confidence: low|medium|high?}; open_questions[] strings; optional project, success_criteria[], constraints[], methods[], tags[], provenance. " + + "Call the 'example' tool first to see a valid v0.2 packet. Same validation and redaction as 'push'; use 'save' when persisting the active session rather than shipping a pre-built packet.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{ From 680c801e2da2b40baf471f6fb790a90cfef71611 Mon Sep 17 00:00:00 2001 From: Turbootzz Date: Tue, 19 May 2026 14:20:16 +0200 Subject: [PATCH 2/2] fix(mcp): apply review polish to save/push descriptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add `consequences?` to save's decisions[] shape so all v0.2-optional decision fields are visible at a glance (matches schema). - Drop "10-64 chars" qualifier from id — "(ULID)" alone is enough; the bound matters only to non-ULID callers, who can hit the schema. - Reframe push's v0.2 field list as "v0.2 (current; v0.1 still accepted)" so the top-level description stays consistent with the param-level note that both versions validate. Assisted-by: Claude:claude-opus-4-7 --- internal/cli/mcp.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/cli/mcp.go b/internal/cli/mcp.go index 4bcb25d..586a504 100644 --- a/internal/cli/mcp.go +++ b/internal/cli/mcp.go @@ -223,7 +223,7 @@ func toolDefinitions() []toolDef { { Name: "push", Description: "Send a Core Memory Packet to the configured ltm server. The packet is schema-validated and scanned for secrets/absolute paths before upload. Pass the packet as a JSON object under 'packet'. " + - "v0.2 required top-level fields: ltm_version: \"0.2\", id (ULID), created_at (RFC3339), goal, next_step. v0.2 nests decisions/attempts as object arrays — call the 'example' tool for the exact shape before building one from scratch.", + "For v0.2 (current; v0.1 still accepted): required top-level fields are ltm_version: \"0.2\", id (ULID), created_at (RFC3339), goal, next_step. v0.2 nests decisions/attempts as object arrays — call the 'example' tool for the exact shape before building one from scratch.", InputSchema: map[string]any{ "type": "object", "properties": map[string]any{ @@ -241,8 +241,8 @@ func toolDefinitions() []toolDef { }, { Name: "save", - Description: "Save the current session as a Core Memory Packet (v0.2). Required top-level fields: ltm_version: \"0.2\", id (ULID, 10-64 chars), created_at (RFC3339), goal, next_step. " + - "Nested shape: decisions[] each {what, why, locked?}; attempts[] each {tried, outcome: succeeded|failed|partial, learned?, confidence: low|medium|high?}; open_questions[] strings; optional project, success_criteria[], constraints[], methods[], tags[], provenance. " + + Description: "Save the current session as a Core Memory Packet (v0.2). Required top-level fields: ltm_version: \"0.2\", id (ULID), created_at (RFC3339), goal, next_step. " + + "Nested shape: decisions[] each {what, why, consequences?, locked?}; attempts[] each {tried, outcome: succeeded|failed|partial, learned?, confidence: low|medium|high?}; open_questions[] strings; optional project, success_criteria[], constraints[], methods[], tags[], provenance. " + "Call the 'example' tool first to see a valid v0.2 packet. Same validation and redaction as 'push'; use 'save' when persisting the active session rather than shipping a pre-built packet.", InputSchema: map[string]any{ "type": "object",