diff --git a/.gitignore b/.gitignore
index ad50ed10..e037ce18 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,3 +69,4 @@ sessions/
kanban.db
config/runtime-config/live/
config/runtime-config/private/
+tools/kurultai/buildroom/.generated/
diff --git a/tests/kurultai/test_buildroom_foundation.py b/tests/kurultai/test_buildroom_foundation.py
index 7d02ac74..6a5c8609 100644
--- a/tests/kurultai/test_buildroom_foundation.py
+++ b/tests/kurultai/test_buildroom_foundation.py
@@ -176,6 +176,9 @@ def test_approved_build_plan_creates_kanban_task_packet_with_parent_refs(tmp_pat
assert packet["title"] == "buildroom: Buildroom foundation demo"
assert packet["assignee"] == "chagatai"
assert packet["parents"] == ["t_parent_one", "t_parent_two"]
+ assert packet["workspace_kind"] == "dir"
+ assert Path(packet["workspace_path"]).is_absolute()
+ assert "${" not in packet["workspace_path"]
assert packet["idempotency_key"] == "buildroom:build-buildroom-foundation-demo"
assert packet["metadata"]["build_id"] == "build-buildroom-foundation-demo"
assert "Allowed paths:" in packet["body"]
@@ -267,6 +270,9 @@ def test_independent_qa_task_packet_uses_build_plan_and_receipt_parent(tmp_path:
assert packet["title"] == "buildroom-qa: Buildroom foundation demo"
assert packet["assignee"] == "ogedei"
assert packet["parents"] == ["t_build123"]
+ assert packet["workspace_kind"] == "dir"
+ assert Path(packet["workspace_path"]).is_absolute()
+ assert "${" not in packet["workspace_path"]
assert packet["idempotency_key"] == "buildroom-qa:build-buildroom-foundation-demo"
assert packet["metadata"]["build_id"] == "build-buildroom-foundation-demo"
assert packet["metadata"]["independent_of"] == "chagatai"
@@ -521,3 +527,145 @@ def test_control_room_cron_fail_on_actionable_exit_code(tmp_path):
"--fail-on-actionable",
)
assert result.returncode == 2
+
+
+
+def test_apply_kanban_drafts_dry_run_dedupes(tmp_path: Path) -> None:
+ drafts = tmp_path / "drafts.json"
+ state = tmp_path / "state.json"
+ ledger = tmp_path / "ledger.json"
+ write_json(drafts, {"drafts": [
+ {"title": "Review room", "metadata": {"attention_item_id": "same", "room_id": "demo-room", "severity": "high", "reason": "watch"}},
+ {"title": "Review room duplicate", "metadata": {"attention_item_id": "same", "room_id": "demo-room", "severity": "high", "reason": "watch"}},
+ ]})
+ result = run_script("tools/kurultai/buildroom/scripts/apply_kanban_drafts.py", "--drafts", str(drafts), "--state", str(state), "--ledger", str(ledger))
+ assert result.returncode == 0, result.stdout
+ payload = read_json(ledger)
+ assert payload["mode"] == "dry-run"
+ assert payload["summary"]["drafts"] == 2
+ assert payload["summary"]["unique"] == 1
+ assert payload["summary"]["new"] == 1
+ task = payload["tasks"][0]
+ assert task["workspace_kind"] == "dir"
+ assert Path(task["workspace_path"]).is_absolute()
+ assert "${" not in task["workspace_path"]
+
+
+def test_apply_kanban_drafts_apply_is_idempotent(tmp_path: Path) -> None:
+ import sqlite3
+ db = tmp_path / "kanban.db"
+ con = sqlite3.connect(db)
+ con.execute("CREATE TABLE tasks (id TEXT PRIMARY KEY, title TEXT NOT NULL, body TEXT, assignee TEXT, status TEXT NOT NULL, priority INTEGER DEFAULT 0, created_by TEXT, created_at INTEGER NOT NULL, started_at INTEGER, completed_at INTEGER, workspace_kind TEXT NOT NULL DEFAULT 'scratch', workspace_path TEXT, claim_lock TEXT, claim_expires INTEGER, tenant TEXT, result TEXT, idempotency_key TEXT, spawn_failures INTEGER NOT NULL DEFAULT 0, worker_pid INTEGER, last_spawn_error TEXT, max_runtime_seconds INTEGER, last_heartbeat_at INTEGER, current_run_id INTEGER, workflow_template_id TEXT, current_step_key TEXT, skills TEXT)")
+ con.execute("CREATE TABLE task_events (id INTEGER PRIMARY KEY AUTOINCREMENT, task_id TEXT NOT NULL, run_id INTEGER, kind TEXT NOT NULL, payload TEXT, created_at INTEGER NOT NULL)")
+ con.commit()
+ con.close()
+ drafts = tmp_path / "drafts.json"
+ state = tmp_path / "state.json"
+ ledger = tmp_path / "ledger.json"
+ write_json(drafts, {"drafts": [{"title": "Review room", "metadata": {"attention_item_id": "same", "room_id": "demo-room"}}]})
+ first = run_script("tools/kurultai/buildroom/scripts/apply_kanban_drafts.py", "--drafts", str(drafts), "--state", str(state), "--ledger", str(ledger), "--kanban-db", str(db), "--apply")
+ second = run_script("tools/kurultai/buildroom/scripts/apply_kanban_drafts.py", "--drafts", str(drafts), "--state", str(state), "--ledger", str(ledger), "--kanban-db", str(db), "--apply")
+ assert first.returncode == 0, first.stdout
+ assert second.returncode == 0, second.stdout
+ con = sqlite3.connect(db)
+ assert con.execute("select count(*) from tasks").fetchone()[0] == 1
+ workspace_kind, workspace_path = con.execute("select workspace_kind, workspace_path from tasks").fetchone()
+ assert workspace_kind == "dir"
+ assert Path(workspace_path).is_absolute()
+ assert "${" not in workspace_path
+ assert con.execute("select count(*) from task_events").fetchone()[0] == 1
+ con.close()
+
+
+def test_retention_review_emits_non_destructive_followups(tmp_path: Path) -> None:
+ room = copy_demo_room(tmp_path, "retention-room")
+ retention = room / "retention" / "retention-review.json"
+ data = read_json(retention)
+ data["recommendation"] = "improve"
+ data["status"] = "pending"
+ write_json(retention, data)
+ output = tmp_path / "retention-items.json"
+ result = run_script("tools/kurultai/buildroom/scripts/retention_review.py", "--rooms", str(tmp_path), "--output", str(output))
+ assert result.returncode == 0, result.stdout
+ payload = read_json(output)
+ assert payload["summary"]["items"] == 1
+ assert payload["items"][0]["needs_receipt"] is True
+ assert payload["items"][0]["room_id"] == "retention-room"
+
+
+def test_buildroom_healthcheck_quick_mode_passes() -> None:
+ result = run_script("tools/kurultai/buildroom/scripts/buildroom_healthcheck.py", "--skip-pytest")
+ assert result.returncode == 0, result.stdout
+ assert "buildroom healthcheck: PASS" in result.stdout
+
+
+
+def test_opportunity_radar_generates_ranked_candidates(tmp_path: Path) -> None:
+ brain = tmp_path / "brain"
+ (brain / "docs" / "designs").mkdir(parents=True)
+ (brain / "docs" / "designs" / "radar.md").write_text(
+ "# Opportunity Radar\n\nAuto Think should rank what should we build next.\n",
+ encoding="utf-8",
+ )
+ json_out = tmp_path / "opportunity-radar.json"
+ md_out = tmp_path / "opportunity-radar.md"
+ drafts_out = tmp_path / "drafts.json"
+ result = subprocess.run(
+ [
+ "python3",
+ str(BUILDROOM / "scripts" / "opportunity_radar.py"),
+ "--brain-root",
+ str(brain),
+ "--buildroom-root",
+ str(BUILDROOM),
+ "--json-output",
+ str(json_out),
+ "--markdown-output",
+ str(md_out),
+ "--kanban-drafts-output",
+ str(drafts_out),
+ "--json",
+ ],
+ cwd=ROOT,
+ text=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ check=True,
+ )
+ payload = json.loads(json_out.read_text())
+ assert payload["recommended_next_action"] == "Buildroom Opportunity Radar v0"
+ assert payload["candidates"][0]["scores"]["total"] >= 38
+ assert "Buildroom Opportunity Radar" in md_out.read_text()
+ drafts = json.loads(drafts_out.read_text())
+ assert drafts["draft_count"] >= 1
+ assert "candidate_count" in result.stdout
+
+
+def test_run_buildroom_cycle_completes_with_dry_run_receipt(tmp_path: Path) -> None:
+ receipt = tmp_path / "cycle-receipt.json"
+ result = subprocess.run(
+ [
+ "python3",
+ str(BUILDROOM / "scripts" / "run_buildroom_cycle.py"),
+ "--skip-pytest",
+ "--receipt-output",
+ str(receipt),
+ "--json",
+ ],
+ cwd=ROOT,
+ text=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ check=True,
+ )
+ summary = json.loads(result.stdout)
+ payload = json.loads(receipt.read_text())
+ assert summary["ok"] is True
+ assert payload["mode"] == "dry-run"
+ assert payload["ok"] is True
+ assert payload["step_count"] >= 6
+ assert "proposal_summary" in summary
+ assert "proposal_summary" in payload
+ assert summary["proposal_summary"]["outcome"]["opportunity_radar_candidates"] >= 1
+ assert summary["proposal_summary"]["proposals"][0]["title"] == "Buildroom Opportunity Radar v0"
+ assert summary["proposal_summary"]["proposals"][0]["summary"]
diff --git a/tools/kurultai/buildroom/control-room-attention-items.json b/tools/kurultai/buildroom/control-room-attention-items.json
index 624d1574..cdb106ef 100644
--- a/tools/kurultai/buildroom/control-room-attention-items.json
+++ b/tools/kurultai/buildroom/control-room-attention-items.json
@@ -25,7 +25,7 @@
"summary": "Room is in watch state."
}
],
- "generated_at": "2026-05-11T02:09:12Z",
+ "generated_at": "2026-05-11T02:29:48Z",
"items": [
{
"category": "operator_decision",
diff --git a/tools/kurultai/buildroom/control-room-kanban-drafts.json b/tools/kurultai/buildroom/control-room-kanban-drafts.json
index bc69cd1f..d8c23ec1 100644
--- a/tools/kurultai/buildroom/control-room-kanban-drafts.json
+++ b/tools/kurultai/buildroom/control-room-kanban-drafts.json
@@ -28,6 +28,6 @@
"title": "Buildroom follow-up: 2026-05-10-gkisokay-auto-think-auto-build \u2014 trust"
}
],
- "generated_at": "2026-05-11T02:09:12Z",
+ "generated_at": "2026-05-11T02:29:48Z",
"source": "buildroom-control-room-cron-v0"
}
diff --git a/tools/kurultai/buildroom/control-room-retention-items.json b/tools/kurultai/buildroom/control-room-retention-items.json
new file mode 100644
index 00000000..2a8766c1
--- /dev/null
+++ b/tools/kurultai/buildroom/control-room-retention-items.json
@@ -0,0 +1,31 @@
+{
+ "items": [
+ {
+ "id": "retention:2026-05-10-gkisokay-auto-think-auto-build",
+ "needs_receipt": true,
+ "next_action": "review retention recommendation and write receipt",
+ "receipt_template": "brain/receipts/kurultai/{date}-2026-05-10-gkisokay-auto-think-auto-build-retention-review.md",
+ "recommendation": "keep",
+ "room_id": "2026-05-10-gkisokay-auto-think-auto-build",
+ "severity": "medium",
+ "status": "pending",
+ "trust_state": "watch"
+ },
+ {
+ "id": "retention:demo-room",
+ "needs_receipt": true,
+ "next_action": "review retention recommendation and write receipt",
+ "receipt_template": "brain/receipts/kurultai/{date}-demo-room-retention-review.md",
+ "recommendation": "keep",
+ "room_id": "demo-room",
+ "severity": "low",
+ "status": "pending",
+ "trust_state": "clean"
+ }
+ ],
+ "rooms_root": "rooms",
+ "summary": {
+ "items": 2,
+ "needs_receipt": 2
+ }
+}
diff --git a/tools/kurultai/buildroom/control-room.html b/tools/kurultai/buildroom/control-room.html
index 5cf4b43b..97173a9a 100644
--- a/tools/kurultai/buildroom/control-room.html
+++ b/tools/kurultai/buildroom/control-room.html
@@ -31,7 +31,7 @@
Kurultai / Buildroom
Control Room
-
Generated 2026-05-11T02:09:12Z. Static, public-safe dashboard for buildroom trust and evidence.
+
Generated 2026-05-11T02:29:48Z. Static, public-safe dashboard for buildroom trust and evidence.
@@ -239,7 +239,7 @@ Install a typed buildroom foundation for autonomous improvement work
}
],
"summary": {
- "generated_at": "2026-05-11T02:09:12Z",
+ "generated_at": "2026-05-11T02:29:48Z",
"room_count": 2,
"rooms_needing_decision": 1,
"rooms_with_missing_evidence": 0,
diff --git a/tools/kurultai/buildroom/control-room.json b/tools/kurultai/buildroom/control-room.json
index fae9375e..342dfc29 100644
--- a/tools/kurultai/buildroom/control-room.json
+++ b/tools/kurultai/buildroom/control-room.json
@@ -135,7 +135,7 @@
}
],
"summary": {
- "generated_at": "2026-05-11T02:09:12Z",
+ "generated_at": "2026-05-11T02:29:48Z",
"room_count": 2,
"rooms_needing_decision": 1,
"rooms_with_missing_evidence": 0,
diff --git a/tools/kurultai/buildroom/control-room.md b/tools/kurultai/buildroom/control-room.md
index 17d55d7c..c3ec3ff6 100644
--- a/tools/kurultai/buildroom/control-room.md
+++ b/tools/kurultai/buildroom/control-room.md
@@ -1,6 +1,6 @@
# Kurultai Buildroom Control Room
-Generated: 2026-05-11T02:09:12Z
+Generated: 2026-05-11T02:29:48Z
## Summary
diff --git a/tools/kurultai/buildroom/docs/control-room-operating-loop.md b/tools/kurultai/buildroom/docs/control-room-operating-loop.md
new file mode 100644
index 00000000..faf5a8df
--- /dev/null
+++ b/tools/kurultai/buildroom/docs/control-room-operating-loop.md
@@ -0,0 +1,52 @@
+# Buildroom Control Room Operating Loop
+
+The Control Room loop turns buildroom contracts into recurring caretaker work.
+
+## Commands
+
+Run from the Kurultai repo root:
+
+- `python3 tools/kurultai/buildroom/scripts/control_room_cron.py`
+- `python3 tools/kurultai/buildroom/scripts/apply_kanban_drafts.py`
+- `python3 tools/kurultai/buildroom/scripts/retention_review.py`
+- `python3 tools/kurultai/buildroom/scripts/buildroom_healthcheck.py`
+
+## Loop phases
+
+1. Regenerate the dashboard: `control-room.md/json/html`.
+2. Emit attention items: `control-room-attention-items.json`.
+3. Emit Kanban drafts: `control-room-kanban-drafts.json`.
+4. Dry-run the Kanban bridge and write an apply ledger under `.generated/`.
+5. Emit retention review items: `control-room-retention-items.json`.
+6. Run the healthcheck canary before any PR or scheduled rollout.
+
+## Kanban bridge safety
+
+`apply_kanban_drafts.py` is dry-run by default. It only creates real Hermes Kanban tasks when `--apply` is passed.
+
+Dedupe is based on a stable attention-item key and the Hermes task `idempotency_key`, prefixed with `buildroom-control-room:`. This prevents repeated cron runs from spamming duplicate tasks.
+
+## Retention safety
+
+`retention_review.py` never deletes buildroom artifacts. It only emits follow-up items and receipt templates for keep/improve/park/prune decisions.
+
+## Healthcheck contract
+
+`buildroom_healthcheck.py` verifies:
+
+- demo room validates
+- real gkisokay room validates
+- Control Room generation succeeds
+- Control Room Cron succeeds
+- Kanban bridge dry-run succeeds
+- generated files exist
+- buildroom scripts compile
+- focused buildroom pytest passes unless `--skip-pytest` is used
+
+## Suggested Hermes cron
+
+Conservative schedule: every 60 minutes.
+
+Command shape: run healthcheck in quick mode, run Control Room Cron, dry-run the Kanban bridge, and emit retention review items.
+
+Default behavior remains proposal-only. Add `--apply` to the Kanban bridge only after the dedupe ledger and task bodies are reviewed.
diff --git a/tools/kurultai/buildroom/docs/opportunity-radar.md b/tools/kurultai/buildroom/docs/opportunity-radar.md
new file mode 100644
index 00000000..74b218c9
--- /dev/null
+++ b/tools/kurultai/buildroom/docs/opportunity-radar.md
@@ -0,0 +1,31 @@
+# Buildroom Opportunity Radar
+
+Opportunity Radar is the Auto Think layer for the buildroom system. It ranks evidence-backed build candidates from Brain and buildroom state, emits inspectable JSON/markdown reports, and drafts follow-up work without applying side effects by default.
+
+Run:
+
+```bash
+python3 tools/kurultai/buildroom/scripts/opportunity_radar.py
+```
+
+Outputs:
+
+- `tools/kurultai/buildroom/opportunity-radar.json`
+- `tools/kurultai/buildroom/opportunity-radar.md`
+- `tools/kurultai/buildroom/opportunity-radar-kanban-drafts.json`
+
+Buildroom cycle command:
+
+```bash
+python3 tools/kurultai/buildroom/scripts/run_buildroom_cycle.py
+```
+
+This validates rooms, regenerates Control Room outputs, runs cron extraction, runs Opportunity Radar, performs a Kanban bridge dry-run, runs retention review, runs healthcheck, and writes `buildroom-cycle-receipt.json`.
+
+Real Kanban creation requires:
+
+```bash
+python3 tools/kurultai/buildroom/scripts/run_buildroom_cycle.py --apply-kanban
+```
+
+Safety defaults: local-first, dry-run by default, no external side effects, no hard deletes, inspectable generated artifacts, and explicit apply modes.
diff --git a/tools/kurultai/buildroom/opportunity-radar-kanban-drafts.json b/tools/kurultai/buildroom/opportunity-radar-kanban-drafts.json
new file mode 100644
index 00000000..b0b5f7f9
--- /dev/null
+++ b/tools/kurultai/buildroom/opportunity-radar-kanban-drafts.json
@@ -0,0 +1,46 @@
+{
+ "draft_count": 3,
+ "drafts": [
+ {
+ "body": "Candidate: Buildroom Opportunity Radar v0\nType: system-improvement\nScore: 49.9\nDisposition: buildroom-candidate\nWhy now: Kurultai has a strong Auto Build loop, but candidate selection is still less inspectable than execution.\nExpected leverage: Turns Brain artifacts into recurring ranked build intent and reduces ad hoc operator steering.\nAcceptance criteria:\n- emit JSON and markdown reports\n- score candidates explainably\n- emit dry-run Kanban drafts\n- link recommendations to source refs\n- pass tests and leakage scan",
+ "candidate_id": "e5b14f92b7ca",
+ "labels": [
+ "buildroom",
+ "opportunity-radar",
+ "system-improvement",
+ "buildroom-candidate"
+ ],
+ "priority": "high",
+ "source": "buildroom-opportunity-radar-v0",
+ "title": "Buildroom opportunity: Buildroom Opportunity Radar v0"
+ },
+ {
+ "body": "Candidate: Brain Compiler Coverage Ledger\nType: brain-compiler\nScore: 47.9\nDisposition: buildroom-candidate\nWhy now: The Brain has more durable artifacts; now it needs coverage accounting to prevent passive storage.\nExpected leverage: Enforces the invariant that memory only matters when it changes future behavior or gets a no-op receipt.\nAcceptance criteria:\n- scan queue/generated/reviews/proposals/receipts\n- identify missing dispositions\n- emit coverage report",
+ "candidate_id": "19eca945eb9b",
+ "labels": [
+ "buildroom",
+ "opportunity-radar",
+ "brain-compiler",
+ "buildroom-candidate"
+ ],
+ "priority": "high",
+ "source": "buildroom-opportunity-radar-v0",
+ "title": "Buildroom opportunity: Brain Compiler Coverage Ledger"
+ },
+ {
+ "body": "Candidate: Agent Harness Maturity Scoreboard\nType: evaluation-candidate\nScore: 46.7\nDisposition: buildroom-candidate\nWhy now: The agent-engineering research argues that agent engineering is harness engineering.\nExpected leverage: Makes agent trust and hardening gaps visible before autonomy expands.\nAcceptance criteria:\n- produce explainable maturity scores\n- surface improvement recommendations\n- integrate with Control Room",
+ "candidate_id": "05b418059610",
+ "labels": [
+ "buildroom",
+ "opportunity-radar",
+ "evaluation-candidate",
+ "buildroom-candidate"
+ ],
+ "priority": "high",
+ "source": "buildroom-opportunity-radar-v0",
+ "title": "Buildroom opportunity: Agent Harness Maturity Scoreboard"
+ }
+ ],
+ "generated_at": "2026-05-11T03:21:25Z",
+ "source": "buildroom-opportunity-radar-v0"
+}
diff --git a/tools/kurultai/buildroom/opportunity-radar.json b/tools/kurultai/buildroom/opportunity-radar.json
new file mode 100644
index 00000000..49511447
--- /dev/null
+++ b/tools/kurultai/buildroom/opportunity-radar.json
@@ -0,0 +1,603 @@
+{
+ "candidates": [
+ {
+ "acceptance_criteria": [
+ "emit JSON and markdown reports",
+ "score candidates explainably",
+ "emit dry-run Kanban drafts",
+ "link recommendations to source refs",
+ "pass tests and leakage scan"
+ ],
+ "candidate_type": "system-improvement",
+ "dependencies": [
+ "Brain artifacts",
+ "buildroom Control Room outputs"
+ ],
+ "expected_leverage": "Turns Brain artifacts into recurring ranked build intent and reduces ad hoc operator steering.",
+ "explainability": {
+ "counterarguments": [
+ "Could create noisy recommendations if reports are not capped",
+ "Scoring must not replace verified user value"
+ ],
+ "top_negative_factors": [
+ "requires calibration against outcomes"
+ ],
+ "top_positive_factors": [
+ "compounds future agent behavior",
+ "local-first and reversible",
+ "8 supporting source artifacts"
+ ]
+ },
+ "id": "e5b14f92b7ca",
+ "proposed_artifacts": [],
+ "recommended_disposition": "buildroom-candidate",
+ "risks": [
+ "scope creep",
+ "duplicate work",
+ "weak outcome feedback"
+ ],
+ "scores": {
+ "compounding_value": 5,
+ "dependency_readiness": 5,
+ "future_behavior_improvement": 5,
+ "risk_reversibility": 5,
+ "total": 49.9,
+ "tractability": 4,
+ "urgency_freshness": 4,
+ "user_leverage": 5,
+ "verification_clarity": 4
+ },
+ "source_evidence": [
+ {
+ "hit_count": 4,
+ "kind": "docs/designs",
+ "ref": "brain/docs/designs/2026-05-10-buildroom-opportunity-radar-intelligent-design.md",
+ "title": "Buildroom Opportunity Radar intelligent design and SWOT"
+ },
+ {
+ "hit_count": 2,
+ "kind": "docs/proposals",
+ "ref": "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "title": "Build proposals from compiled Brain research"
+ },
+ {
+ "hit_count": 1,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-05-10-opportunity-radar-and-buildroom-cycle-implementation-plan.md",
+ "title": "Opportunity Radar and buildroom cycle command implementation plan"
+ },
+ {
+ "hit_count": 1,
+ "kind": "generated",
+ "ref": "brain/generated/2026-05-10-gkisokay-auto-think-auto-build-synthesis.md",
+ "title": "Graeme gkisokay Auto Think Auto Build Synthesis"
+ },
+ {
+ "hit_count": 1,
+ "kind": "generated",
+ "ref": "brain/generated/reviews/2026-05-10-gkisokay-auto-think-auto-build-review.md",
+ "title": "Review - Graeme gkisokay Auto Think Auto Build Synthesis"
+ },
+ {
+ "hit_count": 1,
+ "kind": "queue",
+ "ref": "brain/queue/2026-05-10-gkisokay-hermes-auto-think-auto-build.md",
+ "title": "Graeme gkisokay Hermes Auto Think Auto Build Research Packet"
+ },
+ {
+ "hit_count": 1,
+ "kind": "receipts",
+ "ref": "brain/receipts/kurultai/2026-05-10-gkisokay-auto-think-auto-build-research-to-brain.md",
+ "title": "Receipt - gkisokay Auto Think Auto Build Research Compiled Into Brain"
+ },
+ {
+ "hit_count": 1,
+ "kind": "receipts",
+ "ref": "brain/receipts/kurultai/2026-05-10-kurultai-buildroom-contract-slice-implemented.md",
+ "title": "Receipt - Kurultai Buildroom Contract Slice Implemented"
+ }
+ ],
+ "source_refs": [
+ "brain/docs/designs/2026-05-10-buildroom-opportunity-radar-intelligent-design.md",
+ "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "brain/docs/plans/2026-05-10-opportunity-radar-and-buildroom-cycle-implementation-plan.md",
+ "brain/generated/2026-05-10-gkisokay-auto-think-auto-build-synthesis.md",
+ "brain/generated/reviews/2026-05-10-gkisokay-auto-think-auto-build-review.md",
+ "brain/queue/2026-05-10-gkisokay-hermes-auto-think-auto-build.md",
+ "brain/receipts/kurultai/2026-05-10-gkisokay-auto-think-auto-build-research-to-brain.md",
+ "brain/receipts/kurultai/2026-05-10-kurultai-buildroom-contract-slice-implemented.md"
+ ],
+ "summary": "Build a local-first strategy layer that ranks next buildroom candidates from Brain and buildroom evidence.",
+ "title": "Buildroom Opportunity Radar v0",
+ "why_now": "Kurultai has a strong Auto Build loop, but candidate selection is still less inspectable than execution."
+ },
+ {
+ "acceptance_criteria": [
+ "scan queue/generated/reviews/proposals/receipts",
+ "identify missing dispositions",
+ "emit coverage report"
+ ],
+ "candidate_type": "brain-compiler",
+ "dependencies": [
+ "Brain artifacts",
+ "buildroom Control Room outputs"
+ ],
+ "expected_leverage": "Enforces the invariant that memory only matters when it changes future behavior or gets a no-op receipt.",
+ "explainability": {
+ "counterarguments": [
+ "Could create noisy recommendations if reports are not capped",
+ "Scoring must not replace verified user value"
+ ],
+ "top_negative_factors": [
+ "requires calibration against outcomes"
+ ],
+ "top_positive_factors": [
+ "compounds future agent behavior",
+ "local-first and reversible",
+ "8 supporting source artifacts"
+ ]
+ },
+ "id": "19eca945eb9b",
+ "proposed_artifacts": [],
+ "recommended_disposition": "buildroom-candidate",
+ "risks": [
+ "scope creep",
+ "duplicate work",
+ "weak outcome feedback"
+ ],
+ "scores": {
+ "compounding_value": 5,
+ "dependency_readiness": 4,
+ "future_behavior_improvement": 5,
+ "risk_reversibility": 5,
+ "total": 47.9,
+ "tractability": 4,
+ "urgency_freshness": 3,
+ "user_leverage": 4,
+ "verification_clarity": 5
+ },
+ "source_evidence": [
+ {
+ "hit_count": 5,
+ "kind": "docs/proposals",
+ "ref": "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "title": "Build proposals from compiled Brain research"
+ },
+ {
+ "hit_count": 4,
+ "kind": "docs/designs",
+ "ref": "brain/docs/designs/2026-05-10-buildroom-opportunity-radar-intelligent-design.md",
+ "title": "Buildroom Opportunity Radar intelligent design and SWOT"
+ },
+ {
+ "hit_count": 3,
+ "kind": "docs/kurultai",
+ "ref": "brain/docs/kurultai/command-doctrine-v1.md",
+ "title": "Kurultai Command Doctrine v1"
+ },
+ {
+ "hit_count": 3,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-05-10-entangled-agent-capability-compiler-implementation-plan.md",
+ "title": "Entangled Agent Capability Compiler Implementation Plan"
+ },
+ {
+ "hit_count": 3,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-05-10-kurultai-learn-retro-command-doctrine-vertical-slice.md",
+ "title": "Kurultai Learn/Retro Command Doctrine Vertical Slice"
+ },
+ {
+ "hit_count": 2,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-05-10-memory-is-leverage-doctrine-implementation-plan.md",
+ "title": "Memory Is Leverage \u2014 Doctrine Implementation Plan"
+ },
+ {
+ "hit_count": 2,
+ "kind": "generated",
+ "ref": "brain/generated/2026-05-10-gkisokay-auto-think-auto-build-synthesis.md",
+ "title": "Graeme gkisokay Auto Think Auto Build Synthesis"
+ },
+ {
+ "hit_count": 1,
+ "kind": "docs/kurultai",
+ "ref": "brain/docs/kurultai/agent-operable-brain-os.md",
+ "title": "Agent-operable Brain OS"
+ }
+ ],
+ "source_refs": [
+ "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "brain/docs/designs/2026-05-10-buildroom-opportunity-radar-intelligent-design.md",
+ "brain/docs/kurultai/command-doctrine-v1.md",
+ "brain/docs/plans/2026-05-10-entangled-agent-capability-compiler-implementation-plan.md",
+ "brain/docs/plans/2026-05-10-kurultai-learn-retro-command-doctrine-vertical-slice.md",
+ "brain/docs/plans/2026-05-10-memory-is-leverage-doctrine-implementation-plan.md",
+ "brain/generated/2026-05-10-gkisokay-auto-think-auto-build-synthesis.md",
+ "brain/docs/kurultai/agent-operable-brain-os.md"
+ ],
+ "summary": "Report which meaningful sources changed behavior and which still need synthesis, skill, Kanban, receipt, or no-op disposition.",
+ "title": "Brain Compiler Coverage Ledger",
+ "why_now": "The Brain has more durable artifacts; now it needs coverage accounting to prevent passive storage."
+ },
+ {
+ "acceptance_criteria": [
+ "produce explainable maturity scores",
+ "surface improvement recommendations",
+ "integrate with Control Room"
+ ],
+ "candidate_type": "evaluation-candidate",
+ "dependencies": [
+ "Brain artifacts",
+ "buildroom Control Room outputs"
+ ],
+ "expected_leverage": "Makes agent trust and hardening gaps visible before autonomy expands.",
+ "explainability": {
+ "counterarguments": [
+ "Could create noisy recommendations if reports are not capped",
+ "Scoring must not replace verified user value"
+ ],
+ "top_negative_factors": [
+ "requires calibration against outcomes"
+ ],
+ "top_positive_factors": [
+ "compounds future agent behavior",
+ "local-first and reversible",
+ "8 supporting source artifacts"
+ ]
+ },
+ "id": "05b418059610",
+ "proposed_artifacts": [],
+ "recommended_disposition": "buildroom-candidate",
+ "risks": [
+ "scope creep",
+ "duplicate work",
+ "weak outcome feedback"
+ ],
+ "scores": {
+ "compounding_value": 5,
+ "dependency_readiness": 4,
+ "future_behavior_improvement": 5,
+ "risk_reversibility": 5,
+ "total": 46.7,
+ "tractability": 4,
+ "urgency_freshness": 3,
+ "user_leverage": 4,
+ "verification_clarity": 4
+ },
+ "source_evidence": [
+ {
+ "hit_count": 6,
+ "kind": "docs/proposals",
+ "ref": "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "title": "Build proposals from compiled Brain research"
+ },
+ {
+ "hit_count": 5,
+ "kind": "generated",
+ "ref": "brain/generated/2026-05-11-av1dlive-agent-engineering-roadmap-synthesis.md",
+ "title": "Synthesis \u2014 Avid 2026 AI Agent Engineering Roadmap"
+ },
+ {
+ "hit_count": 5,
+ "kind": "generated",
+ "ref": "brain/generated/reviews/2026-05-11-av1dlive-agent-engineering-roadmap-review.md",
+ "title": "Review \u2014 Avid 2026 AI Agent Engineering Roadmap"
+ },
+ {
+ "hit_count": 4,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-04-21-parse-post-training-kickoff-prompt.md",
+ "title": "Kickoff prompt \u2014 Parse post-training deployment + narrative push"
+ },
+ {
+ "hit_count": 4,
+ "kind": "queue",
+ "ref": "brain/queue/2026-05-11-av1dlive-agent-engineering-roadmap.md",
+ "title": "Avid / @Av1dlive \u2014 2026 AI Agent Engineering Roadmap"
+ },
+ {
+ "hit_count": 4,
+ "kind": "receipts",
+ "ref": "brain/receipts/kurultai/2026-05-11-av1dlive-agent-engineering-roadmap-research.md",
+ "title": "Receipt \u2014 Avid 2026 AI Agent Engineering Roadmap Research"
+ },
+ {
+ "hit_count": 3,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-04-21-parse-soft-launch-option-a-kickoff-prompt.md",
+ "title": "Kickoff prompt \u2014 Parse for Agents soft launch (Option A)"
+ },
+ {
+ "hit_count": 3,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-04-22-meta-harness-option-b-design-v2.md",
+ "title": "2026-04-22-meta-harness-option-b-design-v2"
+ }
+ ],
+ "source_refs": [
+ "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "brain/generated/2026-05-11-av1dlive-agent-engineering-roadmap-synthesis.md",
+ "brain/generated/reviews/2026-05-11-av1dlive-agent-engineering-roadmap-review.md",
+ "brain/docs/plans/2026-04-21-parse-post-training-kickoff-prompt.md",
+ "brain/queue/2026-05-11-av1dlive-agent-engineering-roadmap.md",
+ "brain/receipts/kurultai/2026-05-11-av1dlive-agent-engineering-roadmap-research.md",
+ "brain/docs/plans/2026-04-21-parse-soft-launch-option-a-kickoff-prompt.md",
+ "brain/docs/plans/2026-04-22-meta-harness-option-b-design-v2.md"
+ ],
+ "summary": "Score projects, agents, and buildrooms against harness maturity primitives.",
+ "title": "Agent Harness Maturity Scoreboard",
+ "why_now": "The agent-engineering research argues that agent engineering is harness engineering."
+ },
+ {
+ "acceptance_criteria": [
+ "extract claims/evidence",
+ "scan public/private boundary",
+ "draft publish/no-op recommendation"
+ ],
+ "candidate_type": "content-candidate",
+ "dependencies": [
+ "Brain artifacts",
+ "buildroom Control Room outputs"
+ ],
+ "expected_leverage": "Turns proven internal work into public learning when safe.",
+ "explainability": {
+ "counterarguments": [
+ "Could create noisy recommendations if reports are not capped",
+ "Scoring must not replace verified user value"
+ ],
+ "top_negative_factors": [
+ "requires calibration against outcomes"
+ ],
+ "top_positive_factors": [
+ "compounds future agent behavior",
+ "local-first and reversible",
+ "8 supporting source artifacts"
+ ]
+ },
+ "id": "cad7ee042c11",
+ "proposed_artifacts": [],
+ "recommended_disposition": "watch",
+ "risks": [
+ "scope creep",
+ "duplicate work",
+ "weak outcome feedback"
+ ],
+ "scores": {
+ "compounding_value": 4,
+ "dependency_readiness": 3,
+ "future_behavior_improvement": 3,
+ "risk_reversibility": 4,
+ "total": 35.0,
+ "tractability": 3,
+ "urgency_freshness": 2,
+ "user_leverage": 3,
+ "verification_clarity": 3
+ },
+ "source_evidence": [
+ {
+ "hit_count": 5,
+ "kind": "docs/proposals",
+ "ref": "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "title": "Build proposals from compiled Brain research"
+ },
+ {
+ "hit_count": 2,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-04-27-kublai-brain-v4-merged-design.md",
+ "title": "v4 Sketch (final): v3 backend + claude-obsidian-style human surface + graphify as the corpus extractor + Karpathy second-brain patterns + private/public tier carve-out + JARVIS content production + Research Skill Graph"
+ },
+ {
+ "hit_count": 2,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-05-02-llm-survivor-paid-multiplayer-design.md",
+ "title": "LLM Survivor Paid Multiplayer Design"
+ },
+ {
+ "hit_count": 2,
+ "kind": "docs/proposals",
+ "ref": "brain/docs/proposals/2026-05-10-agent-operable-brain-and-bounty-proof-loops.md",
+ "title": "Agent-operable Brain OS and bounty/proof loop proposals"
+ },
+ {
+ "hit_count": 2,
+ "kind": "queue",
+ "ref": "brain/queue/2026-05-10-cyrilxbt-obsidian-business-os.md",
+ "title": "CyrilXBT Obsidian business operating system signal"
+ },
+ {
+ "hit_count": 2,
+ "kind": "queue",
+ "ref": "brain/queue/2026-05-10-gkisokay-hermes-auto-think-auto-build.md",
+ "title": "Graeme gkisokay Hermes Auto Think Auto Build Research Packet"
+ },
+ {
+ "hit_count": 2,
+ "kind": "queue",
+ "ref": "brain/queue/2026-05-11-av1dlive-agent-engineering-roadmap.md",
+ "title": "Avid / @Av1dlive \u2014 2026 AI Agent Engineering Roadmap"
+ },
+ {
+ "hit_count": 2,
+ "kind": "receipts",
+ "ref": "brain/receipts/kurultai/2026-05-11-av1dlive-agent-engineering-roadmap-research.md",
+ "title": "Receipt \u2014 Avid 2026 AI Agent Engineering Roadmap Research"
+ }
+ ],
+ "source_refs": [
+ "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "brain/docs/plans/2026-04-27-kublai-brain-v4-merged-design.md",
+ "brain/docs/plans/2026-05-02-llm-survivor-paid-multiplayer-design.md",
+ "brain/docs/proposals/2026-05-10-agent-operable-brain-and-bounty-proof-loops.md",
+ "brain/queue/2026-05-10-cyrilxbt-obsidian-business-os.md",
+ "brain/queue/2026-05-10-gkisokay-hermes-auto-think-auto-build.md",
+ "brain/queue/2026-05-11-av1dlive-agent-engineering-roadmap.md",
+ "brain/receipts/kurultai/2026-05-11-av1dlive-agent-engineering-roadmap-research.md"
+ ],
+ "summary": "Convert completed buildrooms into evidence-backed content candidates.",
+ "title": "Buildroom-to-Content OS Bridge",
+ "why_now": "Buildrooms are starting to produce reusable doctrine and receipts."
+ },
+ {
+ "acceptance_criteria": [
+ "evaluate five opportunities on paper",
+ "classify proceed/no-op/needs approval",
+ "perform no external actions"
+ ],
+ "candidate_type": "external-opportunity",
+ "dependencies": [
+ "Brain artifacts",
+ "buildroom Control Room outputs"
+ ],
+ "expected_leverage": "Creates a safe path to evaluate economic opportunities without uncontrolled commitments.",
+ "explainability": {
+ "counterarguments": [
+ "Could create noisy recommendations if reports are not capped",
+ "Scoring must not replace verified user value"
+ ],
+ "top_negative_factors": [
+ "external-side-effect-approval-required"
+ ],
+ "top_positive_factors": [
+ "compounds future agent behavior",
+ "local-first and reversible",
+ "8 supporting source artifacts"
+ ]
+ },
+ "id": "ea047f2d69ea",
+ "proposed_artifacts": [],
+ "recommended_disposition": "needs-human-approval",
+ "risks": [
+ "external-side-effect-approval-required"
+ ],
+ "scores": {
+ "compounding_value": 4,
+ "dependency_readiness": 3,
+ "future_behavior_improvement": 3,
+ "risk_reversibility": 2,
+ "total": 32.6,
+ "tractability": 3,
+ "urgency_freshness": 2,
+ "user_leverage": 3,
+ "verification_clarity": 3
+ },
+ "source_evidence": [
+ {
+ "hit_count": 5,
+ "kind": "docs/proposals",
+ "ref": "brain/docs/proposals/2026-05-10-agent-operable-brain-and-bounty-proof-loops.md",
+ "title": "Agent-operable Brain OS and bounty/proof loop proposals"
+ },
+ {
+ "hit_count": 3,
+ "kind": "docs/proposals",
+ "ref": "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "title": "Build proposals from compiled Brain research"
+ },
+ {
+ "hit_count": 2,
+ "kind": "docs/designs",
+ "ref": "brain/docs/designs/2026-05-10-buildroom-opportunity-radar-intelligent-design.md",
+ "title": "Buildroom Opportunity Radar intelligent design and SWOT"
+ },
+ {
+ "hit_count": 2,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-05-02-turo-cybertruck-ops-rebuild-plan.md",
+ "title": "Turo Cybertruck Ops Functional Metrics Plan"
+ },
+ {
+ "hit_count": 2,
+ "kind": "receipts",
+ "ref": "brain/receipts/kurultai/2026-05-10-agent-operable-brain-os-vertical-slice.md",
+ "title": "Agent-operable Brain OS vertical slice receipt"
+ },
+ {
+ "hit_count": 1,
+ "kind": "docs/kurultai",
+ "ref": "brain/docs/kurultai/agent-operable-brain-os.md",
+ "title": "Agent-operable Brain OS"
+ },
+ {
+ "hit_count": 1,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-04-21-parse-soft-launch-option-a-kickoff-prompt.md",
+ "title": "Kickoff prompt \u2014 Parse for Agents soft launch (Option A)"
+ },
+ {
+ "hit_count": 1,
+ "kind": "docs/plans",
+ "ref": "brain/docs/plans/2026-04-21-parse-soft-launch-option-a.md",
+ "title": "Parse for Agents \u2014 Soft-Launch Plan (Option A)"
+ }
+ ],
+ "source_refs": [
+ "brain/docs/proposals/2026-05-10-agent-operable-brain-and-bounty-proof-loops.md",
+ "brain/docs/proposals/2026-05-11-build-proposals-from-compiled-research.md",
+ "brain/docs/designs/2026-05-10-buildroom-opportunity-radar-intelligent-design.md",
+ "brain/docs/plans/2026-05-02-turo-cybertruck-ops-rebuild-plan.md",
+ "brain/receipts/kurultai/2026-05-10-agent-operable-brain-os-vertical-slice.md",
+ "brain/docs/kurultai/agent-operable-brain-os.md",
+ "brain/docs/plans/2026-04-21-parse-soft-launch-option-a-kickoff-prompt.md",
+ "brain/docs/plans/2026-04-21-parse-soft-launch-option-a.md"
+ ],
+ "summary": "Design a paper-only workflow for evaluating external opportunities without external side effects.",
+ "title": "Paper-only Bounty Proof Loop",
+ "why_now": "There is upside, but reputation and payment surfaces require stronger proof gates first."
+ }
+ ],
+ "generated_at": "2026-05-11T03:21:25Z",
+ "input_summary": {
+ "attention_count": 3,
+ "brain_artifact_count": 60,
+ "buildroom_count": 2,
+ "control_room_present": true,
+ "kanban_draft_count": 2
+ },
+ "kanban_drafts": [
+ {
+ "body": "Candidate: Buildroom Opportunity Radar v0\nType: system-improvement\nScore: 49.9\nDisposition: buildroom-candidate\nWhy now: Kurultai has a strong Auto Build loop, but candidate selection is still less inspectable than execution.\nExpected leverage: Turns Brain artifacts into recurring ranked build intent and reduces ad hoc operator steering.\nAcceptance criteria:\n- emit JSON and markdown reports\n- score candidates explainably\n- emit dry-run Kanban drafts\n- link recommendations to source refs\n- pass tests and leakage scan",
+ "candidate_id": "e5b14f92b7ca",
+ "labels": [
+ "buildroom",
+ "opportunity-radar",
+ "system-improvement",
+ "buildroom-candidate"
+ ],
+ "priority": "high",
+ "source": "buildroom-opportunity-radar-v0",
+ "title": "Buildroom opportunity: Buildroom Opportunity Radar v0"
+ },
+ {
+ "body": "Candidate: Brain Compiler Coverage Ledger\nType: brain-compiler\nScore: 47.9\nDisposition: buildroom-candidate\nWhy now: The Brain has more durable artifacts; now it needs coverage accounting to prevent passive storage.\nExpected leverage: Enforces the invariant that memory only matters when it changes future behavior or gets a no-op receipt.\nAcceptance criteria:\n- scan queue/generated/reviews/proposals/receipts\n- identify missing dispositions\n- emit coverage report",
+ "candidate_id": "19eca945eb9b",
+ "labels": [
+ "buildroom",
+ "opportunity-radar",
+ "brain-compiler",
+ "buildroom-candidate"
+ ],
+ "priority": "high",
+ "source": "buildroom-opportunity-radar-v0",
+ "title": "Buildroom opportunity: Brain Compiler Coverage Ledger"
+ },
+ {
+ "body": "Candidate: Agent Harness Maturity Scoreboard\nType: evaluation-candidate\nScore: 46.7\nDisposition: buildroom-candidate\nWhy now: The agent-engineering research argues that agent engineering is harness engineering.\nExpected leverage: Makes agent trust and hardening gaps visible before autonomy expands.\nAcceptance criteria:\n- produce explainable maturity scores\n- surface improvement recommendations\n- integrate with Control Room",
+ "candidate_id": "05b418059610",
+ "labels": [
+ "buildroom",
+ "opportunity-radar",
+ "evaluation-candidate",
+ "buildroom-candidate"
+ ],
+ "priority": "high",
+ "source": "buildroom-opportunity-radar-v0",
+ "title": "Buildroom opportunity: Agent Harness Maturity Scoreboard"
+ }
+ ],
+ "mode": "dry-run",
+ "recommended_next_action": "Buildroom Opportunity Radar v0",
+ "rejected": [],
+ "schema_version": "0.1.0",
+ "warnings": []
+}
diff --git a/tools/kurultai/buildroom/opportunity-radar.md b/tools/kurultai/buildroom/opportunity-radar.md
new file mode 100644
index 00000000..700a4b96
--- /dev/null
+++ b/tools/kurultai/buildroom/opportunity-radar.md
@@ -0,0 +1,92 @@
+# Buildroom Opportunity Radar
+
+Generated: 2026-05-11T03:21:25Z
+
+## Summary
+
+Candidates: 5
+Kanban drafts: 3
+
+## Top candidates
+
+### Buildroom Opportunity Radar v0
+
+- Type: `system-improvement`
+- Score: `49.9`
+- Disposition: `buildroom-candidate`
+- Why now: Kurultai has a strong Auto Build loop, but candidate selection is still less inspectable than execution.
+- Expected leverage: Turns Brain artifacts into recurring ranked build intent and reduces ad hoc operator steering.
+- Sources: 8
+- Acceptance criteria:
+ - emit JSON and markdown reports
+ - score candidates explainably
+ - emit dry-run Kanban drafts
+ - link recommendations to source refs
+ - pass tests and leakage scan
+- Counterarguments:
+ - Could create noisy recommendations if reports are not capped
+ - Scoring must not replace verified user value
+
+### Brain Compiler Coverage Ledger
+
+- Type: `brain-compiler`
+- Score: `47.9`
+- Disposition: `buildroom-candidate`
+- Why now: The Brain has more durable artifacts; now it needs coverage accounting to prevent passive storage.
+- Expected leverage: Enforces the invariant that memory only matters when it changes future behavior or gets a no-op receipt.
+- Sources: 8
+- Acceptance criteria:
+ - scan queue/generated/reviews/proposals/receipts
+ - identify missing dispositions
+ - emit coverage report
+- Counterarguments:
+ - Could create noisy recommendations if reports are not capped
+ - Scoring must not replace verified user value
+
+### Agent Harness Maturity Scoreboard
+
+- Type: `evaluation-candidate`
+- Score: `46.7`
+- Disposition: `buildroom-candidate`
+- Why now: The agent-engineering research argues that agent engineering is harness engineering.
+- Expected leverage: Makes agent trust and hardening gaps visible before autonomy expands.
+- Sources: 8
+- Acceptance criteria:
+ - produce explainable maturity scores
+ - surface improvement recommendations
+ - integrate with Control Room
+- Counterarguments:
+ - Could create noisy recommendations if reports are not capped
+ - Scoring must not replace verified user value
+
+### Buildroom-to-Content OS Bridge
+
+- Type: `content-candidate`
+- Score: `35.0`
+- Disposition: `watch`
+- Why now: Buildrooms are starting to produce reusable doctrine and receipts.
+- Expected leverage: Turns proven internal work into public learning when safe.
+- Sources: 8
+- Acceptance criteria:
+ - extract claims/evidence
+ - scan public/private boundary
+ - draft publish/no-op recommendation
+- Counterarguments:
+ - Could create noisy recommendations if reports are not capped
+ - Scoring must not replace verified user value
+
+### Paper-only Bounty Proof Loop
+
+- Type: `external-opportunity`
+- Score: `32.6`
+- Disposition: `needs-human-approval`
+- Why now: There is upside, but reputation and payment surfaces require stronger proof gates first.
+- Expected leverage: Creates a safe path to evaluate economic opportunities without uncontrolled commitments.
+- Sources: 8
+- Acceptance criteria:
+ - evaluate five opportunities on paper
+ - classify proceed/no-op/needs approval
+ - perform no external actions
+- Counterarguments:
+ - Could create noisy recommendations if reports are not capped
+ - Scoring must not replace verified user value
diff --git a/tools/kurultai/buildroom/schemas/opportunity-radar.schema.json b/tools/kurultai/buildroom/schemas/opportunity-radar.schema.json
new file mode 100644
index 00000000..b7e10b11
--- /dev/null
+++ b/tools/kurultai/buildroom/schemas/opportunity-radar.schema.json
@@ -0,0 +1 @@
+{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"Buildroom Opportunity Radar","type":"object","required":["schema_version","generated_at","mode","input_summary","candidates","recommended_next_action"],"properties":{"schema_version":{"type":"string"},"generated_at":{"type":"string"},"mode":{"type":"string"},"input_summary":{"type":"object"},"recommended_next_action":{"type":["string","null"]},"warnings":{"type":"array","items":{"type":"string"}},"candidates":{"type":"array","items":{"type":"object","required":["id","title","candidate_type","source_refs","summary","recommended_disposition","scores"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"candidate_type":{"type":"string"},"source_refs":{"type":"array","items":{"type":"string"}},"summary":{"type":"string"},"recommended_disposition":{"type":"string"},"scores":{"type":"object","required":["total"]}}}}}}
diff --git a/tools/kurultai/buildroom/scripts/apply_kanban_drafts.py b/tools/kurultai/buildroom/scripts/apply_kanban_drafts.py
new file mode 100644
index 00000000..fee4e7ed
--- /dev/null
+++ b/tools/kurultai/buildroom/scripts/apply_kanban_drafts.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+
+import argparse
+import hashlib
+import json
+import sqlite3
+import sys
+import time
+from pathlib import Path
+from typing import Any
+
+from common import default_workspace_path
+
+ROOT = Path(__file__).resolve().parents[1]
+DEFAULT_DRAFTS = ROOT / "control-room-kanban-drafts.json"
+DEFAULT_STATE = ROOT / ".generated" / "kanban-draft-state.json"
+DEFAULT_LEDGER = ROOT / ".generated" / "kanban-apply-ledger.json"
+
+
+def load_json(path: Path) -> Any:
+ return json.loads(path.read_text())
+
+
+def write_json(path: Path, payload: Any) -> None:
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n")
+
+
+def drafts_from_payload(payload: Any) -> list[dict[str, Any]]:
+ if isinstance(payload, dict):
+ value = payload.get("drafts") or payload.get("tasks") or []
+ if isinstance(value, list):
+ return [item for item in value if isinstance(item, dict)]
+ if isinstance(payload, list):
+ return [item for item in payload if isinstance(item, dict)]
+ return []
+
+
+def stable_key(draft: dict[str, Any]) -> str:
+ metadata = draft.get("metadata") if isinstance(draft.get("metadata"), dict) else {}
+ for field in ("attention_item_id", "attention_id", "item_id", "idempotency_key"):
+ value = metadata.get(field) or draft.get(field)
+ if isinstance(value, str) and value.strip():
+ return value.strip()
+ room = str(metadata.get("room_id") or draft.get("room_id") or "unknown-room")
+ reason = str(metadata.get("reason") or draft.get("reason") or draft.get("title") or draft.get("source") or "unknown-reason")
+ return hashlib.sha256(f"{room}\n{reason}".encode()).hexdigest()[:24]
+
+
+def normalize_draft(draft: dict[str, Any]) -> dict[str, Any]:
+ key = stable_key(draft)
+ title = str(draft.get("title") or f"buildroom attention: {key}").strip()
+ body = str(draft.get("body") or draft.get("description") or "").strip()
+ metadata = draft.get("metadata") if isinstance(draft.get("metadata"), dict) else {}
+ severity = str(metadata.get("severity") or draft.get("severity") or "medium")
+ room_id = str(metadata.get("room_id") or draft.get("room_id") or "")
+ reason = str(metadata.get("reason") or draft.get("reason") or draft.get("source") or "")
+ acceptance = draft.get("acceptance_criteria") or metadata.get("acceptance_criteria") or []
+ if not isinstance(acceptance, list):
+ acceptance = [str(acceptance)]
+ verification = draft.get("verification_commands") or metadata.get("verification_commands") or []
+ if not isinstance(verification, list):
+ verification = [str(verification)]
+ lines = [body] if body else []
+ lines.extend([
+ "",
+ f"Source: buildroom Control Room attention item `{key}`",
+ f"Room: `{room_id or 'unknown'}`",
+ f"Severity: `{severity}`",
+ f"Reason: {reason or 'see generated attention item payload'}`" if reason else "Reason: see generated attention item payload",
+ "",
+ "Acceptance criteria:",
+ ])
+ lines.extend(f"- {item}" for item in acceptance or ["attention item is resolved or explicitly receipted as no-op"])
+ lines.append("")
+ lines.append("Verification commands:")
+ lines.extend(f"- {item}" for item in verification or ["python3 tools/kurultai/buildroom/scripts/buildroom_healthcheck.py"])
+ return {
+ "dedupe_key": key,
+ "title": title,
+ "body": "\n".join(lines).strip() + "\n",
+ "assignee": str(draft.get("assignee") or metadata.get("assignee") or "kublai"),
+ "priority": coerce_priority(draft.get("priority") or metadata.get("priority"), severity),
+ "workspace_kind": str(draft.get("workspace_kind") or "dir"),
+ "workspace_path": str(draft.get("workspace_path") or default_workspace_path()),
+ "idempotency_key": f"buildroom-control-room:{key}",
+ "metadata": {**metadata, "dedupe_key": key, "room_id": room_id, "severity": severity, "reason": reason},
+ }
+
+
+def priority_for_severity(severity: str) -> int:
+ return {"critical": 90, "high": 70, "medium": 50, "low": 30}.get(severity.lower(), 50)
+
+
+
+def coerce_priority(value: Any, severity: str) -> int:
+ if isinstance(value, int):
+ return value
+ if isinstance(value, str) and value.strip().isdigit():
+ return int(value.strip())
+ if isinstance(value, str) and value.strip().lower() in {"critical", "high", "medium", "normal", "low"}:
+ mapped = value.strip().lower().replace("normal", "medium")
+ return priority_for_severity(mapped)
+ return priority_for_severity(severity)
+
+def load_state(path: Path) -> dict[str, Any]:
+ if not path.exists():
+ return {"applied": {}}
+ data = load_json(path)
+ return data if isinstance(data, dict) else {"applied": {}}
+
+
+def existing_task_by_idempotency(con: sqlite3.Connection, key: str) -> str | None:
+ row = con.execute("select id from tasks where idempotency_key = ? limit 1", (key,)).fetchone()
+ return str(row[0]) if row else None
+
+
+def insert_task(con: sqlite3.Connection, task: dict[str, Any], created_by: str) -> str:
+ existing = existing_task_by_idempotency(con, task["idempotency_key"])
+ if existing:
+ return existing
+ task_id = "t_" + hashlib.sha256(task["idempotency_key"].encode()).hexdigest()[:8]
+ now = int(time.time())
+ con.execute(
+ """
+ insert into tasks (
+ id, title, body, assignee, status, priority, created_by, created_at,
+ workspace_kind, workspace_path, idempotency_key, skills
+ ) values (?, ?, ?, ?, 'todo', ?, ?, ?, ?, ?, ?, ?)
+ """,
+ (
+ task_id,
+ task["title"],
+ task["body"],
+ task["assignee"],
+ task["priority"],
+ created_by,
+ now,
+ task["workspace_kind"],
+ task["workspace_path"],
+ task["idempotency_key"],
+ json.dumps(["kanban-worker", "kurultai-operations"]),
+ ),
+ )
+ con.execute(
+ "insert into task_events (task_id, kind, payload, created_at) values (?, 'created', ?, ?)",
+ (task_id, json.dumps({"source": "buildroom-control-room", "metadata": task["metadata"]}, sort_keys=True), now),
+ )
+ return task_id
+
+
+def build_plan(drafts_path: Path, state_path: Path) -> dict[str, Any]:
+ payload = load_json(drafts_path)
+ state = load_state(state_path)
+ applied = state.get("applied") if isinstance(state.get("applied"), dict) else {}
+ normalized = [normalize_draft(item) for item in drafts_from_payload(payload)]
+ unique: dict[str, dict[str, Any]] = {}
+ for task in normalized:
+ unique.setdefault(task["dedupe_key"], task)
+ tasks = []
+ for task in unique.values():
+ prior = applied.get(task["dedupe_key"])
+ tasks.append({**task, "already_applied": bool(prior), "existing_task_id": prior.get("task_id") if isinstance(prior, dict) else None})
+ return {"source": str(drafts_path), "state": str(state_path), "tasks": tasks, "summary": {"drafts": len(normalized), "unique": len(unique), "new": sum(1 for task in tasks if not task["already_applied"])}}
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(description="Apply buildroom Control Room Kanban drafts with idempotent dry-run default.")
+ parser.add_argument("--drafts", type=Path, default=DEFAULT_DRAFTS)
+ parser.add_argument("--state", type=Path, default=DEFAULT_STATE)
+ parser.add_argument("--ledger", type=Path, default=DEFAULT_LEDGER)
+ parser.add_argument("--kanban-db", type=Path, default=Path.home() / ".hermes" / "kanban.db")
+ parser.add_argument("--apply", action="store_true", help="Create real Hermes Kanban tasks. Default is dry-run only.")
+ parser.add_argument("--created-by", default="kublai-control-room")
+ parser.add_argument("--output", type=Path)
+ args = parser.parse_args()
+
+ plan = build_plan(args.drafts, args.state)
+ if args.apply:
+ state = load_state(args.state)
+ state.setdefault("applied", {})
+ con = sqlite3.connect(args.kanban_db)
+ try:
+ with con:
+ for task in plan["tasks"]:
+ task_id = insert_task(con, task, args.created_by)
+ task["created_task_id"] = task_id
+ task["already_applied"] = bool(task.get("existing_task_id")) or task_id == task.get("existing_task_id")
+ state["applied"][task["dedupe_key"]] = {"task_id": task_id, "idempotency_key": task["idempotency_key"], "applied_at": int(time.time())}
+ finally:
+ con.close()
+ write_json(args.state, state)
+ write_json(args.ledger, {"mode": "apply", **plan})
+ else:
+ write_json(args.ledger, {"mode": "dry-run", **plan})
+ if args.output:
+ write_json(args.output, plan)
+ print(json.dumps({"mode": "apply" if args.apply else "dry-run", **plan["summary"]}, sort_keys=True))
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/tools/kurultai/buildroom/scripts/buildroom_healthcheck.py b/tools/kurultai/buildroom/scripts/buildroom_healthcheck.py
new file mode 100644
index 00000000..f9cd220e
--- /dev/null
+++ b/tools/kurultai/buildroom/scripts/buildroom_healthcheck.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+
+import argparse
+import json
+import subprocess
+import sys
+from pathlib import Path
+from typing import Any
+
+ROOT = Path(__file__).resolve().parents[4]
+BUILDROOM = ROOT / "tools" / "kurultai" / "buildroom"
+
+
+def run(command: list[str]) -> dict[str, Any]:
+ proc = subprocess.run(command, cwd=ROOT, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ return {"command": command, "exit_code": proc.returncode, "output": proc.stdout[-4000:]}
+
+
+def generated_files_present() -> dict[str, Any]:
+ expected = [
+ BUILDROOM / "control-room-attention-items.json",
+ BUILDROOM / "control-room-kanban-drafts.json",
+ BUILDROOM / "control-room.json",
+ BUILDROOM / "control-room.html",
+ BUILDROOM / "control-room.md",
+ ]
+ missing = [str(path.relative_to(ROOT)) for path in expected if not path.exists()]
+ return {"name": "generated-files-present", "exit_code": 0 if not missing else 1, "missing": missing, "output": ""}
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(description="Run public-safe buildroom canaries and regressions.")
+ parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON.")
+ parser.add_argument("--skip-pytest", action="store_true", help="Skip focused pytest run for quick cron checks.")
+ args = parser.parse_args()
+
+ checks = []
+ rooms = [BUILDROOM / "rooms" / "demo-room", BUILDROOM / "rooms" / "2026-05-10-gkisokay-auto-think-auto-build"]
+ for room in rooms:
+ checks.append({"name": f"validate:{room.name}", **run([sys.executable, "tools/kurultai/buildroom/scripts/validate_room.py", str(room)])})
+ checks.append({"name": "control-room-generate", **run([sys.executable, "tools/kurultai/buildroom/scripts/control_room.py"])})
+ checks.append({"name": "control-room-cron", **run([sys.executable, "tools/kurultai/buildroom/scripts/control_room_cron.py"])})
+ checks.append({"name": "kanban-bridge-dry-run", **run([sys.executable, "tools/kurultai/buildroom/scripts/apply_kanban_drafts.py"])})
+ checks.append(generated_files_present())
+ checks.append({"name": "compileall-buildroom", **run([sys.executable, "-m", "compileall", "-q", "tools/kurultai/buildroom/scripts"])})
+ if not args.skip_pytest:
+ checks.append({"name": "pytest-buildroom", **run([sys.executable, "-m", "pytest", "tests/kurultai/test_buildroom_foundation.py", "--no-cov", "-q"])})
+ passed = all(check["exit_code"] == 0 for check in checks)
+ payload = {"passed": passed, "checks": checks}
+ if args.json:
+ print(json.dumps(payload, indent=2, sort_keys=True))
+ else:
+ print(f"buildroom healthcheck: {'PASS' if passed else 'FAIL'}")
+ for check in checks:
+ print(f"- {check['name']}: exit {check['exit_code']}")
+ return 0 if passed else 1
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/tools/kurultai/buildroom/scripts/common.py b/tools/kurultai/buildroom/scripts/common.py
index 04e9e523..9e27a9fc 100644
--- a/tools/kurultai/buildroom/scripts/common.py
+++ b/tools/kurultai/buildroom/scripts/common.py
@@ -1,6 +1,7 @@
from __future__ import annotations
import json
+import os
import re
import shutil
from datetime import datetime, timezone
@@ -29,6 +30,13 @@
def utc_now() -> str:
return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
+
+def default_workspace_path() -> str:
+ configured = os.environ.get("KURULTAI_HOME", "").strip()
+ if configured:
+ return str(Path(configured).expanduser().resolve())
+ return str(BUILDROOM_ROOT.parents[2].resolve())
+
def load_json(path: Path) -> Any:
with path.open("r", encoding="utf-8") as handle: return json.load(handle)
diff --git a/tools/kurultai/buildroom/scripts/kanban_adapter.py b/tools/kurultai/buildroom/scripts/kanban_adapter.py
index 22c0678b..753cf4f8 100644
--- a/tools/kurultai/buildroom/scripts/kanban_adapter.py
+++ b/tools/kurultai/buildroom/scripts/kanban_adapter.py
@@ -6,7 +6,7 @@
from pathlib import Path
from typing import Any
-from common import load_json, resolve_room_path, utc_now, write_json
+from common import default_workspace_path, load_json, resolve_room_path, utc_now, write_json
def _kanban_parent_ids(task_refs: list[Any]) -> list[str]:
@@ -85,7 +85,7 @@ def build_task_packet(room: Path) -> dict[str, Any]:
"body": body,
"parents": _kanban_parent_ids(task_refs),
"workspace_kind": "dir",
- "workspace_path": "${KURULTAI_HOME}",
+ "workspace_path": default_workspace_path(),
"idempotency_key": f"buildroom:{build_id}",
"metadata": {
"room_id": room.name,
diff --git a/tools/kurultai/buildroom/scripts/opportunity_radar.py b/tools/kurultai/buildroom/scripts/opportunity_radar.py
new file mode 100644
index 00000000..6671bb0e
--- /dev/null
+++ b/tools/kurultai/buildroom/scripts/opportunity_radar.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+import argparse, hashlib, json, os
+from datetime import datetime, timezone
+from pathlib import Path
+from typing import Any
+ROOT = Path(__file__).resolve().parents[4]
+BUILDROOM = ROOT / "tools" / "kurultai" / "buildroom"
+DEFAULT_BRAIN = Path(os.environ.get("BRAIN_ROOT", "/Users/kublai/brain"))
+WEIGHTS = {"user_leverage":1.4,"compounding_value":1.6,"tractability":1.1,"verification_clarity":1.2,"risk_reversibility":1.2,"dependency_readiness":1.0,"future_behavior_improvement":1.7,"urgency_freshness":0.8}
+SCAN_DIRS = ["queue","generated","docs/proposals","docs/plans","docs/designs","docs/kurultai","receipts"]
+TOPIC_RULES: list[dict[str, Any]] = [
+ {"title":"Buildroom Opportunity Radar v0","candidate_type":"system-improvement","aliases":["opportunity radar","auto think","what should we build next","ranked build intent"],"summary":"Build a local-first strategy layer that ranks next buildroom candidates from Brain and buildroom evidence.","why_now":"Kurultai has a strong Auto Build loop, but candidate selection is still less inspectable than execution.","expected_leverage":"Turns Brain artifacts into recurring ranked build intent and reduces ad hoc operator steering.","acceptance_criteria":["emit JSON and markdown reports","score candidates explainably","emit dry-run Kanban drafts","link recommendations to source refs","pass tests and leakage scan"],"base_scores":{"user_leverage":5,"compounding_value":5,"tractability":4,"verification_clarity":4,"risk_reversibility":5,"dependency_readiness":5,"future_behavior_improvement":5,"urgency_freshness":4}},
+ {"title":"Agent Harness Maturity Scoreboard","candidate_type":"evaluation-candidate","aliases":["harness maturity","agent engineering","eval","regression","sandbox","observability"],"summary":"Score projects, agents, and buildrooms against harness maturity primitives.","why_now":"The agent-engineering research argues that agent engineering is harness engineering.","expected_leverage":"Makes agent trust and hardening gaps visible before autonomy expands.","acceptance_criteria":["produce explainable maturity scores","surface improvement recommendations","integrate with Control Room"],"base_scores":{"user_leverage":4,"compounding_value":5,"tractability":4,"verification_clarity":4,"risk_reversibility":5,"dependency_readiness":4,"future_behavior_improvement":5,"urgency_freshness":3}},
+ {"title":"Brain Compiler Coverage Ledger","candidate_type":"brain-compiler","aliases":["compiler coverage","memory is leverage","no-op receipt","changed future behavior","processed until"],"summary":"Report which meaningful sources changed behavior and which still need synthesis, skill, Kanban, receipt, or no-op disposition.","why_now":"The Brain has more durable artifacts; now it needs coverage accounting to prevent passive storage.","expected_leverage":"Enforces the invariant that memory only matters when it changes future behavior or gets a no-op receipt.","acceptance_criteria":["scan queue/generated/reviews/proposals/receipts","identify missing dispositions","emit coverage report"],"base_scores":{"user_leverage":4,"compounding_value":5,"tractability":4,"verification_clarity":5,"risk_reversibility":5,"dependency_readiness":4,"future_behavior_improvement":5,"urgency_freshness":3}},
+ {"title":"Paper-only Bounty Proof Loop","candidate_type":"external-opportunity","aliases":["bounty","proof loop","revenue","external acceptance","payment"],"summary":"Design a paper-only workflow for evaluating external opportunities without external side effects.","why_now":"There is upside, but reputation and payment surfaces require stronger proof gates first.","expected_leverage":"Creates a safe path to evaluate economic opportunities without uncontrolled commitments.","acceptance_criteria":["evaluate five opportunities on paper","classify proceed/no-op/needs approval","perform no external actions"],"base_scores":{"user_leverage":3,"compounding_value":4,"tractability":3,"verification_clarity":3,"risk_reversibility":2,"dependency_readiness":3,"future_behavior_improvement":3,"urgency_freshness":2},"gates":["external-side-effect-approval-required"]},
+ {"title":"Buildroom-to-Content OS Bridge","candidate_type":"content-candidate","aliases":["content os","public artifact","x article","launch","article"],"summary":"Convert completed buildrooms into evidence-backed content candidates.","why_now":"Buildrooms are starting to produce reusable doctrine and receipts.","expected_leverage":"Turns proven internal work into public learning when safe.","acceptance_criteria":["extract claims/evidence","scan public/private boundary","draft publish/no-op recommendation"],"base_scores":{"user_leverage":3,"compounding_value":4,"tractability":3,"verification_clarity":3,"risk_reversibility":4,"dependency_readiness":3,"future_behavior_improvement":3,"urgency_freshness":2}},
+]
+def utc_now() -> str: return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00","Z")
+def rel_ref(path: Path, base: Path, prefix: str) -> str:
+ try: return f"{prefix}/{path.relative_to(base).as_posix()}"
+ except ValueError: return path.name
+def discover_brain(brain_root: Path) -> list[dict[str, Any]]:
+ artifacts=[]
+ if not brain_root.exists(): return artifacts
+ for sub in SCAN_DIRS:
+ folder=brain_root/sub
+ if not folder.exists(): continue
+ for path in sorted(folder.rglob("*.md")):
+ try: text=path.read_text(encoding="utf-8", errors="ignore")
+ except OSError: continue
+ title=path.stem
+ for line in text.splitlines()[:30]:
+ s=line.strip()
+ if s.lower().startswith("title:"): title=s.split(":",1)[1].strip().strip('"') or title; break
+ if s.startswith("# "): title=s[2:].strip() or title; break
+ artifacts.append({"ref":rel_ref(path, brain_root, "brain"),"title":title,"text":text.lower(),"kind":sub})
+ return artifacts
+def discover_buildroom(buildroom_root: Path) -> dict[str, Any]:
+ summary={"rooms":[],"control_room_present":False,"attention_count":0,"kanban_draft_count":0}
+ rooms=buildroom_root/"rooms"
+ if rooms.exists(): summary["rooms"]=[p.name for p in sorted(rooms.iterdir()) if p.is_dir()]
+ summary["control_room_present"]=(buildroom_root/"control-room.json").exists()
+ for name,key in [("control-room-attention-items.json","attention_count"),("control-room-kanban-drafts.json","kanban_draft_count")]:
+ try:
+ payload=json.loads((buildroom_root/name).read_text())
+ summary[key]=int(payload.get("attention_count") or payload.get("draft_count") or len(payload.get("items") or payload.get("drafts") or []))
+ except Exception: pass
+ return summary
+def stable_id(title: str, candidate_type: str, refs: list[str]) -> str:
+ raw=json.dumps({"title":title.lower(),"type":candidate_type,"refs":sorted(refs)[:8]}, sort_keys=True)
+ return hashlib.sha256(raw.encode()).hexdigest()[:12]
+def score_total(scores: dict[str,int]) -> float: return round(sum(scores.get(k,0)*w for k,w in WEIGHTS.items()),1)
+def source_matches(rule: dict[str, Any], artifacts: list[dict[str, Any]]) -> list[dict[str, str]]:
+ aliases=[a.lower() for a in rule["aliases"]]; matches=[]
+ for artifact in artifacts:
+ hay=artifact["text"]+" "+artifact["title"].lower()+" "+artifact["ref"].lower()
+ hits=sum(1 for a in aliases if a in hay)
+ if hits: matches.append({"ref":artifact["ref"],"title":artifact["title"],"kind":artifact["kind"],"hit_count":hits})
+ return sorted(matches, key=lambda m:(-m["hit_count"], m["ref"]))[:8]
+def build_candidates(artifacts: list[dict[str, Any]], buildroom_summary: dict[str, Any]) -> list[dict[str, Any]]:
+ candidates=[]
+ for rule in TOPIC_RULES:
+ matches=source_matches(rule, artifacts); refs=[m["ref"] for m in matches]; scores=dict(rule["base_scores"])
+ if not matches:
+ scores["verification_clarity"]=max(0,scores["verification_clarity"]-1); scores["dependency_readiness"]=max(0,scores["dependency_readiness"]-1)
+ total=score_total(scores)+min(3,len(matches)); gates=list(rule.get("gates", [])); disposition="buildroom-candidate"
+ if gates: disposition="needs-human-approval"
+ elif total < 20: disposition="no-op"
+ elif total < 30: disposition="backlog"
+ elif total < 38: disposition="watch"
+ candidates.append({"id":stable_id(rule["title"],rule["candidate_type"],refs),"title":rule["title"],"candidate_type":rule["candidate_type"],"source_refs":refs,"summary":rule["summary"],"why_now":rule["why_now"],"expected_leverage":rule["expected_leverage"],"acceptance_criteria":rule["acceptance_criteria"],"risks":gates or ["scope creep","duplicate work","weak outcome feedback"],"dependencies":["Brain artifacts","buildroom Control Room outputs"],"recommended_disposition":disposition,"scores":{**scores,"total":total},"explainability":{"top_positive_factors":["compounds future agent behavior","local-first and reversible",f"{len(matches)} supporting source artifacts"],"top_negative_factors":gates or (["limited direct source evidence in this run"] if not matches else ["requires calibration against outcomes"]),"counterarguments":["Could create noisy recommendations if reports are not capped","Scoring must not replace verified user value"]},"source_evidence":matches,"proposed_artifacts":[]})
+ return sorted(candidates, key=lambda c:(-float(c["scores"]["total"]), c["title"]))
+def kanban_drafts(candidates: list[dict[str, Any]], threshold: float) -> list[dict[str, Any]]:
+ drafts=[]
+ for c in candidates:
+ if float(c["scores"]["total"]) < threshold or c["recommended_disposition"] not in {"buildroom-candidate","watch"}: continue
+ body="\n".join([f"Candidate: {c['title']}",f"Type: {c['candidate_type']}",f"Score: {c['scores']['total']}",f"Disposition: {c['recommended_disposition']}",f"Why now: {c['why_now']}",f"Expected leverage: {c['expected_leverage']}","Acceptance criteria:",*[f"- {a}" for a in c["acceptance_criteria"]]])
+ drafts.append({"title":f"Buildroom opportunity: {c['title']}","body":body,"labels":["buildroom","opportunity-radar",c["candidate_type"],c["recommended_disposition"]],"priority":"high" if float(c["scores"]["total"])>=42 else "normal","source":"buildroom-opportunity-radar-v0","candidate_id":c["id"]})
+ return drafts
+def markdown_report(payload: dict[str, Any]) -> str:
+ lines=["# Buildroom Opportunity Radar","",f"Generated: {payload['generated_at']}","","## Summary","",f"Candidates: {len(payload['candidates'])}",f"Kanban drafts: {len(payload['kanban_drafts'])}","","## Top candidates",""]
+ for c in payload["candidates"][:8]:
+ lines += [f"### {c['title']}","",f"- Type: `{c['candidate_type']}`",f"- Score: `{c['scores']['total']}`",f"- Disposition: `{c['recommended_disposition']}`",f"- Why now: {c['why_now']}",f"- Expected leverage: {c['expected_leverage']}",f"- Sources: {len(c['source_refs'])}","- Acceptance criteria:"]
+ lines += [f" - {a}" for a in c["acceptance_criteria"]]
+ lines += ["- Counterarguments:"]+[f" - {a}" for a in c["explainability"]["counterarguments"]]+[""]
+ if payload.get("warnings"): lines += ["## Warnings",""]+[f"- {w}" for w in payload["warnings"]]
+ return "\n".join(lines).rstrip()+"\n"
+def main() -> int:
+ parser=argparse.ArgumentParser(description="Rank buildroom opportunities from Brain and buildroom evidence.")
+ parser.add_argument("--brain-root", default=str(DEFAULT_BRAIN)); parser.add_argument("--buildroom-root", default=str(BUILDROOM)); parser.add_argument("--json-output", default=str(BUILDROOM/"opportunity-radar.json")); parser.add_argument("--markdown-output", default=str(BUILDROOM/"opportunity-radar.md")); parser.add_argument("--kanban-drafts-output", default=str(BUILDROOM/"opportunity-radar-kanban-drafts.json")); parser.add_argument("--draft-threshold", type=float, default=38.0); parser.add_argument("--json", action="store_true")
+ args=parser.parse_args(); artifacts=discover_brain(Path(args.brain_root).expanduser()); summary=discover_buildroom(Path(args.buildroom_root).expanduser()); candidates=build_candidates(artifacts,summary); drafts=kanban_drafts(candidates,args.draft_threshold); warnings=[]
+ if not artifacts: warnings.append("No Brain artifacts discovered; output is based on canonical fallback candidates only.")
+ if not summary.get("control_room_present"): warnings.append("Control Room JSON not found; buildroom state evidence is partial.")
+ payload={"schema_version":"0.1.0","generated_at":utc_now(),"mode":"dry-run","input_summary":{"brain_artifact_count":len(artifacts),"buildroom_count":len(summary.get("rooms",[])),"control_room_present":summary.get("control_room_present",False),"attention_count":summary.get("attention_count",0),"kanban_draft_count":summary.get("kanban_draft_count",0)},"candidates":candidates,"rejected":[],"warnings":warnings,"recommended_next_action":candidates[0]["title"] if candidates else None,"kanban_drafts":drafts}
+ for path,data in [(Path(args.json_output),payload),(Path(args.kanban_drafts_output),{"source":"buildroom-opportunity-radar-v0","generated_at":payload["generated_at"],"draft_count":len(drafts),"drafts":drafts})]: path.parent.mkdir(parents=True, exist_ok=True); path.write_text(json.dumps(data, indent=2, sort_keys=True)+"\n")
+ md=Path(args.markdown_output); md.parent.mkdir(parents=True, exist_ok=True); md.write_text(markdown_report(payload))
+ if args.json: print(json.dumps({"candidate_count":len(candidates),"draft_count":len(drafts),"recommended_next_action":payload["recommended_next_action"],"warnings":warnings}, indent=2, sort_keys=True))
+ else: print(f"Wrote {args.json_output}, {args.markdown_output}, and {args.kanban_drafts_output}")
+ return 0
+if __name__ == "__main__": raise SystemExit(main())
diff --git a/tools/kurultai/buildroom/scripts/qa_trust.py b/tools/kurultai/buildroom/scripts/qa_trust.py
index 44df2653..11b442ca 100644
--- a/tools/kurultai/buildroom/scripts/qa_trust.py
+++ b/tools/kurultai/buildroom/scripts/qa_trust.py
@@ -7,7 +7,7 @@
from pathlib import Path
from typing import Any
-from common import load_json, resolve_room_path, utc_now, write_json
+from common import default_workspace_path, load_json, resolve_room_path, utc_now, write_json
def _as_list(value: Any) -> list[Any]:
@@ -97,7 +97,7 @@ def build_qa_packet(room: Path) -> dict[str, Any]:
"body": body,
"parents": [parent] if parent else [],
"workspace_kind": "dir",
- "workspace_path": "${KURULTAI_HOME}",
+ "workspace_path": default_workspace_path(),
"idempotency_key": f"buildroom-qa:{build_id}",
"metadata": {
"room_id": room.name,
diff --git a/tools/kurultai/buildroom/scripts/retention_review.py b/tools/kurultai/buildroom/scripts/retention_review.py
new file mode 100644
index 00000000..e4ebedc7
--- /dev/null
+++ b/tools/kurultai/buildroom/scripts/retention_review.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+
+import argparse
+import json
+from pathlib import Path
+from typing import Any
+
+ROOT = Path(__file__).resolve().parents[1]
+ROOMS = ROOT / "rooms"
+OUTPUT = ROOT / "control-room-retention-items.json"
+
+
+def load_json(path: Path) -> dict[str, Any]:
+ if not path.exists():
+ return {}
+ data = json.loads(path.read_text())
+ return data if isinstance(data, dict) else {}
+
+
+def write_json(path: Path, payload: Any) -> None:
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n")
+
+
+def room_dirs(root: Path) -> list[Path]:
+ if not root.exists():
+ return []
+ return sorted(path for path in root.iterdir() if path.is_dir())
+
+
+def retention_item(room: Path) -> dict[str, Any] | None:
+ retention = load_json(room / "retention" / "retention-review.json")
+ trust = load_json(room / "trust" / "trust-report.json")
+ summary = load_json(room / "operator" / "operator-summary.json")
+ recommendation = str(retention.get("recommendation") or retention.get("retention_recommendation") or "").lower()
+ status = str(retention.get("status") or retention.get("decision_status") or "pending").lower()
+ if recommendation in {"", "keep"} and status in {"resolved", "complete", "completed"}:
+ return None
+ needs_receipt = status not in {"resolved", "complete", "completed"}
+ trust_state = str(trust.get("trust_state") or trust.get("state") or "unknown")
+ next_action = str(summary.get("next_action") or "review retention recommendation and write receipt")
+ severity = "medium" if recommendation in {"improve", "prune"} or trust_state in {"watch", "investigate"} else "low"
+ return {
+ "id": f"retention:{room.name}",
+ "room_id": room.name,
+ "recommendation": recommendation or "review",
+ "status": status,
+ "trust_state": trust_state,
+ "severity": severity,
+ "needs_receipt": needs_receipt,
+ "next_action": next_action,
+ "receipt_template": f"brain/receipts/kurultai/{{date}}-{room.name}-retention-review.md",
+ }
+
+
+def build_payload(rooms_root: Path) -> dict[str, Any]:
+ items = [item for room in room_dirs(rooms_root) if (item := retention_item(room))]
+ try:
+ rooms_ref = str(rooms_root.resolve().relative_to(ROOT.resolve()))
+ except ValueError:
+ rooms_ref = "${BUILDROOM_ROOMS}"
+ return {"rooms_root": rooms_ref, "items": items, "summary": {"items": len(items), "needs_receipt": sum(1 for item in items if item["needs_receipt"])}}
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(description="Emit buildroom retention follow-up items without deleting anything.")
+ parser.add_argument("--rooms", type=Path, default=ROOMS)
+ parser.add_argument("--output", type=Path, default=OUTPUT)
+ parser.add_argument("--fail-on-items", action="store_true")
+ args = parser.parse_args()
+ payload = build_payload(args.rooms)
+ write_json(args.output, payload)
+ print(json.dumps(payload["summary"], sort_keys=True))
+ return 1 if args.fail_on_items and payload["items"] else 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/tools/kurultai/buildroom/scripts/run_buildroom_cycle.py b/tools/kurultai/buildroom/scripts/run_buildroom_cycle.py
new file mode 100644
index 00000000..9b30847b
--- /dev/null
+++ b/tools/kurultai/buildroom/scripts/run_buildroom_cycle.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+import argparse, json, subprocess
+from datetime import datetime, timezone
+from pathlib import Path
+from typing import Any
+ROOT = Path(__file__).resolve().parents[4]
+BUILDROOM = ROOT / "tools" / "kurultai" / "buildroom"
+PYTHON = "/opt/homebrew/opt/python@3.14/bin/python3.14"
+def now() -> str: return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00","Z")
+def run(cmd: list[str], cwd: Path = ROOT, allow_codes: set[int] | None = None) -> dict[str, Any]:
+ allow_codes=allow_codes or {0}; proc=subprocess.run(cmd, cwd=cwd, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ return {"command":cmd,"exit_code":proc.returncode,"ok":proc.returncode in allow_codes,"output_tail":"\n".join(proc.stdout.splitlines()[-20:])}
+def room_dirs() -> list[Path]:
+ rooms=BUILDROOM/"rooms"; return [p for p in sorted(rooms.iterdir()) if p.is_dir()] if rooms.exists() else []
+
+def load_json(path: Path) -> Any:
+ if not path.exists():
+ return None
+ return json.loads(path.read_text())
+
+def proposal_summary() -> dict[str, Any]:
+ radar = load_json(BUILDROOM / "opportunity-radar.json") or {}
+ radar_drafts = load_json(BUILDROOM / "opportunity-radar-kanban-drafts.json") or {}
+ control_drafts = load_json(BUILDROOM / "control-room-kanban-drafts.json") or {}
+ attention = load_json(BUILDROOM / "control-room-attention-items.json") or {}
+ retention = load_json(BUILDROOM / "control-room-retention-items.json") or {}
+ candidates = radar.get("candidates", []) if isinstance(radar, dict) else []
+ def compact_candidate(candidate: dict[str, Any]) -> dict[str, Any]:
+ scores = candidate.get("scores", {}) if isinstance(candidate.get("scores"), dict) else {}
+ return {
+ "title": candidate.get("title"),
+ "disposition": candidate.get("disposition") or candidate.get("recommended_disposition"),
+ "summary": candidate.get("summary"),
+ "score": scores.get("total"),
+ "score_breakdown": {k: v for k, v in scores.items() if k != "total"},
+ }
+ return {
+ "outcome": {
+ "attention_items": len(attention.get("items", [])) if isinstance(attention, dict) else 0,
+ "control_room_kanban_drafts": len(control_drafts.get("drafts", [])) if isinstance(control_drafts, dict) else 0,
+ "opportunity_radar_candidates": len(candidates),
+ "opportunity_radar_kanban_drafts": len(radar_drafts.get("drafts", [])) if isinstance(radar_drafts, dict) else 0,
+ "retention_items": len(retention.get("items", [])) if isinstance(retention, dict) else 0,
+ },
+ "recommended_next_action": radar.get("recommended_next_action") if isinstance(radar, dict) else None,
+ "proposals": [compact_candidate(c) for c in candidates if isinstance(c, dict)],
+ "control_room_drafts": control_drafts.get("drafts", []) if isinstance(control_drafts, dict) else [],
+ }
+
+def print_proposal_report(summary: dict[str, Any], ok: bool, receipt: Path) -> None:
+ outcome = summary.get("outcome", {})
+ print(f"Buildroom cycle {'passed' if ok else 'failed'}; receipt: {receipt}")
+ print("")
+ print("Outcome:")
+ for key, value in outcome.items():
+ print(f"- {key.replace('_', ' ')}: {value}")
+ print("")
+ print("Proposals:")
+ proposals = summary.get("proposals", [])
+ if not proposals:
+ print("- none")
+ for index, proposal in enumerate(proposals, 1):
+ print(f"{index}. {proposal.get('title')} — {proposal.get('disposition')} — score {proposal.get('score')}")
+ if proposal.get("summary"):
+ print(f" {proposal['summary']}")
+ if summary.get("recommended_next_action"):
+ print("")
+ print(f"Recommended next action: {summary['recommended_next_action']}")
+
+def main() -> int:
+ parser=argparse.ArgumentParser(description="Run a local buildroom cycle to completion on command.")
+ parser.add_argument("--apply-kanban", action="store_true"); parser.add_argument("--skip-pytest", action="store_true"); parser.add_argument("--json", action="store_true"); parser.add_argument("--receipt-output", default=str(BUILDROOM/".generated"/"buildroom-cycle-receipt.json")); args=parser.parse_args(); steps=[]
+ for room in room_dirs(): steps.append(run(["python3", str(BUILDROOM/"scripts/validate_room.py"), str(room)]))
+ steps.append(run(["python3", str(BUILDROOM/"scripts/control_room.py")]))
+ steps.append(run(["python3", str(BUILDROOM/"scripts/control_room_cron.py")]))
+ steps.append(run(["python3", str(BUILDROOM/"scripts/opportunity_radar.py")]))
+ kanban_cmd=["python3", str(BUILDROOM/"scripts/apply_kanban_drafts.py"), "--output", str(BUILDROOM/".generated"/"kanban-apply-result.json")]
+ if args.apply_kanban: kanban_cmd.append("--apply")
+ steps.append(run(kanban_cmd))
+ steps.append(run(["python3", str(BUILDROOM/"scripts/retention_review.py")]))
+ health=[PYTHON, str(BUILDROOM/"scripts/buildroom_healthcheck.py"), "--json"]
+ if args.skip_pytest: health.append("--skip-pytest")
+ steps.append(run(health)); ok=all(s["ok"] for s in steps); out=Path(args.receipt_output); proposals=proposal_summary()
+ receipt={"schema_version":"0.1.0","generated_at":now(),"source":"run-buildroom-cycle-v0","mode":"apply-kanban" if args.apply_kanban else "dry-run","ok":ok,"step_count":len(steps),"steps":steps,"proposal_summary":proposals,"outputs":{"control_room":"tools/kurultai/buildroom/control-room.md","opportunity_radar":"tools/kurultai/buildroom/opportunity-radar.md","kanban_apply_result":"tools/kurultai/buildroom/.generated/kanban-apply-result.json","retention_items":"tools/kurultai/buildroom/control-room-retention-items.json"}}
+ out.parent.mkdir(parents=True, exist_ok=True); out.write_text(json.dumps(receipt, indent=2, sort_keys=True)+"\n")
+ if args.json: print(json.dumps({"ok":ok,"step_count":len(steps),"receipt":str(out),"failed_steps":[s for s in steps if not s["ok"]],"proposal_summary":proposals}, indent=2, sort_keys=True))
+ else: print_proposal_report(proposals, ok, out)
+ return 0 if ok else 1
+if __name__ == "__main__": raise SystemExit(main())