Context
The Calab.ai Handbook’s Evaluation Workbooks currently use dataviewjs code blocks to auto-generate summary tables from inline criterion fields. Quartz 4 does not support Dataview (Decision 01), so these blocks render as raw code on the published site — a known broken experience.
With the adoption of a distributed criteria architecture (Decision 04), criteria definitions are moving from inline fields within workbook files to structured YAML frontmatter in separate criteria files distributed across Guild Roles/ directories. The workbooks need a rendering mechanism that:
- Aggregates criteria from multiple files across multiple guild directories
- Renders in both Obsidian (authoring) and Quartz (publishing) with rendering parity
- Supports two display modes: summary (aggregated statistics) and detail (full criteria with score fields)
- Follows the established dual-rendering plugin pattern (Decision 03)
Decision
We will implement a criteria-list code block syntax with dual-rendering plugins — a Quartz transformer plugin and a mirrored Obsidian plugin — following the exact same pattern established by the page-list plugin (Decision 03).
Syntax
```criteria-list
role: Engineer
level: L3
mode: summary
```Directives:
| Directive | Required | Values | Description |
|---|---|---|---|
role | Yes | String (e.g., “Engineer”, “Architect”) | The role type to aggregate criteria for |
level | Yes | String (e.g., “L1”, “L2”, “L3”, “L4”, “L5”) | The seniority level |
mode | Yes | summary or detail | Rendering mode |
Rendering Modes
Summary mode — replaces the current dataviewjs auto-summary:
| Guild | Management Practice | Criteria | Self Score (%) | Assessor Score (%) | Delta (%) |
|---|---|---|---|---|---|
| Sales Guild | Stakeholder Mgmt Management | 3 | — | — | — |
| Technology Guild | Software Eng Management | 7 | — | — | — |
| Technology Guild | Solution Eng Management | 8 | — | — | — |
| Technology Guild | Platform Architecture Management | 2 | — | — | — |
| Delivery Guild | Consulting Management | 10 | — | — | — |
| Delivery Guild | Project Mgmt | 5 | — | — | — |
| Delivery Guild | Business Analysis Management | 6 | — | — | — |
Detail mode — replaces the current inline criterion fields:
Renders all criteria grouped by Guild → Management Practice with scoring fields for each criterion.
File Scanning Logic
Both plugins use identical scanning logic:
- Starting from the
02 Guilds/directory, scan all*/Roles/directories recursively - For each
.mdfile found, read its YAML frontmatter - Filter to files where:
type=="role-criteria"rolematches the directive’srolevaluelevelmatches the directive’slevelvalue
- Extract the
criteriaarray from each matching file’s frontmatter - Group all criteria by
guild(from the file’s frontmatter) andsubarea(from each criterion item) - Sort groups: by guild name, then by subarea name within each guild
- Render according to the specified mode
Architecture
Obsidian (authoring) Quartz (publishing)
============================= =============================
registerMarkdownCodeBlockProcessor markdownPlugins() remark plugin
└─ "criteria-list" language └─ visit(tree, "code")
│ │
├─ parseDirectives(source) ├─ parseDirectives(node.value)
├─ vault.getFolderByPath("02 Guilds") ├─ glob("content/02 Guilds/*/Roles/**/*.md")
├─ filter by frontmatter ├─ filter by frontmatter
│ (type, role, level) │ (type, role, level)
├─ extract criteria arrays ├─ extract criteria arrays
├─ group by guild + subarea ├─ group by guild + subarea
├─ sort groups ├─ sort groups
└─ MarkdownRenderer.render() └─ emit MDAST table/heading nodes
Consequences
Benefits
- Rendering parity: Workbooks render identically in Obsidian and Quartz (matching the Decision 03 standard)
- Replaces broken rendering: Eliminates non-functional
dataviewjsblocks from the published site - Dynamic aggregation: Adding or modifying criteria files automatically updates all workbooks that reference the same role+level
- Consistent pattern: Follows the proven
page-listdual-plugin architecture; maintenance teams already understand this pattern - Score management: The detail mode rendering includes score input fields that persist in the workbook file (not in criteria files)
Trade-offs
- Two plugins to maintain: As with
page-list, changes to the scanning/rendering logic must be synchronised between the Quartz transformer and Obsidian plugin - Build time: The Quartz transformer must scan all guild Roles directories and parse frontmatter from criteria files on every build. For the current ~15 files this is negligible; may need caching if file count grows significantly
- No live-reload in Obsidian: As with
page-list, adding a new criteria file requires toggling edit/read mode to see updated output
Considered Alternatives
A. Obsidian Databases (.base files) + Quartz Transformer
Use Obsidian’s native .base database views for workbooks and write a Quartz transformer to render .base files.
Why not chosen: .base files use Obsidian’s internal database format, which is not well-documented and subject to change. Building a Quartz renderer for this format creates a fragile coupling to Obsidian’s internal APIs. The criteria-list code block approach is self-contained and doesn’t depend on Obsidian-specific file formats.
B. Static Markdown Tables Generated by CI Script
Use a pre-build script that reads criteria files and generates static markdown tables in the workbook templates before Quartz build.
Why not chosen: This introduces a build dependency that must run before Quartz build. It would modify workbook files (creating merge conflicts in git), and the static tables in Obsidian wouldn’t auto-update without running the script. The dual-plugin approach provides real-time rendering in both environments without modifying source files.
C. Extend Existing page-list Plugin
Add criteria aggregation capabilities to the existing page-list plugin rather than creating a new plugin.
Why not chosen: The scanning logic, directive syntax, and rendering output are fundamentally different. page-list scans for overview files and renders navigation links; criteria-list scans for criteria files and renders scored tables. Combining them would violate single-responsibility and make both harder to maintain.
Next Actions
- Implement per Plan 07, Steps 5-6
- Consider adding score persistence directives in a future revision (e.g.,
score-file: path/to/scores.md) - Monitor rendering performance as criteria file count grows
Related
- 03 Obsidian to Quartz Rendering — Established the dual-rendering plugin pattern
- 04 Distributed Role Criteria Architecture — Criteria distribution and governance model
quartz/plugins/transformers/pageList.ts— Reference implementation for dual-rendering pluginscontent/.obsidian/plugins/obsidian-page-list/main.js— Obsidian-side reference implementation