Skip to content

Commit 780514b

Browse files
committed
docs: default to deterministic excalidraw exporter
1 parent a41ef7a commit 780514b

11 files changed

Lines changed: 62 additions & 42 deletions

PUBLISHING.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ git push -u origin main
1515
1. The repo-level docs match the shipped skill contract.
1616
2. `code-explainer/SKILL.md` reflects the current pipeline and proof path.
1717
3. `python code-explainer/scripts/self_audit.py` passes.
18-
4. `install_to_codex.ps1` copies the current package cleanly, including `package.json` and `package-lock.json`.
18+
4. `install_to_codex.ps1` copies the current package cleanly.
1919
5. `meta/excalidraw_report.json` is part of the output contract and the self-audit proves editable scene generation.
2020

2121
Recommended:
@@ -54,9 +54,7 @@ Recommended for higher-fidelity diagram rendering:
5454

5555
- Mermaid CLI (`@mermaid-js/mermaid-cli`)
5656

57-
The repo also ships a local Excalidraw bridge dependency through `package.json`.
58-
59-
Even without live LLM access, the proof path still works through `CODE_EXPLAINER_MOCK_LLM=true`. Even if the official Excalidraw bridge is browser-dependent in the local environment, the shipped deterministic fallback scene generator keeps the editable-diagram proof path working and records the downgrade in `meta/excalidraw_report.json`.
57+
Even without live LLM access, the proof path still works through `CODE_EXPLAINER_MOCK_LLM=true`. The deterministic Excalidraw scene generator is now the default production path, so the repo does not need to ship the official bridge dependency in its default install surface. If a developer wants to experiment with the official bridge anyway, they can install it locally with `npm install --no-save @excalidraw/mermaid-to-excalidraw` and enable `--enable-official-excalidraw-bridge true`.
6058

6159
## GitHub Distribution
6260

README.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ The older build looked polished but produced weak output. The current contract i
4545
```text
4646
code-explainer/
4747
SKILL.md
48-
package.json
49-
package-lock.json
5048
agents/openai.yaml
5149
assets/
5250
fixtures/
@@ -70,10 +68,6 @@ Recommended:
7068

7169
- Mermaid CLI (`mmdc`) from `@mermaid-js/mermaid-cli`
7270

73-
Installed locally by the skill runtime:
74-
75-
- `@excalidraw/mermaid-to-excalidraw`
76-
7771
Windows:
7872

7973
```powershell
@@ -94,7 +88,7 @@ From this repository root:
9488
powershell -ExecutionPolicy Bypass -File .\install_to_codex.ps1
9589
```
9690

97-
This copies the current skill package into `~/.codex/skills/code-explainer`. Restart Codex after installation, then run the skill runtime installer inside the installed copy if you need the local Node dependencies there.
91+
This copies the current skill package into `~/.codex/skills/code-explainer`. Restart Codex after installation.
9892

9993
## Run
10094

@@ -110,6 +104,7 @@ python scripts/analyze.py analyze \
110104
--overview-length medium \
111105
--enable-llm-descriptions true \
112106
--enable-excalidraw-export true \
107+
--enable-official-excalidraw-bridge false \
113108
--ask-before-llm-use false \
114109
--prompt-for-llm-key false \
115110
--enable-web-enrichment false
@@ -124,13 +119,14 @@ Useful controls:
124119
- `--explainer-type onboarding|project-recap|plan-review|diff-review`
125120
- `--audience nontech|mixed|engineering`
126121
- `--enable-excalidraw-export true|false`
122+
- `--enable-official-excalidraw-bridge true|false`
127123

128124
## Diagram and Excalidraw Behavior
129125

130126
- Mermaid remains the canonical source of truth.
131127
- The skill exports editable Excalidraw scenes from that Mermaid set.
132-
- If the official Excalidraw bridge works in the local runtime, it is used directly.
133-
- If the official bridge is browser-dependent or unavailable, the skill falls back to a deterministic local scene generator for the Mermaid subset it emits and records that downgrade in `meta/excalidraw_report.json`.
128+
- The deterministic local scene generator is the default production path.
129+
- The official Excalidraw bridge is opt-in only through `--enable-official-excalidraw-bridge true` and is intended for development experiments, not the default runtime.
134130

135131
## LLM Behavior
136132

code-explainer/SKILL.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ python scripts/analyze.py analyze \
5252
--exclude-glob <pattern> \
5353
--enable-llm-descriptions <true|false> \
5454
--enable-excalidraw-export <true|false> \
55+
--enable-official-excalidraw-bridge <true|false> \
5556
--ask-before-llm-use <true|false> \
5657
--prompt-for-llm-key <true|false> \
5758
--enable-web-enrichment <true|false>
@@ -66,6 +67,7 @@ Defaults:
6667
- `overview-length=medium`
6768
- `enable-llm-descriptions=true`
6869
- `enable-excalidraw-export=true`
70+
- `enable-official-excalidraw-bridge=false`
6971
- `ask-before-llm-use=false`
7072
- `prompt-for-llm-key=false`
7173
- `enable-web-enrichment=true`
@@ -84,10 +86,11 @@ Defaults:
8486
3. Build `explanation_plan.json` with top modules, audience starting points, diagram purposes, and caveats.
8587
4. Generate the narrative layer with LLM or grounded mock/deterministic fallback.
8688
5. Build focused diagrams tied to onboarding questions.
87-
6. Export those diagrams into editable Excalidraw scenes when the local runtime is installed.
88-
7. Generate overview and deep docs from the explanation plan plus narrative layer.
89-
8. Run fact-check and explanation-quality evaluation.
90-
9. Fail the run if quality gates do not clear the rubric.
89+
6. Export those diagrams into editable Excalidraw scenes through the deterministic local exporter.
90+
7. Optionally prefer the official Excalidraw bridge only when explicitly enabled for development experiments.
91+
8. Generate overview and deep docs from the explanation plan plus narrative layer.
92+
9. Run fact-check and explanation-quality evaluation.
93+
10. Fail the run if quality gates do not clear the rubric.
9194

9295
## Proof Path
9396

@@ -110,7 +113,7 @@ Required:
110113
Recommended:
111114

112115
- Mermaid CLI (`mmdc`) from `@mermaid-js/mermaid-cli` for higher-fidelity diagram rendering
113-
- `@excalidraw/mermaid-to-excalidraw` installed locally via `npm install` for editable Excalidraw scene export
116+
- Node.js is only required for GitHub cloning and optional development-time Excalidraw bridge experiments
114117

115118
Install dependencies:
116119

@@ -129,7 +132,8 @@ bash ./scripts/install_runtime.sh
129132
- This skill does not mutate the analyzed repository.
130133
- If the explanation-quality score is below the rubric threshold, treat the output as failed even if files were produced.
131134
- If Excalidraw export is enabled, treat missing or partial editable scene generation as a real quality issue, not a cosmetic extra.
132-
- When the official Excalidraw bridge is unavailable or browser-dependent in the local runtime, the skill falls back to a deterministic local scene generator for the Mermaid subset it emits and records that downgrade in `meta/excalidraw_report.json`.
135+
- The deterministic local Excalidraw exporter is the canonical production path.
136+
- The official `@excalidraw/mermaid-to-excalidraw` bridge is opt-in only via `--enable-official-excalidraw-bridge true` and should be treated as a development experiment, not a required runtime dependency.
133137
- Use include/exclude globs to narrow analysis when the repository is very large or noisy.
134138

135139
## References

code-explainer/references/diagram-style-guide.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
3. Keep labels short and plain-language-first for non-technical readers.
88
4. Split diagrams when readability is degraded by scale.
99
5. Mermaid remains the canonical source; Excalidraw exports are editable derivatives of those same diagrams.
10+
6. The deterministic local Excalidraw exporter is the default production path; the official bridge is optional and development-only.
1011

1112
## Standard Mode Diagram Set
1213

code-explainer/references/output-contract.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070
- `excalidraw_export_requested`
7171
- `excalidraw_export_status`
7272
- `excalidraw_scene_count`
73+
- `official_excalidraw_bridge_requested`
74+
- `official_excalidraw_bridge_used`
7375
- `html_generated`
7476

7577
## Coverage Schema
@@ -185,6 +187,8 @@
185187
- `environment_blocked`
186188
- `scene_count`
187189
- `failed_count`
190+
- `official_bridge_requested`
191+
- `official_bridge_used`
188192
- `warnings[]`
189193
- `runtime`
190194
- `results[]` where each result has:

code-explainer/scripts/analyze.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ def _write_manifest(
127127
"excalidraw_export_requested": excalidraw_payload.get("requested", False),
128128
"excalidraw_export_status": excalidraw_payload.get("status", "disabled"),
129129
"excalidraw_scene_count": excalidraw_payload.get("scene_count", 0),
130+
"official_excalidraw_bridge_requested": excalidraw_payload.get("official_bridge_requested", False),
131+
"official_excalidraw_bridge_used": excalidraw_payload.get("official_bridge_used", 0),
130132
"html_generated": bool(html_payload.get("output_file")),
131133
"module_count": module_count,
132134
"diagram_count": diagram_count,
@@ -147,6 +149,7 @@ def run_pipeline(
147149
enable_web_enrichment: bool,
148150
enable_llm_descriptions: bool,
149151
enable_excalidraw_export: bool,
152+
enable_official_excalidraw_bridge: bool = False,
150153
ask_before_llm_use: bool = False,
151154
prompt_for_llm_key: bool = False,
152155
include_globs: List[str] | None = None,
@@ -255,6 +258,7 @@ def run_pipeline(
255258
rendered_diagrams_dir=output_root / "diagrams",
256259
meta_dir=meta_dir,
257260
enabled=enable_excalidraw_export,
261+
prefer_official_bridge=enable_official_excalidraw_bridge,
258262
)
259263

260264
docs_gen_payload = generate_docs.generate_docs(
@@ -356,6 +360,7 @@ def run_pipeline(
356360
"renderer": render_payload.get("renderer", ""),
357361
"excalidraw_status": excalidraw_payload.get("status", "disabled"),
358362
"excalidraw_scene_count": excalidraw_payload.get("scene_count", 0),
363+
"official_excalidraw_bridge_used": excalidraw_payload.get("official_bridge_used", 0),
359364
"html_generated": bool(html_payload.get("output_file")),
360365
"fact_check_passed": fact_check_payload.get("passed", False),
361366
"quality_passed": quality_payload.get("passed", False),
@@ -399,6 +404,7 @@ def _parse_args() -> argparse.Namespace:
399404
parser.add_argument("--enable-web-enrichment", default="true")
400405
parser.add_argument("--enable-llm-descriptions", default="true")
401406
parser.add_argument("--enable-excalidraw-export", default="true")
407+
parser.add_argument("--enable-official-excalidraw-bridge", default="false")
402408
parser.add_argument("--ask-before-llm-use", default="false")
403409
parser.add_argument("--prompt-for-llm-key", default="false")
404410
return parser.parse_args()
@@ -414,6 +420,7 @@ def main() -> int:
414420
web_enabled = common.bool_from_string(args.enable_web_enrichment)
415421
llm_enabled = common.bool_from_string(args.enable_llm_descriptions)
416422
excalidraw_enabled = common.bool_from_string(args.enable_excalidraw_export)
423+
official_excalidraw_bridge_enabled = common.bool_from_string(args.enable_official_excalidraw_bridge)
417424
ask_before_llm_use = common.bool_from_string(args.ask_before_llm_use)
418425
prompt_for_llm_key = common.bool_from_string(args.prompt_for_llm_key)
419426
summary = run_pipeline(
@@ -427,6 +434,7 @@ def main() -> int:
427434
enable_web_enrichment=web_enabled,
428435
enable_llm_descriptions=llm_enabled,
429436
enable_excalidraw_export=excalidraw_enabled,
437+
enable_official_excalidraw_bridge=official_excalidraw_bridge_enabled,
430438
ask_before_llm_use=ask_before_llm_use,
431439
prompt_for_llm_key=prompt_for_llm_key,
432440
include_globs=args.include_glob,
@@ -453,6 +461,7 @@ def main() -> int:
453461
"renderer",
454462
"excalidraw_status",
455463
"excalidraw_scene_count",
464+
"official_excalidraw_bridge_used",
456465
"html_generated",
457466
"fact_check_passed",
458467
"quality_passed",

code-explainer/scripts/export_excalidraw.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,14 @@ def _runtime_status() -> Dict[str, Any]:
3131
node = common.which("node")
3232
bridge = SCRIPT_DIR / "mermaid_to_excalidraw.mjs"
3333
package_dir = SKILL_DIR / "node_modules" / "@excalidraw" / "mermaid-to-excalidraw"
34-
package_json = SKILL_DIR / "package.json"
3534

3635
issues: List[str] = []
3736
if not node:
3837
issues.append("Node.js was not found on PATH.")
3938
if not bridge.exists():
4039
issues.append("The Mermaid-to-Excalidraw bridge script is missing.")
41-
if not package_json.exists():
42-
issues.append("package.json is missing from the skill runtime.")
4340
if not package_dir.exists():
44-
issues.append("The @excalidraw/mermaid-to-excalidraw package is not installed.")
41+
issues.append("The @excalidraw/mermaid-to-excalidraw package is not installed in this skill directory.")
4542

4643
return {
4744
"ok": len(issues) == 0,
@@ -352,6 +349,7 @@ def export_excalidraw(
352349
rendered_diagrams_dir: Path,
353350
meta_dir: Path,
354351
enabled: bool = True,
352+
prefer_official_bridge: bool = False,
355353
) -> Dict[str, Any]:
356354
scene_dir = common.ensure_dir(rendered_diagrams_dir / "excalidraw")
357355
svg_dir = common.ensure_dir(scene_dir / "svg")
@@ -366,16 +364,29 @@ def export_excalidraw(
366364
"environment_blocked": False,
367365
"scene_count": 0,
368366
"failed_count": 0,
367+
"official_bridge_requested": False,
368+
"official_bridge_used": 0,
369369
"results": [],
370370
"warnings": ["Excalidraw export disabled by caller."],
371371
}
372372
common.write_json(report_path, payload)
373373
return payload
374374

375-
runtime = _runtime_status()
375+
runtime = (
376+
_runtime_status()
377+
if prefer_official_bridge
378+
else {
379+
"ok": False,
380+
"node": "",
381+
"bridge": (SCRIPT_DIR / "mermaid_to_excalidraw.mjs").as_posix(),
382+
"package_dir": (SKILL_DIR / "node_modules" / "@excalidraw" / "mermaid-to-excalidraw").as_posix(),
383+
"issues": [],
384+
}
385+
)
376386
results: List[Dict[str, Any]] = []
377387
scene_count = 0
378388
failed_count = 0
389+
bridge_used_count = 0
379390
renderer_svg_dir = rendered_diagrams_dir / "svg"
380391
renderer_png_dir = rendered_diagrams_dir / "png"
381392

@@ -401,7 +412,7 @@ def export_excalidraw(
401412
}
402413

403414
bridge_error = ""
404-
if runtime["ok"]:
415+
if prefer_official_bridge and runtime["ok"]:
405416
code, stdout, stderr = common.run_cmd(
406417
[
407418
runtime["node"],
@@ -420,6 +431,7 @@ def export_excalidraw(
420431
payload = common.read_json(scene_path, default={})
421432
entry["status"] = "ok"
422433
entry["exporter"] = "official-bridge"
434+
bridge_used_count += 1
423435
entry["element_count"] = len(payload.get("elements", []))
424436
entry["file_count"] = len(payload.get("files", {}))
425437
if stdout.strip():
@@ -443,7 +455,7 @@ def export_excalidraw(
443455
entry["file_count"] = len(fallback.get("files", {}))
444456
if bridge_error:
445457
entry["warnings"].append(bridge_error)
446-
if not runtime["ok"]:
458+
if prefer_official_bridge and not runtime["ok"]:
447459
entry["warnings"].extend(runtime["issues"])
448460
except Exception as exc:
449461
failed_count += 1
@@ -468,7 +480,7 @@ def export_excalidraw(
468480
status = "partial" if scene_count > 0 else "failed"
469481

470482
warnings: List[str] = []
471-
if not runtime["ok"]:
483+
if prefer_official_bridge and not runtime["ok"]:
472484
warnings.append("Official Excalidraw bridge runtime unavailable; used the local deterministic scene generator.")
473485
warnings.extend(runtime["issues"])
474486

@@ -479,6 +491,8 @@ def export_excalidraw(
479491
"environment_blocked": False,
480492
"scene_count": scene_count,
481493
"failed_count": failed_count,
494+
"official_bridge_requested": prefer_official_bridge,
495+
"official_bridge_used": bridge_used_count,
482496
"results": results,
483497
"warnings": warnings,
484498
"runtime": runtime,
@@ -493,13 +507,15 @@ def main() -> int:
493507
parser.add_argument("--rendered-diagrams-dir", required=True)
494508
parser.add_argument("--meta-dir", required=True)
495509
parser.add_argument("--enabled", default="true")
510+
parser.add_argument("--prefer-official-bridge", default="false")
496511
args = parser.parse_args()
497512

498513
payload = export_excalidraw(
499514
diagrams_dir=Path(args.diagrams_dir).resolve(),
500515
rendered_diagrams_dir=Path(args.rendered_diagrams_dir).resolve(),
501516
meta_dir=Path(args.meta_dir).resolve(),
502517
enabled=common.bool_from_string(args.enabled),
518+
prefer_official_bridge=common.bool_from_string(args.prefer_official_bridge),
503519
)
504520
print(
505521
json.dumps(

code-explainer/scripts/install_runtime.ps1

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,14 @@ npm --version
1414
Write-Host "Checking Git..."
1515
git --version
1616

17-
Write-Host "Installing local Node runtime packages..."
18-
Push-Location $SkillDir
19-
npm install
20-
Pop-Location
21-
2217
Write-Host "Installing Mermaid CLI (mmdc)..."
2318
npm install -g @mermaid-js/mermaid-cli
2419

2520
Write-Host "Validating mmdc..."
2621
mmdc --version
2722

28-
Write-Host "Validating Excalidraw export bridge..."
29-
Push-Location $SkillDir
30-
node ".\\scripts\\mermaid_to_excalidraw.mjs" --help | Out-Null
31-
Pop-Location
23+
Write-Host "Optional: to enable the official Excalidraw bridge for development, run:"
24+
Write-Host " cd `"$SkillDir`""
25+
Write-Host " npm install --no-save @excalidraw/mermaid-to-excalidraw"
3226

3327
Write-Host "Runtime install complete."

code-explainer/scripts/install_runtime.sh

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,14 @@ npm --version
1414
echo "Checking Git..."
1515
git --version
1616

17-
echo "Installing local Node runtime packages..."
18-
(cd "$SKILL_DIR" && npm install)
19-
2017
echo "Installing Mermaid CLI (mmdc)..."
2118
npm install -g @mermaid-js/mermaid-cli
2219

2320
echo "Validating mmdc..."
2421
mmdc --version
2522

26-
echo "Validating Excalidraw export bridge..."
27-
(cd "$SKILL_DIR" && node "./scripts/mermaid_to_excalidraw.mjs" --help >/dev/null)
23+
echo "Optional: to enable the official Excalidraw bridge for development, run:"
24+
echo " cd \"$SKILL_DIR\""
25+
echo " npm install --no-save @excalidraw/mermaid-to-excalidraw"
2826

2927
echo "Runtime install complete."

code-explainer/scripts/self_audit.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def _run_fixture(base_output: Path, fixture: Dict[str, Any]) -> Dict[str, Any]:
4545
enable_web_enrichment=False,
4646
enable_llm_descriptions=True,
4747
enable_excalidraw_export=True,
48+
enable_official_excalidraw_bridge=False,
4849
)
4950
quality = common.read_json(output_root / "meta" / "quality_report.json", default={})
5051
explanation_quality = common.read_json(output_root / "meta" / "explanation_quality.json", default={})

0 commit comments

Comments
 (0)