Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-3918Done

`buildGenerationSystemPrompt` takes a PHASE — the skeleton framing stops reaching a deepen session

The smallest card in the story and the only one that removes a CONTRADICTION rather than a cost.

The defect, measured

buildGenerationSystemPrompt(mode, extraContext, opts) takes a mode (initial / continue / augment) and has no phase parameter at all. runDeepenSession calls it with rulePacks: selector — so the PACKS are phase-scoped and the FRAMING around them is not. Measured on a real deepen system message for a translate card: 5,161 chars before the rule section, carrying three sections that are all skeleton instructions:

  • THE COMET SHAPE — one level per pass, drill the first child
  • THE ONBOARDING WORKFLOW — the 5-step TITLES-FIRST SKELETON, per level
  • THE FIRST LEVEL IS EPICS (the onboarding root rule)

They instruct the model to "Plan EXACTLY ONE LEVEL this pass, then DRILL into the FIRST child" and name propose_node, complete_level and drill_intothree tools DEEPEN_PHASE_TOOLS does not contain. A deepen session is told to do things it is structurally unable to do.

This is not the same defect as the packs' and does not wait on the ACT decision: the evidence is the tool surface itself, and it needs no judgement.

⚠️ AMENDED 2026-08-29 (MOTIR-3918's own run) — the "5,161 chars" figure above is WRONG, and it UNDERSTATES the defect. It was measured by cutting the composed system message at the first occurrence of SHARED PLANNING RULES — which is a CROSS-REFERENCE inside the framing ("…all in the SHARED PLANNING RULES below", RUNBOOK_PROMPT offset 5,217), not the start of the rule section. The command was right and the cut point was not: a denominator swap of exactly the shape core.md gate 2's QUANTITY limb names.

Re-measured from the constants: the framing is 10,211 chars (the full deepen system message 127,705 minus the rule section 117,494), made of RUNBOOK_PROMPT 6,997 + GENERATION_FEWSHOT 2,742 + the mode note and separators ≈472. Of that, the SKELETON-only portion is ≈8,416:

sectionchars
RUNBOOK_PROMPT — THE COMET SHAPE610
RUNBOOK_PROMPT — THE ONBOARDING WORKFLOW (the 5-step TITLES-FIRST SKELETON)2,819
RUNBOOK_PROMPT — THE FIRST LEVEL IS EPICS747
RUNBOOK_PROMPT — THE ONBOARDING GROUNDING (the catalog epics are carved from)1,098
RUNBOOK_PROMPT — the RECONCILE half of YOUR RECONCILE + CAPTURE TOOLS≈400
GENERATION_FEWSHOT"A level is authored skeleton-first (titles + edges, no prose)"2,742

The claim the figure supported is unchanged and is now larger: a deepen session is handed instructions it cannot follow. Planning bug MOTIR-3926.

Acceptance criteria

  • buildGenerationSystemPrompt takes the PHASE as an input rather than inferring it. Where the caller already passes rulePacks, the phase is read from that selector rather than accepted twice — one source, so the framing and the packs cannot disagree about which phase a session is.
  • A DEEPEN system message contains none of the three skeleton sections above, asserted on the assembled string by their own headings, and a SKELETON one still contains all three.
  • A DEEPEN system message names NO tool absent from DEEPEN_PHASE_TOOLS. Asserted by iterating that constant against SKELETON_PHASE_TOOLS and searching the composed message — so a tool added to either surface later is covered without editing this test.
  • The framing a deepen session DOES need is identified and kept, not dropped wholesale: the card enumerates every section of the current framing with a verdict — skeleton, deepen, or both — and the PR carries that table. A section nobody can classify is the ACT decision's business, not this card's, and is named as such.
  • The before/after size of the deepen framing is stated in the PR, and the deepen system message is measured end to end (it is 127,705 chars today for a translate card, of which 117,494 is rules).
  • tests/plannerPromptAssemblyGate.test.ts keeps its existing assertions; the new ones go beside them, because that file is where the split is already asserted on real assembled strings.

Context refs

  • motir-ai src/llm/treeGeneration.tsbuildGenerationSystemPrompt and its opts; runDeepenSession, which calls it; SKELETON_PHASE_TOOLS / DEEPEN_PHASE_TOOLS.
  • motir-ai tests/plannerPromptAssemblyGate.test.ts — the suite that records every session's system message before silencing the deepen ones, which is what makes this assertable at all.
  • motir-ai src/llm/planningRulePacks.tsPlanningRuleSelector, which already carries the phase the framing needs.