layout.json (*.html.json) — audit verdict
TL;DR: CUT. Zero production usage (the only two .html.json files in existence are demo test fixtures), the visual editor that was the format's whole reason to exist was never started on the frontend, and the "assemble pages from blocks" value already ships today via plain Jet .html layouts ({{ block }} / {{ yield }}). The cut is ~1 day of deletion work and fully reversible from git history. If the grid-layouts DSL ever gets built, it deserves a fresh schema, not this one.
1. Inventory — what exists
Backend (complete, tested, working):
| Piece | Where | State |
|---|---|---|
| JSON → Jet converter | internal/layoutloader/json_layout.go (425 loc) + json_layout_test.go (617 loc) |
done, well tested |
.html.json load path |
internal/noteloader/loader.go:202-225 (ext detection), internal/layoutloader/loader.go:91,215,426 |
done |
| Sync/push allowlist | internal/case/pushnotes/resolve.go:115-122; obsidian-sync isAlwaysPublishable (see docs/dev/local_design_iteration.md) |
done |
| Block metadata for the editor palette | arg_type parsing in layoutloader/loader.go; GraphQL admin.layoutBlocks (internal/graph/schema.graphqls:1253-1281, resolver schema.resolvers.go:2061) |
done, no consumer |
| JSON live-preview endpoint | POST /_system/layouts/render — internal/case/admin/renderlayoutpreview/ |
done, no callers; already marked "Remove (candidate)" in docs/dev/todo_remove_old_layout.md |
| doclint support | internal/doclint/fsenv.go:45-68 |
done |
| Original content round-trip for sync | internal/model/layout.go:17,45, internal/graph/note_path_content.go:32 |
done |
Frontend (the actual product): nothing. LayoutBlock types appear only in generated GraphQL types (assets/ui/graphql/queries.ts:1414,2776); no component in assets/ui/ queries layoutBlocks or renders any editor. The drag-and-drop tree, property panel, palette, partial preview, and save mutation from docs/dev/json_layouts.md are all unchecked TODOs.
2. Usage reality
- Two
.html.jsonfiles exist across all vaults, both demo fixtures:docs/demo/_layouts/json-test.html.jsonandjson-include-missing.html.json(worktree/tmp copies of the same two). - Every real layout is a plain Jet
.html:docs/_layouts/mesh/*(the site chrome/landing),docs/_layouts/kanban.html,docs/demo/_layouts/*(showcase, yield-blocks demo, components), the kanban_template repo. No page anyone looks at depends on.html.jsontoday. - The block-assembly integration the owner remembers as "neat" is real — but it lives in the Jet
.htmllayer ({{ block card(...) }}indocs/demo/_layouts/components/,custom/blocks.html,yield-blocks-demo.html). It survives a JSON cut untouched. - Bug class: the live-pull layout-wipe data-loss hit
_layouts/*.html.jsonfiles. Cutting the format removes that instance, though the sync empty-overwrite asymmetry itself is on the obsidian-sync side and should be fixed regardless.
3. Effort to finish the original vision
Remaining, per json_layouts.md status lists: /_system/layouts/render partial render (node_path), tree UI component, drag & drop, block palette from GraphQL, typed property panel, live preview wiring, save mutation, else branches for if/range. All frontend work in $mol, which has no existing drag-and-drop tree precedent. Realistic estimate: 10–20 person-days for a usable MVP editor, plus ongoing maintenance — for a feature with zero current demand and a product focus that has moved elsewhere (fleetbox).
And it would be built on the wrong schema: docs/dev/grid_layouts.md (the newer design) plans typed grid/flex/slot nodes that subsume magazine/wide/sidebars. An editor built now on the block-call-only JSON schema would need rework the moment grid layouts land.
4. Verdict: CUT
Why not KEEP/FINISH: the format's only value over .html Jet is machine-editability for a visual editor. No editor, no value — a human authoring .html.json by hand is strictly worse off than writing the Jet directly. Finishing costs 10–20 days against zero demand.
Why not FREEZE: freezing costs nothing today, but keeps a third template format threaded through eight subsystems (noteloader, layoutloader, pushnotes allowlist, GraphQL, doclint, obsidian-sync, writer protocol, docs) — every future change to any of them pays a small .html.json tax, and the docs keep promising an editor that will never come. For a solo-maintained codebase, surface area is the real cost.
Steelman for FREEZE (the one real tension): grid_layouts.md explicitly names JSON layouts as "the natural vehicle" for the grid DSL, and the converter is finished and tested. If the grid DSL is genuinely planned within ~6 months, FREEZE (delete only renderlayoutpreview + layoutBlocks, keep the converter) is defensible. But the grid design itself says "full plan before code," the node types (grid/flex/slot with track sizes and area matrices) share almost nothing with today's block-call schema beyond "it's JSON," and git history preserves the converter anyway. Betting kept code on an unplanned design is how zombie features accumulate.
5. What cutting removes, and migration
Delete list (roughly one day, mostly mechanical):
internal/layoutloader/json_layout.go+ test;.html.jsonbranches inlayoutloader/loader.go(:91,215,426) andnoteloader/loader.go(:202-203,225).internal/case/admin/renderlayoutpreview/+ router regen (already slated bytodo_remove_old_layout.md).- GraphQL:
admin.layoutBlocks,LayoutBlock*types (schema.graphqls:1253-1281), resolver,arg_typeparsing inlayoutloader— unless the palette API is wanted for something else, nothing consumes it. .html.jsoninpushnotes/resolve.go:115-122allowlist and error message; obsidian-syncisAlwaysPublishable+ extension lists;doclint/fsenv.go;note_path_content.gooriginal-content branch (keep for.htmlif shared).- The two demo fixtures; docs: retire
json_layouts.md(move to a "removed features" note), updatewriter_protocol.md,local_design_iteration.md,obsidian_bases.mdmentions.
Migration for users: none needed — no known vault has a real .html.json. Safety valve: on push, reject .html.json with a clear "format removed, use Jet .html layouts" error rather than silently ignoring.
6. Relation to grid_layouts
Grid layouts is a different, better-scoped idea (page chrome as a configurable CSS grid) and does not depend on this format — it needs a schema designed around tracks/areas/slots. If/when it gets its full plan, start that schema clean; the JSON→Jet emitter pattern (the useful lesson from json_layout.go) is recoverable from git in minutes. Cutting now does not close that door.