Data Format
Input: interaction traces
Lattice expects a list of sessions. Each session is a dict with the following keys:
| Key | Type | Required | Description |
|---|---|---|---|
interactions | list | Yes | Ordered list of interaction objects |
time | str | No | ISO datetime string for the session start (used for time-based splitting) |
Each interaction object has:
| Key | Type | Required | Description |
|---|---|---|---|
interaction | str | Yes | The raw interaction text (e.g., "Alice: what is the capital of France?") |
metadata | dict | No | Arbitrary key-value pairs — all values are passed to the LLM as context |
Example
interaction_traces = [
{
"interactions": [
{
"interaction": "Alice: how do I center a div in CSS?",
"metadata": {"time sent": "2026-01-01 10:00:00"}
},
{
"interaction": "assistant: Use flexbox: display:flex; justify-content:center; align-items:center",
"metadata": {"time sent": "2026-01-01 10:00:05"}
},
],
"time": "2026-01-01 10:00:00"
},
# ... more sessions
]
Output: lattice JSON
After calling l.save("lattice.json"), the file has this structure:
{
"nodes": {
"0": [ /* observations */ ],
"1": [ /* L1 insights */ ],
"2": [ /* L2 insights (if built) */ ]
},
"edges": {
"1": [ /* edges from L1 insights → observations */ ],
"2": [ /* edges from L2 insights → L1 insights */ ]
}
}
Observation node (layer 0)
{
"id": 0,
"observation": "Alice appears frustrated, rapidly re-typing the same query multiple times.",
"confidence": 4,
"metadata": {
"input_session": 0,
"time": "2026-01-01 10:00:00"
}
}
Insight node (layer 1+)
{
"id": 0,
"title": "Alice Debugs by Brute Force",
"tagline": "Alice tends to retry without reading error messages carefully.",
"insight": "Rather than reading error output, Alice immediately re-runs with small random changes...",
"context": "Applies when Alice is blocked on a technical task.",
"supporting_evidence": ["Observation IDs 2, 5, 8 all show rapid retries without pausing."],
"merged": [2, 5, 8],
"metadata": {
"input_session": 0,
"time": "2026-01-01 10:00:00"
}
}
Edge
{ "source": 0, "target": 2 }
source is the higher-layer node id; target is the lower-layer node id.
Lattice Configs
Configs are defined using Sequential and layer classes from lattice:
from lattice import Sequential, SessionLayer, TimeLayer, NumberLayer, AllLayer
| Layer class | Behavior | Required metadata |
|---|---|---|
SessionLayer(n=1) | Each session is its own group | input_session |
SessionLayer(n=10) | Every 10 consecutive sessions form one group | input_session |
TimeLayer(by="day") | Group by calendar day | time |
TimeLayer(by="week") | Group by ISO calendar week | time |
TimeLayer(by="month") | Group by month | time |
TimeLayer(by="year") | Group by year | time |
NumberLayer(n=20) | Fixed chunks of N nodes | — |
AllLayer() | Collapse all nodes into one group | — |
Example
config = Sequential(
TimeLayer(by="day"), # L1: one group per calendar day
AllLayer(), # L2: one top-level synthesis
)
For more detail on how layers work and how to define custom splitting logic, see Building Layers.