majlis 0.4.0 → 0.4.2
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/cli.js +80 -29
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -522,24 +522,35 @@ Before building:
|
|
|
522
522
|
3. Check docs/classification/ for problem taxonomy
|
|
523
523
|
4. Check docs/experiments/ for prior work
|
|
524
524
|
|
|
525
|
-
|
|
525
|
+
Read as much code as you need to understand the problem. Reading is free \u2014 spend
|
|
526
|
+
as many turns as necessary on Read, Grep, and Glob to build full context before
|
|
527
|
+
you touch anything.
|
|
528
|
+
|
|
529
|
+
## The Rule: ONE Change, Then Document
|
|
530
|
+
|
|
531
|
+
You make ONE code change per cycle. Not two, not "one more quick fix." ONE.
|
|
532
|
+
|
|
533
|
+
The sequence:
|
|
534
|
+
1. **Read and understand** \u2014 read synthesis, dead-ends, source code. Take your time.
|
|
535
|
+
2. **Write the experiment doc FIRST** \u2014 before coding, fill in the Approach section
|
|
536
|
+
with what you plan to do and why. This ensures there is always a record.
|
|
537
|
+
3. **Implement ONE focused change** \u2014 a single coherent edit to the codebase.
|
|
538
|
+
4. **Run the benchmark ONCE** \u2014 observe the result.
|
|
539
|
+
5. **Update the experiment doc** \u2014 fill in Results and Metrics with what happened.
|
|
540
|
+
6. **Output the majlis-json block** \u2014 your structured decisions.
|
|
541
|
+
7. **STOP.**
|
|
526
542
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
3. Implement ONE focused change (not a multi-step debug session)
|
|
531
|
-
4. Run the benchmark ONCE to see the result
|
|
532
|
-
5. Update the experiment doc in docs/experiments/ \u2014 fill in Approach, Results, and Metrics sections. This is NOT optional.
|
|
533
|
-
6. Output the structured majlis-json block with your decisions
|
|
534
|
-
7. STOP
|
|
543
|
+
If your change doesn't work, document what happened and STOP. Do NOT try to fix it.
|
|
544
|
+
Do NOT iterate. Do NOT "try one more thing." The adversary, critic, and verifier
|
|
545
|
+
exist to diagnose what went wrong. The cycle comes back to you with their insights.
|
|
535
546
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
the adversary, critic, and verifier will help diagnose what went wrong.
|
|
539
|
-
The cycle will come back to you with their insights.
|
|
547
|
+
If you find yourself wanting to debug your own fix, that's the signal to stop
|
|
548
|
+
and write up what you learned.
|
|
540
549
|
|
|
541
|
-
|
|
542
|
-
|
|
550
|
+
## Off-limits (DO NOT modify)
|
|
551
|
+
- \`fixtures/\` \u2014 test data, ground truth, STL files. Read-only.
|
|
552
|
+
- \`scripts/benchmark.py\` \u2014 the measurement tool. Never change how you're measured.
|
|
553
|
+
- \`.majlis/\` \u2014 framework config. Not your concern.
|
|
543
554
|
|
|
544
555
|
## During building:
|
|
545
556
|
- Tag EVERY decision: proof / test / strong-consensus / consensus / analogy / judgment
|
|
@@ -2293,13 +2304,15 @@ ${contextJson}
|
|
|
2293
2304
|
\`\`\`
|
|
2294
2305
|
|
|
2295
2306
|
${taskPrompt}`;
|
|
2296
|
-
|
|
2307
|
+
const turns = ROLE_MAX_TURNS[role] ?? 15;
|
|
2308
|
+
console.log(`[majlis] Spawning ${role} agent (model: ${agentDef.model}, maxTurns: ${turns})...`);
|
|
2297
2309
|
const { text: markdown, costUsd } = await runQuery({
|
|
2298
2310
|
prompt,
|
|
2299
2311
|
model: agentDef.model,
|
|
2300
2312
|
tools: agentDef.tools,
|
|
2301
2313
|
systemPrompt: agentDef.systemPrompt,
|
|
2302
|
-
cwd: root
|
|
2314
|
+
cwd: root,
|
|
2315
|
+
maxTurns: turns
|
|
2303
2316
|
});
|
|
2304
2317
|
console.log(`[majlis] ${role} agent complete (cost: $${costUsd.toFixed(4)})`);
|
|
2305
2318
|
const artifactPath = writeArtifact(role, context, markdown, root);
|
|
@@ -2320,14 +2333,15 @@ ${contextJson}
|
|
|
2320
2333
|
\`\`\`
|
|
2321
2334
|
|
|
2322
2335
|
${taskPrompt}`;
|
|
2323
|
-
const systemPrompt =
|
|
2336
|
+
const systemPrompt = 'You are a Synthesis Agent. Be concrete: which decisions failed, which assumptions broke, what constraints must the next approach satisfy. CRITICAL: Your LAST line of output MUST be a <!-- majlis-json --> block. The framework parses this programmatically \u2014 if you omit it, the pipeline breaks. Format: <!-- majlis-json {"guidance": "your guidance here"} -->';
|
|
2324
2337
|
console.log(`[majlis] Spawning synthesiser micro-agent...`);
|
|
2325
2338
|
const { text: markdown, costUsd } = await runQuery({
|
|
2326
2339
|
prompt,
|
|
2327
2340
|
model: "opus",
|
|
2328
2341
|
tools: ["Read", "Glob", "Grep"],
|
|
2329
2342
|
systemPrompt,
|
|
2330
|
-
cwd: root
|
|
2343
|
+
cwd: root,
|
|
2344
|
+
maxTurns: 5
|
|
2331
2345
|
});
|
|
2332
2346
|
console.log(`[majlis] Synthesiser complete (cost: $${costUsd.toFixed(4)})`);
|
|
2333
2347
|
const structured = await extractStructuredData("synthesiser", markdown);
|
|
@@ -2347,7 +2361,7 @@ async function runQuery(opts) {
|
|
|
2347
2361
|
cwd: opts.cwd,
|
|
2348
2362
|
permissionMode: "bypassPermissions",
|
|
2349
2363
|
allowDangerouslySkipPermissions: true,
|
|
2350
|
-
maxTurns:
|
|
2364
|
+
maxTurns: opts.maxTurns ?? 15,
|
|
2351
2365
|
persistSession: false,
|
|
2352
2366
|
settingSources: ["project"]
|
|
2353
2367
|
}
|
|
@@ -2447,7 +2461,7 @@ function writeArtifact(role, context, markdown, projectRoot) {
|
|
|
2447
2461
|
fs7.writeFileSync(target, markdown);
|
|
2448
2462
|
return target;
|
|
2449
2463
|
}
|
|
2450
|
-
var fs7, path7, import_claude_agent_sdk2, DIM2, RESET2, CYAN2;
|
|
2464
|
+
var fs7, path7, import_claude_agent_sdk2, ROLE_MAX_TURNS, DIM2, RESET2, CYAN2;
|
|
2451
2465
|
var init_spawn = __esm({
|
|
2452
2466
|
"src/agents/spawn.ts"() {
|
|
2453
2467
|
"use strict";
|
|
@@ -2456,6 +2470,15 @@ var init_spawn = __esm({
|
|
|
2456
2470
|
import_claude_agent_sdk2 = require("@anthropic-ai/claude-agent-sdk");
|
|
2457
2471
|
init_parse();
|
|
2458
2472
|
init_connection();
|
|
2473
|
+
ROLE_MAX_TURNS = {
|
|
2474
|
+
builder: 50,
|
|
2475
|
+
critic: 12,
|
|
2476
|
+
adversary: 12,
|
|
2477
|
+
verifier: 15,
|
|
2478
|
+
compressor: 15,
|
|
2479
|
+
reframer: 12,
|
|
2480
|
+
scout: 12
|
|
2481
|
+
};
|
|
2459
2482
|
DIM2 = "\x1B[2m";
|
|
2460
2483
|
RESET2 = "\x1B[0m";
|
|
2461
2484
|
CYAN2 = "\x1B[36m";
|
|
@@ -3122,6 +3145,8 @@ async function executeStep(step, exp, root) {
|
|
|
3122
3145
|
break;
|
|
3123
3146
|
case "compressed" /* COMPRESSED */:
|
|
3124
3147
|
await cycle("compress", []);
|
|
3148
|
+
updateExperimentStatus(getDb(root), exp.id, "compressed");
|
|
3149
|
+
info(`Experiment ${exp.slug} compressed.`);
|
|
3125
3150
|
break;
|
|
3126
3151
|
case "reframed" /* REFRAMED */:
|
|
3127
3152
|
updateExperimentStatus(getDb(root), exp.id, "reframed");
|
|
@@ -3268,14 +3293,20 @@ ${deadEnds.map((d) => `- ${d.approach}: ${d.why_failed} [constraint: ${d.structu
|
|
|
3268
3293
|
|
|
3269
3294
|
## Your Task
|
|
3270
3295
|
1. Assess: based on the metrics and synthesis, has the goal been met? Be specific.
|
|
3271
|
-
2. If YES \u2014 output
|
|
3296
|
+
2. If YES \u2014 output the JSON block below with goal_met: true.
|
|
3272
3297
|
3. If NO \u2014 propose the SINGLE most promising next experiment hypothesis.
|
|
3273
|
-
- It must NOT repeat a dead-ended approach
|
|
3298
|
+
- It must NOT repeat a dead-ended approach (check the dead-end registry!)
|
|
3274
3299
|
- It should attack the weakest point revealed by synthesis/fragility
|
|
3275
|
-
- It
|
|
3276
|
-
-
|
|
3300
|
+
- It must be specific and actionable \u2014 name the function or mechanism to change
|
|
3301
|
+
- Do NOT reference specific line numbers \u2014 they shift between experiments
|
|
3302
|
+
- The hypothesis should be a single sentence describing what to do, e.g.:
|
|
3303
|
+
"Activate addSeamEdges() in the runEdgeFirst pipeline for full-revolution cylinder faces"
|
|
3304
|
+
|
|
3305
|
+
CRITICAL: Your LAST line of output MUST be EXACTLY this format (on its own line, nothing after it):
|
|
3306
|
+
<!-- majlis-json {"goal_met": false, "hypothesis": "your single-sentence hypothesis here"} -->
|
|
3277
3307
|
|
|
3278
|
-
|
|
3308
|
+
If the goal is met:
|
|
3309
|
+
<!-- majlis-json {"goal_met": true, "hypothesis": null} -->`
|
|
3279
3310
|
}, root);
|
|
3280
3311
|
const structured = result.structured;
|
|
3281
3312
|
if (structured?.goal_met === true) {
|
|
@@ -3284,9 +3315,27 @@ IMPORTANT: You MUST output the <!-- majlis-json --> block. This is how the frame
|
|
|
3284
3315
|
if (structured?.hypothesis) {
|
|
3285
3316
|
return structured.hypothesis;
|
|
3286
3317
|
}
|
|
3287
|
-
const
|
|
3288
|
-
if (
|
|
3289
|
-
|
|
3318
|
+
const jsonMatch = result.output.match(/"hypothesis"\s*:\s*"([^"]+)"/);
|
|
3319
|
+
if (jsonMatch && jsonMatch[1].length > 10) return jsonMatch[1].trim();
|
|
3320
|
+
const blockMatch = result.output.match(/<!--\s*majlis-json\s*(\{[\s\S]*?\})\s*-->/);
|
|
3321
|
+
if (blockMatch) {
|
|
3322
|
+
try {
|
|
3323
|
+
const parsed = JSON.parse(blockMatch[1]);
|
|
3324
|
+
if (parsed.goal_met === true) return null;
|
|
3325
|
+
if (parsed.hypothesis) return parsed.hypothesis;
|
|
3326
|
+
} catch {
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
warn("Planner did not return structured output. Retrying with focused prompt...");
|
|
3330
|
+
const retry = await spawnSynthesiser({
|
|
3331
|
+
taskPrompt: `Based on this analysis, output ONLY a single-line JSON block:
|
|
3332
|
+
|
|
3333
|
+
${result.output.slice(-2e3)}
|
|
3334
|
+
|
|
3335
|
+
<!-- majlis-json {"goal_met": false, "hypothesis": "your hypothesis"} -->`
|
|
3336
|
+
}, root);
|
|
3337
|
+
if (retry.structured?.hypothesis) return retry.structured.hypothesis;
|
|
3338
|
+
warn("Could not extract hypothesis. Using goal as fallback.");
|
|
3290
3339
|
return goal;
|
|
3291
3340
|
}
|
|
3292
3341
|
function createNewExperiment(db, root, hypothesis) {
|
|
@@ -3312,6 +3361,8 @@ function createNewExperiment(db, root, hypothesis) {
|
|
|
3312
3361
|
warn(`Could not create branch ${branch} \u2014 continuing without git branch.`);
|
|
3313
3362
|
}
|
|
3314
3363
|
const exp = createExperiment(db, finalSlug, branch, hypothesis, null, null);
|
|
3364
|
+
updateExperimentStatus(db, exp.id, "reframed");
|
|
3365
|
+
exp.status = "reframed";
|
|
3315
3366
|
const docsDir = path13.join(root, "docs", "experiments");
|
|
3316
3367
|
const templatePath = path13.join(docsDir, "_TEMPLATE.md");
|
|
3317
3368
|
if (fs13.existsSync(templatePath)) {
|