@papi-ai/server 0.7.59 → 0.7.60

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.
package/dist/index.js CHANGED
@@ -7527,6 +7527,9 @@ ${footer}`);
7527
7527
  function newTaskJoinKey(task, index) {
7528
7528
  return task.tempId ?? `new-${index + 1}`;
7529
7529
  }
7530
+ function isUnresolvedPlaceholder(taskId, map) {
7531
+ return !map.has(taskId) && /^new-\d+$/i.test(taskId);
7532
+ }
7530
7533
  var NONE_PATTERN2 = /^none\b/i;
7531
7534
  function normalizeText2(text) {
7532
7535
  return text.trim().toLowerCase().replace(/[.,;:!]+$/, "").replace(/\s+/g, " ");
@@ -9010,7 +9013,7 @@ var PLAN_FRAGMENT_DESIGN_BRIEF = `
9010
9013
  **Design brief task detection:** When a task's task type is "design-brief", generate a DESIGN BRIEF handoff. Replace the standard SCOPE (DO THIS) section with these type-specific sections:
9011
9014
  - AUDIENCE: Who this design is for \u2014 persona and context of use (e.g. "non-technical Owner, first dashboard visit")
9012
9015
  - BRAND CONSTRAINTS: Palette, typography, tone \u2014 pull from \`.impeccable.md\` (dev patterns, anti-patterns, component rules) AND \`docs/branding/brand-book.html\` (brand identity, positioning, voice canon) if present. If neither exists, state "No brand doc \u2014 Owner should define constraints before starting."
9013
- - DELIVERABLE FORMAT: What the output looks like \u2014 Claude Design handoff package / annotated mockup / style spec. Be specific so the person doing the work knows what "done" means.
9016
+ - DELIVERABLE FORMAT: What the output looks like \u2014 design handoff package / annotated mockup / style spec. Be specific so the person doing the work knows what "done" means.
9014
9017
  - REVIEW POINTS: What the Owner must approve before the design is considered done (e.g. layout, copy, colour, imagery).
9015
9018
  Keep SCOPE BOUNDARY, ACCEPTANCE CRITERIA, SECURITY CONSIDERATIONS, and PRE-BUILD VERIFICATION sections as normal.
9016
9019
  Add to ACCEPTANCE CRITERIA: "[ ] Deliverable format confirmed with Owner before starting" and "[ ] Design output is self-contained \u2014 includes enough context for a developer to implement without further clarification."`;
@@ -9209,6 +9212,21 @@ function buildPlanFullInstructionsConditional(flags, ctx) {
9209
9212
  if (!flags || !ctx) return PLAN_FULL_INSTRUCTIONS;
9210
9213
  return composeFullModeInstructions(flags, ctx);
9211
9214
  }
9215
+ var CYCLE_DENSITY_TARGETS = {
9216
+ light: { label: "Light", range: "2-3" },
9217
+ standard: { label: "Standard", range: "3-5" },
9218
+ deep: { label: "Deep", range: "6-8" }
9219
+ };
9220
+ function buildCycleDensityDirective(density) {
9221
+ if (!density) return "";
9222
+ const target = CYCLE_DENSITY_TARGETS[density];
9223
+ return [
9224
+ `## CYCLE DENSITY: ${target.label}`,
9225
+ "",
9226
+ `The user set this cycle's density to **${density}** \u2014 aim for roughly **${target.range} tasks** this cycle.`,
9227
+ `This is a TARGET to size toward, not a hard floor or cap: still honour explicit user direction, any pre-assigned tasks, and impact-based sizing. If fewer genuinely-valuable tasks exist, plan fewer \u2014 do NOT pad the cycle to hit the number.`
9228
+ ].join("\n");
9229
+ }
9212
9230
  function buildPlanUserMessage(ctx) {
9213
9231
  const modeLabel = ctx.mode.toUpperCase();
9214
9232
  const parts = [
@@ -9226,6 +9244,10 @@ function buildPlanUserMessage(ctx) {
9226
9244
  ""
9227
9245
  );
9228
9246
  }
9247
+ const densityDirective = buildCycleDensityDirective(ctx.density);
9248
+ if (densityDirective) {
9249
+ parts.push(densityDirective, "");
9250
+ }
9229
9251
  if (ctx.mode === "bootstrap") {
9230
9252
  parts.push(PLAN_BOOTSTRAP_INSTRUCTIONS);
9231
9253
  } else {
@@ -10101,15 +10123,49 @@ phases:
10101
10123
 
10102
10124
  *No decisions locked yet. These are added as planning cycles confirm strategic choices.*`;
10103
10125
  }
10126
+ function buildPreScanInstruction(opts) {
10127
+ const docRouting = opts.hosted ? "paste the relevant content (decision records, roadmap, spec excerpts) directly into `description` \u2014 over a remote connector PAPI cannot read local file paths." : "pass local doc file paths as `sources` (comma-separated), or paste content into `description`.";
10128
+ return [
10129
+ `**\u{1F50E} Before you generate anything \u2014 scan the project and gather real context.**`,
10130
+ `A brief and Active Decisions built from the real code and docs are far sharper than ones guessed from a project name. You (the agent running this) have local access that PAPI does not \u2014 do the gathering, then pass it back.`,
10131
+ ``,
10132
+ `1. **Confirm the environment.** Check that you are running from the root of this project's dev environment \u2014 the folder that holds its source, git history, and docs. If you are not there, or you are connected over a remote connector with no access to the user's files, say so and ask the user where the project lives before continuing.`,
10133
+ `2. **Scan the code.** List the top-level directories and files, read the package/build manifest and the README (first ~3000 chars), and collect recent commit subjects. Pass this back as \`codebase_scan\` on the next \`setup\` call.`,
10134
+ `3. **Scan the docs.** Look through \`docs/\`, design notes, ADRs/decision records, and any roadmap or planning files \u2014 not just code.`,
10135
+ `4. **Check for sibling / separate repos.** Many projects span more than one repo (a separate frontend, backend, infra, or mobile repo, or other packages in a monorepo). Ask the user whether any related repos or directories exist, and scan those too.`,
10136
+ `5. **Ask the user to point you at extra context.** Prompt them: "Is there anything else I should read before setting this up \u2014 a PRD or spec, decision records, a roadmap, or links to related repos or docs?" Fold whatever they share into the scan.`,
10137
+ `6. **Re-run \`setup\` with what you gathered:** pass the code scan as \`codebase_scan\`; for docs, decision records, and roadmap, ${docRouting} Then answer the prompts below.`,
10138
+ ``,
10139
+ `If there is genuinely no code and no docs yet, skip this and generate from what the user tells you \u2014 the zero-context path is fully supported.`
10140
+ ].join("\n");
10141
+ }
10142
+ var PAPI_DOCS_QUICKSTART_URL = "https://getpapi.ai/docs/guide/quick-start";
10143
+ var PAPI_PUBLIC_REPO_URL = "https://github.com/getpapi/papi";
10144
+ function buildNewProjectSetupInstruction(opts) {
10145
+ const visionRouting = opts.hosted ? "paste anything they share (notes, a PRD, links) into `description` \u2014 over a remote connector PAPI cannot read local file paths." : "fold anything they share (notes, a PRD, a sketch, links) into `description`, or pass local doc paths as `sources`.";
10146
+ return [
10147
+ `**\u{1F331} New project \u2014 start from the vision.**`,
10148
+ `There's no existing code to mine, so setup builds from what the user wants to create. Do two things before answering the prompts below.`,
10149
+ ``,
10150
+ `1. **Get oriented on PAPI.** So you can guide the user well \u2014 whatever assistant you are \u2014 skim the quick-start docs at ${PAPI_DOCS_QUICKSTART_URL} and the public repo at ${PAPI_PUBLIC_REPO_URL}. They explain the plan \u2192 build \u2192 review cycle the user will run after setup.`,
10151
+ `2. **Draw out the vision with the user.** Ask what they're building and for whom, the core problem it solves, and what success looks like \u2014 enough to write a real brief, a North Star, and a starter backlog rather than a generic scaffold. If they already have a PRD, sketch, notes, or links, ${visionRouting}`,
10152
+ ``,
10153
+ `Then answer the prompts below to generate the brief, decisions, North Star, and a vision-first starter backlog.`
10154
+ ].join("\n");
10155
+ }
10104
10156
  var AD_SEED_SYSTEM = `You are a technical architect seeding initial Active Decisions for a new software project managed by PAPI.
10105
10157
 
10106
10158
  Active Decisions (ADs) are documented architectural choices with confidence levels. They guide the planner and builder agents \u2014 without ADs, planning output is generic and unhelpful.
10107
10159
 
10108
10160
  IMPORTANT: You are running as a non-interactive API call. Do NOT ask questions. Produce decisions directly.
10109
10161
 
10162
+ ## SOURCE OF TRUTH \u2014 extract real decisions first
10163
+
10164
+ If the context includes decision records, ADRs, a roadmap, a README, or codebase analysis, your PRIMARY job is to EXTRACT the real, already-made decisions from that material \u2014 not to invent generic ones. Read the provided context and capture each load-bearing choice the project has actually made (its stack, data model, architecture, positioning, deployment posture). Only fall back to informed defaults for a project of this type when the context contains no evidenced decisions.
10165
+
10110
10166
  ## OUTPUT FORMAT
10111
10167
 
10112
- Return a JSON array of 3-5 Active Decisions. Each AD must have:
10168
+ Return a JSON array of Active Decisions \u2014 ONE per real decision you find. Each AD must have:
10113
10169
  - "id": "AD-1", "AD-2", etc.
10114
10170
  - "body": Full markdown block including ### heading, confidence tag, and body text
10115
10171
 
@@ -10123,17 +10179,20 @@ The body format for each AD:
10123
10179
 
10124
10180
  ## GUIDELINES
10125
10181
 
10126
- - All seeded ADs should have Confidence: MEDIUM (they are informed defaults, not confirmed choices)
10127
- - Focus on decisions that genuinely differ by project type \u2014 avoid generic truisms
10128
- - Each AD should be actionable and falsifiable (something the team could decide differently)
10182
+ - **Count follows the evidence \u2014 there is NO fixed target.** Seed as many ADs as there are real, distinct decisions in the material. Do NOT pad to a number, and do NOT fabricate decisions to hit a count. When the context has no evidenced decisions, return a small set (2-4) of informed defaults for this project type.
10183
+ - **Confidence reflects evidence:** a decision explicitly documented as settled in the source may be HIGH; an informed default you inferred stays MEDIUM.
10184
+ - Never mint an AD that is not a genuine stance-with-alternatives \u2014 a preference, a fact, or a config value is NOT an AD.
10185
+ - Focus on decisions that genuinely differ by project \u2014 avoid generic truisms.
10186
+ - Each AD should be actionable and falsifiable (something the team could decide differently).
10129
10187
  - Cover different concerns: architecture, data, deployment, testing strategy, API design, etc.
10130
- - Keep each AD body to 4-6 lines \u2014 concise and scannable
10188
+ - Keep each AD body to 4-6 lines \u2014 concise and scannable.
10189
+ - **Do NOT duplicate** any decision already listed as an existing Active Decision in the context \u2014 skip it entirely.
10131
10190
  - **Quality bar:** ADs are for product and architecture choices that constrain future work \u2014 technology selections, data model designs, UX principles, strategic positioning. They are NOT for process preferences, configuration choices, or temporary workarounds.
10132
10191
 
10133
10192
  Return ONLY valid JSON \u2014 no preamble, no code fences, no explanation.`;
10134
10193
  function buildAdSeedPrompt(ctx) {
10135
10194
  const parts = [
10136
- `Generate 3-5 Active Decisions for this project.`,
10195
+ ctx.codebaseContext ? `Extract the real Active Decisions for this project from the context below. Seed one AD per genuine decision \u2014 do not cap the count, and do not fabricate.` : `Seed the informed default Active Decisions for this project (no decision docs were supplied \u2014 infer sensible MEDIUM-confidence defaults for this project type).`,
10137
10196
  "",
10138
10197
  `**Project:** ${ctx.projectName}`,
10139
10198
  `**Type:** ${ctx.projectType}`,
@@ -10146,12 +10205,57 @@ function buildAdSeedPrompt(ctx) {
10146
10205
  if (ctx.constraints) {
10147
10206
  parts.push(`**Constraints:** ${ctx.constraints}`);
10148
10207
  }
10208
+ if (ctx.codebaseContext) {
10209
+ parts.push(
10210
+ "",
10211
+ "## Project context \u2014 extract the real decisions from here",
10212
+ ctx.codebaseContext
10213
+ );
10214
+ }
10215
+ if (ctx.existingDecisions && ctx.existingDecisions.length > 0) {
10216
+ parts.push(
10217
+ "",
10218
+ "## Existing Active Decisions \u2014 do NOT duplicate these",
10219
+ ...ctx.existingDecisions.map((d) => `- ${d}`)
10220
+ );
10221
+ }
10149
10222
  parts.push(
10150
10223
  "",
10151
10224
  'Return a JSON array of AD objects with "id" and "body" fields. No other text.'
10152
10225
  );
10153
10226
  return parts.join("\n");
10154
10227
  }
10228
+ var NORTH_STAR_SYSTEM = `You are helping a builder define the North Star for a software project set up with PAPI.
10229
+
10230
+ A North Star is the ONE outcome that best captures whether the project is succeeding \u2014 a single, measurable, user-centred statement the team can steer by. It is not a feature list and not a vision paragraph.
10231
+
10232
+ IMPORTANT: You are running as a non-interactive API call. Do NOT ask questions in your output.
10233
+
10234
+ ## HOW TO PRODUCE IT
10235
+ - If the provided context (brief, docs, decision records) ALREADY states a North Star, goal metric, or primary success measure, EXTRACT and restate it \u2014 do not invent a competing one.
10236
+ - Otherwise, PROPOSE the most fitting North Star from the project's purpose and users. (The calling agent will confirm it with the user before it is saved.)
10237
+
10238
+ ## OUTPUT FORMAT
10239
+ Return ONLY the North Star statement \u2014 one or two sentences, concrete and measurable where possible. No heading, no preamble, no quotes, no code fences.`;
10240
+ function buildNorthStarPrompt(inputs) {
10241
+ const parts = [
10242
+ `Define the North Star for this project.`,
10243
+ "",
10244
+ `**Project:** ${inputs.projectName}`,
10245
+ `**Description:** ${inputs.description?.trim() || "(not provided \u2014 infer from context below)"}`,
10246
+ `**Target users:** ${inputs.targetUsers?.trim() || "(not provided \u2014 infer from context below)"}`,
10247
+ `**Problems solved:** ${inputs.problems}`
10248
+ ];
10249
+ if (inputs.codebaseContext) {
10250
+ parts.push(
10251
+ "",
10252
+ "## Project context \u2014 extract an existing North Star from here if one is stated",
10253
+ inputs.codebaseContext
10254
+ );
10255
+ }
10256
+ parts.push("", "Return only the North Star statement.");
10257
+ return parts.join("\n");
10258
+ }
10155
10259
  var CONVENTIONS_SYSTEM = `You are a senior software engineer generating CLAUDE.md coding conventions for a new project.
10156
10260
 
10157
10261
  IMPORTANT: You are running as a non-interactive API call. Do NOT ask questions. Produce conventions directly.
@@ -12327,10 +12431,10 @@ ${cleanContent}`;
12327
12431
  }
12328
12432
  for (const handoff of data.cycleHandoffs) {
12329
12433
  const resolvedId = newTaskIdMap.get(handoff.taskId) ?? handoff.taskId;
12330
- if (resolvedId === handoff.taskId && /^new-\d+$/i.test(handoff.taskId)) {
12434
+ if (isUnresolvedPlaceholder(handoff.taskId, newTaskIdMap)) {
12331
12435
  const titleLine = handoff.buildHandoff.match(/^Task:\s*(.+)/m)?.[1] ?? "(unknown)";
12332
- console.error(
12333
- `[plan] UNRESOLVED handoff reference "${handoff.taskId}" (task: ${titleLine.slice(0, 80)}) \u2014 no newTask carries this tempId/index. Handoff NOT written. Ensure each newTasks entry has a tempId matching its cycleHandoffs taskId (task-2242).`
12436
+ warnings.push(
12437
+ `UNRESOLVED handoff "${handoff.taskId}" (task: ${titleLine.slice(0, 80)}) \u2014 no newTask carries this tempId/index; handoff NOT written and the task is missing from the cycle. Ensure each newTasks entry has a tempId matching its cycleHandoffs taskId (task-2242).`
12334
12438
  );
12335
12439
  continue;
12336
12440
  }
@@ -12596,7 +12700,7 @@ async function processLlmOutput(adapter2, config2, rawOutput, mode, cycleNumber,
12596
12700
  skippedCancellations
12597
12701
  };
12598
12702
  }
12599
- async function preparePlan(adapter2, config2, filters, focus, force, handoffsOnly, skipHandoffs, tracker) {
12703
+ async function preparePlan(adapter2, config2, filters, focus, force, handoffsOnly, skipHandoffs, tracker, density) {
12600
12704
  const prepareTimer = startTimer();
12601
12705
  tracker?.mark("validate_and_prepare");
12602
12706
  let t = startTimer();
@@ -12657,6 +12761,7 @@ async function preparePlan(adapter2, config2, filters, focus, force, handoffsOnl
12657
12761
  throw new Error("TEMPLATE_BRIEF");
12658
12762
  }
12659
12763
  if (skipHandoffs) context.skipHandoffs = true;
12764
+ if (density) context.density = density;
12660
12765
  tracker?.mark("codebase_scan");
12661
12766
  t = startTimer();
12662
12767
  try {
@@ -13297,11 +13402,6 @@ var planTool = {
13297
13402
  type: "string",
13298
13403
  description: 'Absolute path to a file containing the plan output (mode "apply" only). Use this when the response is too large to pass as a string parameter (some hosts cap inputs around 50KB). The file must be absolute, exist, and be \u2264500KB. Mutually exclusive with llm_response.'
13299
13404
  },
13300
- plan_mode: {
13301
- type: "string",
13302
- enum: ["bootstrap", "full"],
13303
- description: 'The plan mode returned from prepare phase (mode "apply" only).'
13304
- },
13305
13405
  cycle_number: {
13306
13406
  type: "number",
13307
13407
  description: 'The cycle number returned from prepare phase (mode "apply" only).'
@@ -13330,6 +13430,11 @@ var planTool = {
13330
13430
  type: "string",
13331
13431
  description: 'User direction for this cycle \u2014 what to focus on, which phase/tasks to prioritise, or constraints to respect. Overrides the autonomous priority tier system. Example: "Focus on Schema Model phase 9 tasks this cycle".'
13332
13432
  },
13433
+ density: {
13434
+ type: "string",
13435
+ enum: ["light", "standard", "deep"],
13436
+ description: 'Target cycle density \u2014 how many tasks the planner should aim to include. "light" \u2248 2-3 tasks, "standard" \u2248 3-5 (the default when omitted), "deep" \u2248 6-8. A TARGET, not a floor or cap: the planner still honours user direction, pre-assigned tasks, and impact sizing, and plans fewer if fewer genuinely-valuable tasks exist.'
13437
+ },
13333
13438
  force: {
13334
13439
  type: "boolean",
13335
13440
  description: "Bypass planning guards (unreleased cycle block, strategy review hard-block). Only use when explicitly requested by the user."
@@ -13428,6 +13533,7 @@ async function handlePlan(adapter2, config2, args) {
13428
13533
  const focus = typeof args.focus === "string" ? args.focus : void 0;
13429
13534
  const force = args.force === true;
13430
13535
  const handoffsOnly = args.handoffs_only === true;
13536
+ const density = args.density === "light" || args.density === "standard" || args.density === "deep" ? args.density : void 0;
13431
13537
  const tracker = new ProgressTracker(toolMode === "apply" ? "apply_validate" : "prepare_validate").bindStream(adapter2, { stage: "plan" });
13432
13538
  try {
13433
13539
  if (toolMode === "apply") {
@@ -13439,7 +13545,6 @@ async function handlePlan(adapter2, config2, args) {
13439
13545
  return errorResponse(resolved.error);
13440
13546
  }
13441
13547
  const llmResponse = resolved.llmResponse;
13442
- const planMode = args.plan_mode || "full";
13443
13548
  const rawCycleNumber = args.cycle_number != null ? Number(args.cycle_number) : NaN;
13444
13549
  const strategyReviewWarning = args.strategy_review_warning || "";
13445
13550
  const prep = planPrepareCache.peek(callerKey) ?? loadPrepareSpill(adapter2.getProjectId?.(), callerKey);
@@ -13469,6 +13574,7 @@ async function handlePlan(adapter2, config2, args) {
13469
13574
  );
13470
13575
  }
13471
13576
  const cycleNumber = newCycleNumber - 1;
13577
+ const planMode = determineMode(cycleNumber);
13472
13578
  planPrepareCache.clear(callerKey);
13473
13579
  clearPrepareSpill(adapter2.getProjectId?.(), callerKey);
13474
13580
  let utilisation;
@@ -13500,7 +13606,7 @@ async function handlePlan(adapter2, config2, args) {
13500
13606
  } catch {
13501
13607
  }
13502
13608
  const skipHandoffs = args.skip_handoffs === true;
13503
- const result = await preparePlan(adapter2, config2, filters, focus, force, handoffsOnly, skipHandoffs, tracker);
13609
+ const result = await preparePlan(adapter2, config2, filters, focus, force, handoffsOnly, skipHandoffs, tracker, density);
13504
13610
  const prepareState = {
13505
13611
  contextHashes: result.contextHashes,
13506
13612
  userMessage: result.userMessage,
@@ -13550,7 +13656,6 @@ Follow the system prompt and context below to generate a complete cycle plan.
13550
13656
  When done, call \`plan\` again with:
13551
13657
  - \`mode\`: "apply"
13552
13658
  - \`llm_response\`: your complete output (both parts)
13553
- - \`plan_mode\`: "${result.mode}"
13554
13659
  - \`cycle_number\`: ${result.cycleNumber + 1}
13555
13660
  - \`strategy_review_warning\`: "${result.strategyReviewWarning.replace(/"/g, '\\"')}"
13556
13661
 
@@ -13575,7 +13680,9 @@ ${result.userMessage}
13575
13680
  } catch (err) {
13576
13681
  const message = err instanceof Error ? err.message : String(err);
13577
13682
  if (message === "TEMPLATE_BRIEF") {
13578
- return textResponse("Your Product Brief still contains template text. Run `setup` first to generate a real Product Brief for your project.");
13683
+ return textResponse(
13684
+ "Can't plan a full cycle yet \u2014 your Product Brief is still the placeholder template.\n\nPlan mode is derived automatically from your cycle count: your first-ever cycle runs in bootstrap mode (which tolerates a thin brief), and every cycle after that runs in full mode (which needs a real brief to scope work against). This project is past its first cycle, so full mode expected a real brief but found the template text.\n\nFix: run `setup` to generate a real Product Brief for your project, then run `plan` again."
13685
+ );
13579
13686
  }
13580
13687
  const isKnownFriendly = /^(Cannot run plan|Strategy Review gate|No tasks assigned|llm_response is required|cycle_number|Merge conflicts|applyPlan timed out)/i.test(message);
13581
13688
  if (isKnownFriendly) {
@@ -18008,6 +18115,7 @@ async function prepareSetup(adapter2, config2, input) {
18008
18115
  codebaseContext: codebaseSummary
18009
18116
  })
18010
18117
  };
18118
+ const existingDecisions = adapter2.getActiveDecisions ? (await adapter2.getActiveDecisions({ includeRetired: true }).catch(() => [])).filter((a) => !a.superseded).map((a) => `${a.displayId}: ${a.title}`) : [];
18011
18119
  const adSeedPrompt = input.projectType ? {
18012
18120
  system: AD_SEED_SYSTEM,
18013
18121
  user: buildAdSeedPrompt({
@@ -18018,7 +18126,11 @@ async function prepareSetup(adapter2, config2, input) {
18018
18126
  problems: input.problems,
18019
18127
  teamSize: input.teamSize,
18020
18128
  deploymentTarget: input.deploymentTarget,
18021
- constraints: input.constraints
18129
+ constraints: input.constraints,
18130
+ // task-2811: feed the pre-scanned codebase/decision-doc context so ADs are
18131
+ // extracted from the project's real decisions, not invented generically.
18132
+ codebaseContext: codebaseSummary,
18133
+ existingDecisions: existingDecisions.length > 0 ? existingDecisions : void 0
18022
18134
  })
18023
18135
  } : void 0;
18024
18136
  const conventionsPrompt = input.projectType ? {
@@ -18052,6 +18164,21 @@ async function prepareSetup(adapter2, config2, input) {
18052
18164
  projectType: input.projectType
18053
18165
  })
18054
18166
  } : void 0;
18167
+ const existingNorthStar = adapter2.getCurrentNorthStar ? await adapter2.getCurrentNorthStar().catch(() => null) : null;
18168
+ const northStarAlreadyExists = Boolean(existingNorthStar && existingNorthStar.trim());
18169
+ const northStarPrompt = northStarAlreadyExists ? void 0 : {
18170
+ system: NORTH_STAR_SYSTEM,
18171
+ user: buildNorthStarPrompt({
18172
+ projectName: input.projectName,
18173
+ description: input.description,
18174
+ targetUsers: input.targetUsers,
18175
+ problems: input.problems,
18176
+ codebaseContext: codebaseSummary
18177
+ })
18178
+ };
18179
+ const willGenerateBrief = !effectiveBriefAlreadyExists;
18180
+ const preScanInstruction = willGenerateBrief && isExistingProject && !input.codebaseScan ? buildPreScanInstruction({ hosted: !canScanFilesystem, existingProject: true }) : void 0;
18181
+ const newProjectInstruction = willGenerateBrief && !isExistingProject ? buildNewProjectSetupInstruction({ hosted: !canScanFilesystem }) : void 0;
18055
18182
  return {
18056
18183
  createdProject,
18057
18184
  projectName: input.projectName,
@@ -18059,17 +18186,21 @@ async function prepareSetup(adapter2, config2, input) {
18059
18186
  adSeedPrompt,
18060
18187
  conventionsPrompt,
18061
18188
  initialTasksPrompt,
18189
+ northStarPrompt,
18190
+ northStarAlreadyExists,
18062
18191
  codebaseSummary,
18063
18192
  detectedCodebaseType,
18064
18193
  autoDetected: autoDetected && detectedCodebaseType !== "new_project",
18065
18194
  briefAlreadyExists: effectiveBriefAlreadyExists,
18066
18195
  briefWillRegenerate,
18067
18196
  briefRegenReason,
18197
+ preScanInstruction,
18198
+ newProjectInstruction,
18068
18199
  warnings: warnings.length > 0 ? warnings : void 0,
18069
18200
  filesToWrite: prepareCollector.isEmpty() ? void 0 : prepareCollector
18070
18201
  };
18071
18202
  }
18072
- async function applySetup(adapter2, config2, input, briefText, adSeedText, conventionsText, initialTasksText) {
18203
+ async function applySetup(adapter2, config2, input, briefText, adSeedText, conventionsText, initialTasksText, northStarText) {
18073
18204
  const collector = new FileWriteCollector();
18074
18205
  const createdProject = await scaffoldPapiDir(adapter2, config2, input, collector);
18075
18206
  let effectiveBriefText = briefText;
@@ -18096,6 +18227,21 @@ async function applySetup(adapter2, config2, input, briefText, adSeedText, conve
18096
18227
  }
18097
18228
  }
18098
18229
  const { seededAds, warnings } = await applySetupOutputs(adapter2, config2, input, collector, effectiveBriefText, adSeedText, conventionsText);
18230
+ let northStarSet = false;
18231
+ const northStarStatement = northStarText?.trim();
18232
+ if (northStarStatement && adapter2.upsertNorthStar) {
18233
+ try {
18234
+ const existing = adapter2.getCurrentNorthStar ? await adapter2.getCurrentNorthStar().catch(() => null) : null;
18235
+ if (!(existing && existing.trim()) || input.force) {
18236
+ await adapter2.upsertNorthStar(northStarStatement, 0);
18237
+ northStarSet = true;
18238
+ }
18239
+ } catch (err) {
18240
+ warnings.push(
18241
+ `North Star not saved \u2014 ${err instanceof Error ? err.message : String(err)}. Set one later during your first \`plan\`.`
18242
+ );
18243
+ }
18244
+ }
18099
18245
  let createdTasks = 0;
18100
18246
  let tasksSkipped = 0;
18101
18247
  if (initialTasksText?.trim()) {
@@ -18241,6 +18387,7 @@ async function applySetup(adapter2, config2, input, briefText, adSeedText, conve
18241
18387
  seededAds,
18242
18388
  createdTasks,
18243
18389
  tasksSkipped: tasksSkipped > 0 ? tasksSkipped : void 0,
18390
+ northStarSet: northStarSet || void 0,
18244
18391
  briefRegenerated: briefRegenerated || void 0,
18245
18392
  cursorScaffolded,
18246
18393
  gitignoreNote,
@@ -18299,6 +18446,10 @@ var setupTool = {
18299
18446
  type: "string",
18300
18447
  description: 'Your generated conventions markdown to append to CLAUDE.md (mode "apply" only). Optional.'
18301
18448
  },
18449
+ north_star_response: {
18450
+ type: "string",
18451
+ description: `The project's North Star statement \u2014 one or two sentences (mode "apply" only). Provide the statement you extracted from the docs or agreed with the user in response to the prepare-phase North Star prompt. Optional; omit when the project already has one.`
18452
+ },
18302
18453
  project_name: {
18303
18454
  type: "string",
18304
18455
  description: "Name of the project."
@@ -18408,6 +18559,9 @@ function formatSuccessResponse(result, constraints, writesClaudeMd = true) {
18408
18559
  const adNote = result.seededAds > 0 ? `
18409
18560
 
18410
18561
  ${result.seededAds} Active Decision${result.seededAds > 1 ? "s" : ""} seeded based on project type \u2014 review them with \`strategy_review\` after your first cycle.` : "";
18562
+ const northStarNote = result.northStarSet ? `
18563
+
18564
+ \u2B50 North Star set \u2014 your project starts steered (no "define a North Star" warning on \`orient\`).` : "";
18411
18565
  const taskNote = result.createdTasks > 0 || (result.tasksSkipped ?? 0) > 0 ? (() => {
18412
18566
  const created = result.createdTasks > 0 ? `${result.createdTasks} initial backlog task${result.createdTasks > 1 ? "s" : ""} created` : "";
18413
18567
  const skipped = (result.tasksSkipped ?? 0) > 0 ? `${result.tasksSkipped} duplicate${(result.tasksSkipped ?? 0) > 1 ? "s" : ""} skipped` : "";
@@ -18427,7 +18581,7 @@ ${[created, skipped].filter(Boolean).join(", ")}.${idea}`;
18427
18581
  ${result.warnings.map((w) => `- ${w}`).join("\n")}` : "";
18428
18582
  const filesToWriteSection = result.filesToWrite ? formatFilesToWriteSection(result.filesToWrite) : "";
18429
18583
  return textResponse(
18430
- `${prefix}Product Brief generated and saved.${briefRegenNote}${adNote}${taskNote}${constraintsHint}${editorNote}${gitignoreNote}${warningsNote}
18584
+ `${prefix}Product Brief generated and saved.${briefRegenNote}${adNote}${northStarNote}${taskNote}${constraintsHint}${editorNote}${gitignoreNote}${warningsNote}
18431
18585
 
18432
18586
  **Important:** Setup created/modified files (${harnessFiles}, .claude/settings.json, docs/). Commit these changes before running \`build_execute\` \u2014 it requires a clean working directory.
18433
18587
 
@@ -18460,8 +18614,9 @@ PAPI needs the project name. Description and target users are optional \u2014 th
18460
18614
  const adSeedResponse = args.ad_seed_response;
18461
18615
  const conventionsResponse = args.conventions_response;
18462
18616
  const initialTasksResponse = args.initial_tasks_response;
18617
+ const northStarResponse = args.north_star_response;
18463
18618
  tracker.mark("apply_setup_writeback");
18464
- const result = await applySetup(adapter2, config2, input, briefResponse, adSeedResponse, conventionsResponse, initialTasksResponse);
18619
+ const result = await applySetup(adapter2, config2, input, briefResponse, adSeedResponse, conventionsResponse, initialTasksResponse, northStarResponse);
18465
18620
  tracker.mark("apply_format_response");
18466
18621
  return formatSuccessResponse(result, args.constraints, writesClaudeMd);
18467
18622
  }
@@ -18517,7 +18672,13 @@ PAPI needs the project name. Description and target users are optional \u2014 th
18517
18672
  ""
18518
18673
  );
18519
18674
  }
18520
- if (result.briefPrompt && !result.briefAlreadyExists) {
18675
+ if (result.preScanInstruction) {
18676
+ sections.push(result.preScanInstruction, "");
18677
+ }
18678
+ if (result.newProjectInstruction) {
18679
+ sections.push(result.newProjectInstruction, "");
18680
+ }
18681
+ if (!result.preScanInstruction && !result.newProjectInstruction && result.briefPrompt && !result.briefAlreadyExists) {
18521
18682
  sections.push(
18522
18683
  `**\u{1F4C4} Before you write the brief \u2014 does the user already have a PRD, brief, spec, or design doc?**`,
18523
18684
  `A brief generated from the user's real spec produces a far better first plan than a generic scaffold.`,
@@ -18534,6 +18695,7 @@ PAPI needs the project name. Description and target users are optional \u2014 th
18534
18695
  result.briefPrompt ? `- \`brief_response\`: your Product Brief markdown` : "",
18535
18696
  result.adSeedPrompt ? `- \`ad_seed_response\`: your AD seed JSON array` : "",
18536
18697
  result.conventionsPrompt ? `- \`conventions_response\`: your conventions markdown` : "",
18698
+ result.northStarPrompt ? `- \`north_star_response\`: the North Star statement (confirm it with the user first)` : "",
18537
18699
  result.initialTasksPrompt ? `- \`initial_tasks_response\`: your initial tasks JSON array` : "",
18538
18700
  `- Plus all the original setup fields (project_name, description, target_users${isExisting ? ", existing_project: true" : ""})`,
18539
18701
  "",
@@ -18586,6 +18748,25 @@ ${result.conventionsPrompt.system}
18586
18748
  "",
18587
18749
  `<context>
18588
18750
  ${result.conventionsPrompt.user}
18751
+ </context>`
18752
+ );
18753
+ }
18754
+ if (result.northStarPrompt) {
18755
+ sectionNum++;
18756
+ sections.push(
18757
+ "",
18758
+ `---`,
18759
+ "",
18760
+ `### ${sectionNum}. North Star`,
18761
+ "",
18762
+ `This project has no North Star yet \u2014 define one now so it starts steered (otherwise \`orient\` will warn that none is set). Extract it from the docs if one is already stated there; otherwise propose one and **confirm it with the user** before applying. Return it as \`north_star_response\`.`,
18763
+ "",
18764
+ `<system_prompt>
18765
+ ${result.northStarPrompt.system}
18766
+ </system_prompt>`,
18767
+ "",
18768
+ `<context>
18769
+ ${result.northStarPrompt.user}
18589
18770
  </context>`
18590
18771
  );
18591
18772
  }
package/dist/prompts.js CHANGED
@@ -236,7 +236,7 @@ var PLAN_FRAGMENT_DESIGN_BRIEF = `
236
236
  **Design brief task detection:** When a task's task type is "design-brief", generate a DESIGN BRIEF handoff. Replace the standard SCOPE (DO THIS) section with these type-specific sections:
237
237
  - AUDIENCE: Who this design is for \u2014 persona and context of use (e.g. "non-technical Owner, first dashboard visit")
238
238
  - BRAND CONSTRAINTS: Palette, typography, tone \u2014 pull from \`.impeccable.md\` (dev patterns, anti-patterns, component rules) AND \`docs/branding/brand-book.html\` (brand identity, positioning, voice canon) if present. If neither exists, state "No brand doc \u2014 Owner should define constraints before starting."
239
- - DELIVERABLE FORMAT: What the output looks like \u2014 Claude Design handoff package / annotated mockup / style spec. Be specific so the person doing the work knows what "done" means.
239
+ - DELIVERABLE FORMAT: What the output looks like \u2014 design handoff package / annotated mockup / style spec. Be specific so the person doing the work knows what "done" means.
240
240
  - REVIEW POINTS: What the Owner must approve before the design is considered done (e.g. layout, copy, colour, imagery).
241
241
  Keep SCOPE BOUNDARY, ACCEPTANCE CRITERIA, SECURITY CONSIDERATIONS, and PRE-BUILD VERIFICATION sections as normal.
242
242
  Add to ACCEPTANCE CRITERIA: "[ ] Deliverable format confirmed with Owner before starting" and "[ ] Design output is self-contained \u2014 includes enough context for a developer to implement without further clarification."`;
@@ -435,6 +435,21 @@ function buildPlanFullInstructionsConditional(flags, ctx) {
435
435
  if (!flags || !ctx) return PLAN_FULL_INSTRUCTIONS;
436
436
  return composeFullModeInstructions(flags, ctx);
437
437
  }
438
+ var CYCLE_DENSITY_TARGETS = {
439
+ light: { label: "Light", range: "2-3" },
440
+ standard: { label: "Standard", range: "3-5" },
441
+ deep: { label: "Deep", range: "6-8" }
442
+ };
443
+ function buildCycleDensityDirective(density) {
444
+ if (!density) return "";
445
+ const target = CYCLE_DENSITY_TARGETS[density];
446
+ return [
447
+ `## CYCLE DENSITY: ${target.label}`,
448
+ "",
449
+ `The user set this cycle's density to **${density}** \u2014 aim for roughly **${target.range} tasks** this cycle.`,
450
+ `This is a TARGET to size toward, not a hard floor or cap: still honour explicit user direction, any pre-assigned tasks, and impact-based sizing. If fewer genuinely-valuable tasks exist, plan fewer \u2014 do NOT pad the cycle to hit the number.`
451
+ ].join("\n");
452
+ }
438
453
  function buildPlanUserMessage(ctx) {
439
454
  const modeLabel = ctx.mode.toUpperCase();
440
455
  const parts = [
@@ -452,6 +467,10 @@ function buildPlanUserMessage(ctx) {
452
467
  ""
453
468
  );
454
469
  }
470
+ const densityDirective = buildCycleDensityDirective(ctx.density);
471
+ if (densityDirective) {
472
+ parts.push(densityDirective, "");
473
+ }
455
474
  if (ctx.mode === "bootstrap") {
456
475
  parts.push(PLAN_BOOTSTRAP_INSTRUCTIONS);
457
476
  } else {
@@ -1327,15 +1346,49 @@ phases:
1327
1346
 
1328
1347
  *No decisions locked yet. These are added as planning cycles confirm strategic choices.*`;
1329
1348
  }
1349
+ function buildPreScanInstruction(opts) {
1350
+ const docRouting = opts.hosted ? "paste the relevant content (decision records, roadmap, spec excerpts) directly into `description` \u2014 over a remote connector PAPI cannot read local file paths." : "pass local doc file paths as `sources` (comma-separated), or paste content into `description`.";
1351
+ return [
1352
+ `**\u{1F50E} Before you generate anything \u2014 scan the project and gather real context.**`,
1353
+ `A brief and Active Decisions built from the real code and docs are far sharper than ones guessed from a project name. You (the agent running this) have local access that PAPI does not \u2014 do the gathering, then pass it back.`,
1354
+ ``,
1355
+ `1. **Confirm the environment.** Check that you are running from the root of this project's dev environment \u2014 the folder that holds its source, git history, and docs. If you are not there, or you are connected over a remote connector with no access to the user's files, say so and ask the user where the project lives before continuing.`,
1356
+ `2. **Scan the code.** List the top-level directories and files, read the package/build manifest and the README (first ~3000 chars), and collect recent commit subjects. Pass this back as \`codebase_scan\` on the next \`setup\` call.`,
1357
+ `3. **Scan the docs.** Look through \`docs/\`, design notes, ADRs/decision records, and any roadmap or planning files \u2014 not just code.`,
1358
+ `4. **Check for sibling / separate repos.** Many projects span more than one repo (a separate frontend, backend, infra, or mobile repo, or other packages in a monorepo). Ask the user whether any related repos or directories exist, and scan those too.`,
1359
+ `5. **Ask the user to point you at extra context.** Prompt them: "Is there anything else I should read before setting this up \u2014 a PRD or spec, decision records, a roadmap, or links to related repos or docs?" Fold whatever they share into the scan.`,
1360
+ `6. **Re-run \`setup\` with what you gathered:** pass the code scan as \`codebase_scan\`; for docs, decision records, and roadmap, ${docRouting} Then answer the prompts below.`,
1361
+ ``,
1362
+ `If there is genuinely no code and no docs yet, skip this and generate from what the user tells you \u2014 the zero-context path is fully supported.`
1363
+ ].join("\n");
1364
+ }
1365
+ var PAPI_DOCS_QUICKSTART_URL = "https://getpapi.ai/docs/guide/quick-start";
1366
+ var PAPI_PUBLIC_REPO_URL = "https://github.com/getpapi/papi";
1367
+ function buildNewProjectSetupInstruction(opts) {
1368
+ const visionRouting = opts.hosted ? "paste anything they share (notes, a PRD, links) into `description` \u2014 over a remote connector PAPI cannot read local file paths." : "fold anything they share (notes, a PRD, a sketch, links) into `description`, or pass local doc paths as `sources`.";
1369
+ return [
1370
+ `**\u{1F331} New project \u2014 start from the vision.**`,
1371
+ `There's no existing code to mine, so setup builds from what the user wants to create. Do two things before answering the prompts below.`,
1372
+ ``,
1373
+ `1. **Get oriented on PAPI.** So you can guide the user well \u2014 whatever assistant you are \u2014 skim the quick-start docs at ${PAPI_DOCS_QUICKSTART_URL} and the public repo at ${PAPI_PUBLIC_REPO_URL}. They explain the plan \u2192 build \u2192 review cycle the user will run after setup.`,
1374
+ `2. **Draw out the vision with the user.** Ask what they're building and for whom, the core problem it solves, and what success looks like \u2014 enough to write a real brief, a North Star, and a starter backlog rather than a generic scaffold. If they already have a PRD, sketch, notes, or links, ${visionRouting}`,
1375
+ ``,
1376
+ `Then answer the prompts below to generate the brief, decisions, North Star, and a vision-first starter backlog.`
1377
+ ].join("\n");
1378
+ }
1330
1379
  var AD_SEED_SYSTEM = `You are a technical architect seeding initial Active Decisions for a new software project managed by PAPI.
1331
1380
 
1332
1381
  Active Decisions (ADs) are documented architectural choices with confidence levels. They guide the planner and builder agents \u2014 without ADs, planning output is generic and unhelpful.
1333
1382
 
1334
1383
  IMPORTANT: You are running as a non-interactive API call. Do NOT ask questions. Produce decisions directly.
1335
1384
 
1385
+ ## SOURCE OF TRUTH \u2014 extract real decisions first
1386
+
1387
+ If the context includes decision records, ADRs, a roadmap, a README, or codebase analysis, your PRIMARY job is to EXTRACT the real, already-made decisions from that material \u2014 not to invent generic ones. Read the provided context and capture each load-bearing choice the project has actually made (its stack, data model, architecture, positioning, deployment posture). Only fall back to informed defaults for a project of this type when the context contains no evidenced decisions.
1388
+
1336
1389
  ## OUTPUT FORMAT
1337
1390
 
1338
- Return a JSON array of 3-5 Active Decisions. Each AD must have:
1391
+ Return a JSON array of Active Decisions \u2014 ONE per real decision you find. Each AD must have:
1339
1392
  - "id": "AD-1", "AD-2", etc.
1340
1393
  - "body": Full markdown block including ### heading, confidence tag, and body text
1341
1394
 
@@ -1349,17 +1402,20 @@ The body format for each AD:
1349
1402
 
1350
1403
  ## GUIDELINES
1351
1404
 
1352
- - All seeded ADs should have Confidence: MEDIUM (they are informed defaults, not confirmed choices)
1353
- - Focus on decisions that genuinely differ by project type \u2014 avoid generic truisms
1354
- - Each AD should be actionable and falsifiable (something the team could decide differently)
1405
+ - **Count follows the evidence \u2014 there is NO fixed target.** Seed as many ADs as there are real, distinct decisions in the material. Do NOT pad to a number, and do NOT fabricate decisions to hit a count. When the context has no evidenced decisions, return a small set (2-4) of informed defaults for this project type.
1406
+ - **Confidence reflects evidence:** a decision explicitly documented as settled in the source may be HIGH; an informed default you inferred stays MEDIUM.
1407
+ - Never mint an AD that is not a genuine stance-with-alternatives \u2014 a preference, a fact, or a config value is NOT an AD.
1408
+ - Focus on decisions that genuinely differ by project \u2014 avoid generic truisms.
1409
+ - Each AD should be actionable and falsifiable (something the team could decide differently).
1355
1410
  - Cover different concerns: architecture, data, deployment, testing strategy, API design, etc.
1356
- - Keep each AD body to 4-6 lines \u2014 concise and scannable
1411
+ - Keep each AD body to 4-6 lines \u2014 concise and scannable.
1412
+ - **Do NOT duplicate** any decision already listed as an existing Active Decision in the context \u2014 skip it entirely.
1357
1413
  - **Quality bar:** ADs are for product and architecture choices that constrain future work \u2014 technology selections, data model designs, UX principles, strategic positioning. They are NOT for process preferences, configuration choices, or temporary workarounds.
1358
1414
 
1359
1415
  Return ONLY valid JSON \u2014 no preamble, no code fences, no explanation.`;
1360
1416
  function buildAdSeedPrompt(ctx) {
1361
1417
  const parts = [
1362
- `Generate 3-5 Active Decisions for this project.`,
1418
+ ctx.codebaseContext ? `Extract the real Active Decisions for this project from the context below. Seed one AD per genuine decision \u2014 do not cap the count, and do not fabricate.` : `Seed the informed default Active Decisions for this project (no decision docs were supplied \u2014 infer sensible MEDIUM-confidence defaults for this project type).`,
1363
1419
  "",
1364
1420
  `**Project:** ${ctx.projectName}`,
1365
1421
  `**Type:** ${ctx.projectType}`,
@@ -1372,12 +1428,57 @@ function buildAdSeedPrompt(ctx) {
1372
1428
  if (ctx.constraints) {
1373
1429
  parts.push(`**Constraints:** ${ctx.constraints}`);
1374
1430
  }
1431
+ if (ctx.codebaseContext) {
1432
+ parts.push(
1433
+ "",
1434
+ "## Project context \u2014 extract the real decisions from here",
1435
+ ctx.codebaseContext
1436
+ );
1437
+ }
1438
+ if (ctx.existingDecisions && ctx.existingDecisions.length > 0) {
1439
+ parts.push(
1440
+ "",
1441
+ "## Existing Active Decisions \u2014 do NOT duplicate these",
1442
+ ...ctx.existingDecisions.map((d) => `- ${d}`)
1443
+ );
1444
+ }
1375
1445
  parts.push(
1376
1446
  "",
1377
1447
  'Return a JSON array of AD objects with "id" and "body" fields. No other text.'
1378
1448
  );
1379
1449
  return parts.join("\n");
1380
1450
  }
1451
+ var NORTH_STAR_SYSTEM = `You are helping a builder define the North Star for a software project set up with PAPI.
1452
+
1453
+ A North Star is the ONE outcome that best captures whether the project is succeeding \u2014 a single, measurable, user-centred statement the team can steer by. It is not a feature list and not a vision paragraph.
1454
+
1455
+ IMPORTANT: You are running as a non-interactive API call. Do NOT ask questions in your output.
1456
+
1457
+ ## HOW TO PRODUCE IT
1458
+ - If the provided context (brief, docs, decision records) ALREADY states a North Star, goal metric, or primary success measure, EXTRACT and restate it \u2014 do not invent a competing one.
1459
+ - Otherwise, PROPOSE the most fitting North Star from the project's purpose and users. (The calling agent will confirm it with the user before it is saved.)
1460
+
1461
+ ## OUTPUT FORMAT
1462
+ Return ONLY the North Star statement \u2014 one or two sentences, concrete and measurable where possible. No heading, no preamble, no quotes, no code fences.`;
1463
+ function buildNorthStarPrompt(inputs) {
1464
+ const parts = [
1465
+ `Define the North Star for this project.`,
1466
+ "",
1467
+ `**Project:** ${inputs.projectName}`,
1468
+ `**Description:** ${inputs.description?.trim() || "(not provided \u2014 infer from context below)"}`,
1469
+ `**Target users:** ${inputs.targetUsers?.trim() || "(not provided \u2014 infer from context below)"}`,
1470
+ `**Problems solved:** ${inputs.problems}`
1471
+ ];
1472
+ if (inputs.codebaseContext) {
1473
+ parts.push(
1474
+ "",
1475
+ "## Project context \u2014 extract an existing North Star from here if one is stated",
1476
+ inputs.codebaseContext
1477
+ );
1478
+ }
1479
+ parts.push("", "Return only the North Star statement.");
1480
+ return parts.join("\n");
1481
+ }
1381
1482
  var CONVENTIONS_SYSTEM = `You are a senior software engineer generating CLAUDE.md coding conventions for a new project.
1382
1483
 
1383
1484
  IMPORTANT: You are running as a non-interactive API call. Do NOT ask questions. Produce conventions directly.
@@ -1497,9 +1598,13 @@ export {
1497
1598
  AD_REJECTION_RULES,
1498
1599
  AD_SEED_SYSTEM,
1499
1600
  CONVENTIONS_SYSTEM,
1601
+ CYCLE_DENSITY_TARGETS,
1500
1602
  HANDOFF_REGEN_SYSTEM,
1501
1603
  INITIAL_TASKS_SYSTEM,
1604
+ NORTH_STAR_SYSTEM,
1502
1605
  OUTPUT_QUALITY_RUBRIC,
1606
+ PAPI_DOCS_QUICKSTART_URL,
1607
+ PAPI_PUBLIC_REPO_URL,
1503
1608
  PLAN_BOOTSTRAP_INSTRUCTIONS,
1504
1609
  PLAN_FULL_INSTRUCTIONS,
1505
1610
  PLAN_SYSTEM,
@@ -1509,11 +1614,15 @@ export {
1509
1614
  VISION_TASKS_SYSTEM,
1510
1615
  buildAdSeedPrompt,
1511
1616
  buildConventionsPrompt,
1617
+ buildCycleDensityDirective,
1512
1618
  buildHandoffRegenMessage,
1513
1619
  buildHandoffsOnlyUserMessage,
1514
1620
  buildInitialTasksPrompt,
1621
+ buildNewProjectSetupInstruction,
1622
+ buildNorthStarPrompt,
1515
1623
  buildPlanFullInstructionsConditional,
1516
1624
  buildPlanUserMessage,
1625
+ buildPreScanInstruction,
1517
1626
  buildProductBriefPrompt,
1518
1627
  buildReviewSystemPrompt,
1519
1628
  buildReviewUserMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@papi-ai/server",
3
- "version": "0.7.59",
3
+ "version": "0.7.60",
4
4
  "description": "PAPI MCP server — AI-powered sprint planning, build execution, and strategy review for software projects",
5
5
  "license": "Elastic-2.0",
6
6
  "mcpName": "io.github.getpapi/papi",