Matrix evaluation¶
This document explains the design decision for the /matrix command that creates cross-product evaluation tables.
Context¶
When exploring ideas in Canvas Chat, users often need to evaluate multiple options against multiple criteria. For example:
- Evaluating 10 mRNA therapy ideas against 5 development criteria
- Comparing product features across customer segments
- Assessing risks against mitigation strategies
Doing this manually requires creating many individual nodes and loses the structured relationship between rows and columns.
Decision¶
We implemented a /matrix command that creates a specialized MATRIX node type representing a cross-product evaluation table.
User flow¶
- Select two nodes containing lists (e.g., "10 ideas" and "5 criteria")
- Type
/matrix <context>where context describes the evaluation goal - Confirm axes in modal - review parsed items, remove unwanted ones, swap rows/columns
- Create empty matrix - table appears with "+" buttons in each cell
- Fill cells - click individual cells, rows, columns, or "Fill All"
- View and pin - click filled cells to see details, optionally pin to canvas
Alternatives considered¶
Individual nodes for each evaluation¶
Create a separate node for each row×column combination.
Advantages:
- Simpler implementation
- Each evaluation is a first-class node
Disadvantages:
- Overwhelming for large matrices (50+ nodes for 10×5)
- Loses visual structure of the matrix relationship
- Difficult to compare across rows or columns
Markdown table in a single node¶
Generate a markdown table with all evaluations in one node.
Advantages:
- Simple rendering
- Compact display
Disadvantages:
- No interactivity (can't fill cells individually)
- Can't branch from individual cells
- All-or-nothing generation
Spreadsheet-like interface¶
Full spreadsheet with formulas, sorting, filtering.
Advantages:
- Maximum flexibility
- Familiar interface
Disadvantages:
- Scope creep beyond chat interface
- Complex implementation
- Doesn't integrate with DAG structure
Why interactive matrix nodes¶
The matrix node approach provides the best balance:
- Structured visualization - clear rows, columns, and cells
- Incremental filling - fill one cell, one row, or all at once
- Cell-level interaction - view details, pin to canvas
- DAG integration - pinned cells become nodes you can branch from
- Context-aware generation - each cell fill includes DAG history
Implementation notes¶
Axis limits¶
Maximum 10 items per axis (100 cells total). This prevents:
- Overwhelming API costs
- UI performance issues
- Unreadable tables
Users are warned when their lists exceed 10 items.
LLM-powered list parsing¶
The /api/parse-list endpoint uses an LLM to extract list items from freeform text. This handles:
- Numbered lists (
1.,2., etc.) - Bullet lists (
-,*,•) - Paragraph-separated items
- Mixed formats
Cell context¶
When filling a cell, the LLM receives:
- The matrix context (user-provided evaluation goal)
- The row item (full text)
- The column item (full text)
- The DAG history (all ancestor nodes)
This ensures evaluations are informed by the full conversation context.
Pinned cells¶
Clicking a filled cell opens a detail modal. The "Pin to Canvas" action:
- Creates a CELL node with the evaluation content
- Connects it to the matrix via MATRIX_CELL edge (dashed line)
- Positions it to the right of the matrix
Pinned cells are full nodes that can be replied to, branched from, or used as context for new questions.
Future improvements¶
Potential enhancements if needed:
- Row/column fill buttons - fill entire row or column at once
- Re-fill cell - regenerate a cell's content
- Export to CSV - download matrix as spreadsheet
- Sort/filter - reorder rows based on column values
- Cell editing - manually adjust generated content