Skip to content

Commit e8d94ad

Browse files
authored
Merge pull request #145 from AxmeAI/fix/finalize-close-required-field-errors-20260603
fix(mcp): make axme_finalize_close required-field errors agent-actionable
2 parents 8078551 + aefae51 commit e8d94ad

1 file changed

Lines changed: 29 additions & 19 deletions

File tree

src/server.ts

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,7 @@ server.tool(
883883
"",
884884
"## Step 2: Prepare Everything for `axme_finalize_close`",
885885
"",
886-
"Collect ALL data into a single `axme_finalize_close` call:",
886+
"Collect ALL data into a single `axme_finalize_close` call.",
887887
"",
888888
"### Extractions (arrays, can be empty):",
889889
"- `memories`: [{action, type, title, description, body, keywords, scope}]",
@@ -893,15 +893,19 @@ server.tool(
893893
"- `safety_rules`: [{action, rule_type, value}]",
894894
" - action: `add` | `remove`",
895895
"",
896-
"### Handoff:",
897-
"- `stopped_at`: what the session stopped at (single line)",
898-
"- `summary`: 2-5 bullet points of what was accomplished",
899-
"- `in_progress`: current state (branches, PRs, uncommitted work)",
896+
"### Handoff — six REQUIRED string fields. ALL must be present and non-empty.",
897+
"If a session legitimately has nothing to report for one of them, pass an explicit placeholder string (examples below) — do NOT omit the field. Omitting yields per-field 'Expected string, received undefined' errors from Zod.",
898+
"",
899+
"- **`stopped_at`** (REQUIRED, single line) — where the session stopped, e.g. `\"finalized PR #207 review\"`",
900+
"- **`summary`** (REQUIRED) — 2-5 bullet points of accomplishments. Empty placeholder: `\"- (no items)\"`",
901+
"- **`in_progress`** (REQUIRED) — branches, PRs, uncommitted work. Empty placeholder: `\"(nothing in progress)\"`",
902+
"- **`next_steps`** (REQUIRED) — concrete next steps. Empty placeholder: `\"(none — work is complete)\"`",
903+
"- **`worklog_entry`** (REQUIRED) — 5-15 line narrative markdown summary of the session",
904+
"- **`startup_text`** (REQUIRED) — ready-to-paste startup text for the next session",
905+
"",
906+
"### Handoff — optional fields (omit if not applicable):",
900907
"- `prs`: [{url, title, status}]",
901-
"- `test_results`, `blockers`, `dirty_branches` (optional)",
902-
"- `next_steps`: concrete next steps",
903-
"- `worklog_entry`: narrative summary (5-15 lines markdown)",
904-
"- `startup_text`: ready-to-paste text for next session",
908+
"- `test_results`, `blockers`, `dirty_branches`",
905909
"",
906910
"## Step 3: Call `axme_finalize_close`",
907911
"",
@@ -946,20 +950,26 @@ server.tool(
946950
value: z.string(),
947951
})).optional().describe("Safety rules to add/remove"),
948952
// --- Handoff ---
949-
stopped_at: z.string().describe("What the session stopped at (single line)"),
950-
summary: z.string().describe("2-5 bullet points of what was accomplished. Use real newlines, NOT literal backslash-n. Each bullet on its own line starting with '- '."),
951-
in_progress: z.string().describe("Current state: branches, PRs, uncommitted work. Use real newlines, NOT literal backslash-n."),
953+
// All six strings below are REQUIRED. If a session legitimately has
954+
// nothing to report for one, pass an explicit placeholder like
955+
// "(nothing in progress)" — do NOT omit the field. Omitting yields a
956+
// Zod "Expected string, received undefined" error per missing field,
957+
// which has historically been mis-read by agents as a per-field server
958+
// bug rather than a missing-argument error.
959+
stopped_at: z.string().min(1, "stopped_at is REQUIRED — pass a single-line description of where the session stopped, e.g. 'finalized PR #207 review'.").describe("[REQUIRED] What the session stopped at (single line)"),
960+
summary: z.string().min(1, "summary is REQUIRED — pass 2-5 bullet points of accomplishments separated by real newlines, or '- (no items)' if truly empty.").describe("[REQUIRED] 2-5 bullet points of what was accomplished. Use real newlines, NOT literal backslash-n. Each bullet on its own line starting with '- '."),
961+
in_progress: z.string().min(1, "in_progress is REQUIRED — pass branches / PRs / uncommitted work, or '(nothing in progress)' if the working tree is clean. Do not omit the field.").describe("[REQUIRED] Current state: branches, PRs, uncommitted work. Use real newlines, NOT literal backslash-n. Pass '(nothing in progress)' if clean."),
952962
prs: z.array(z.object({
953963
url: z.string(),
954964
title: z.string(),
955965
status: z.string(),
956-
})).optional().describe("PRs created/merged in this session"),
957-
test_results: z.string().optional().describe("Test run summary"),
958-
blockers: z.string().optional().describe("Blockers for next session"),
959-
next_steps: z.string().describe("Concrete next steps for next session. Use real newlines, NOT literal backslash-n."),
960-
dirty_branches: z.string().optional().describe("Branch names with state"),
961-
worklog_entry: z.string().describe("Narrative session summary (5-15 lines markdown). Use real newlines, NOT literal backslash-n."),
962-
startup_text: z.string().describe("Ready-to-paste startup text for the next session"),
966+
})).optional().describe("[optional] PRs created/merged in this session"),
967+
test_results: z.string().optional().describe("[optional] Test run summary"),
968+
blockers: z.string().optional().describe("[optional] Blockers for next session"),
969+
next_steps: z.string().min(1, "next_steps is REQUIRED — pass concrete next steps for the next session, or '(none — work is complete)' if there are none. Do not omit the field.").describe("[REQUIRED] Concrete next steps for next session. Use real newlines, NOT literal backslash-n. Pass '(none — work is complete)' if there are none."),
970+
dirty_branches: z.string().optional().describe("[optional] Branch names with state"),
971+
worklog_entry: z.string().min(1, "worklog_entry is REQUIRED — pass a 5-15 line narrative summary of the session in markdown. Do not omit the field.").describe("[REQUIRED] Narrative session summary (5-15 lines markdown). Use real newlines, NOT literal backslash-n."),
972+
startup_text: z.string().min(1, "startup_text is REQUIRED — pass ready-to-paste text the user will hand to the next session. Do not omit the field.").describe("[REQUIRED] Ready-to-paste startup text for the next session"),
963973
},
964974
async (args) => {
965975
const sid = getOwnedSessionIdForLogging();

0 commit comments

Comments
 (0)