Custom Views
Overview
By default the log viewer chooses sensible defaults for how a task’s samples are listed, how their scores are summarized, and how scanner results are displayed. For your own task, however you have a better idea which scores matter, which columns are worth showing, and more. Your task can customize the view directly by using the viewer arg of the Task.
For example, the following customizes the Task’s view by passing a set of columns, a default sort, and enables multiline display (which may be better for long textual fields):
from inspect_ai import Task, task
from inspect_ai.scorer import match
from inspect_ai.viewer import (
TaskSamplesColumn,
TaskSamplesSort,
TaskSamplesView,
ViewerConfig,
)
@task
def popularity():
return Task(
name="popularity",
dataset=dataset,
scorer=match(location="any"),
viewer=ViewerConfig(
task_samples_view=TaskSamplesView(
name="Default",
columns=[
TaskSamplesColumn(id="sampleId"),
TaskSamplesColumn(id="input"),
TaskSamplesColumn(id="target"),
TaskSamplesColumn(id="answer"),
TaskSamplesColumn.score("match"),
TaskSamplesColumn(id="sampleStatus", visible=False),
TaskSamplesColumn(id="tokens", visible=False),
TaskSamplesColumn(id="duration", visible=False),
],
sort=[
TaskSamplesSort.score("match", dir="asc"),
TaskSamplesSort(column="sampleId", dir="asc"),
],
multiline=True,
)
),
)The configuration that you specify in your task will be serialized into the eval log when it is written, so the configuration will be used for anyone viewing the log file produced using the configuration.
ViewerConfig covers three areas, each configured independently:
| Field | Configures |
|---|---|
task_samples_view |
The task’s sample list — the grid of samples shown for an eval log. |
sample_score_view |
The score panel in an individual sample’s score display. |
scanner_result_view |
The scanner results sidebar (for scanners). |
These settings are defaults, not overrides. The viewer honors them only until a reviewer customizes the view in their own browser. The resolution priority is user override > view configuration > viewer built-in, so a user’s hand-picked columns or sort always win and are never clobbered by the eval default.
The Sample List
task_samples_view configures the grid of samples shown for an eval log. A TaskSamplesView requires a name and accepts optional column, sort, and presentation settings — any field left unset falls back to the viewer’s built-in behaviour.
from inspect_ai.viewer import (
ViewerConfig,
TaskSamplesView,
TaskSamplesColumn,
TaskSamplesSort,
)
ViewerConfig(
task_samples_view=TaskSamplesView(
name="Triage",
columns=[
TaskSamplesColumn(id="sampleId"),
TaskSamplesColumn(id="input"),
TaskSamplesColumn.score("my_scorer"),
TaskSamplesColumn(id="target", visible=False),
],
sort=[TaskSamplesSort.score("my_scorer", dir="desc")],
multiline=True,
)
)- 1
- Controls the order of these columns.
- 2
- Hide these columns by default.
- 3
-
Sort by
my_scorer’s value, descending. - 4
- Enable multiline display.
Columns
You can control the order and visibility of columns within the task’s sample list by passing a list of TaskSamplesColumn to columns. The order of the columns in this list is the default order for the columns in the sample view. Use visible=False on a column to hide it by default. Leaving columns as None uses the viewer’s built-in column set for that log’s shape.
All samples have the following built-in columns available:
sampleStatus, sampleId, sampleUuid, epoch, input, target, answer, tokens, duration, retries, error, limit.
Score columns
Score columns are addressed by scorer name with the score() helpers. For simple scorers, you can just pass the scorer name:
TaskSamplesColumn.score("my_scorer")
TaskSamplesSort.score("my_scorer", dir="desc")Pass the score you’d like to target when a scorer emits a dictionary of named sub-scores:
TaskSamplesColumn.score("my_scorer", "calibration")Sort
sort is a list of TaskSamplesSort entries (each a column id and a dir of "asc" or "desc"), applied in order. Use TaskSamplesSort.score(...) to sort on a score column.
Score labels
score_labels renames score column headers for display, keyed by score name. Lookup falls back to the scorer name when no override is set.
TaskSamplesView(
name="Audit",
score_labels={
"situational_awareness": "Situational Awareness",
"ascii-art": "ASCII Art",
},
)Color scales
Numeric score cells can be shaded with a background heat scale. score_color_scales is keyed by score name, and each entry is either a named palette, a ScoreColorScale (a palette with an explicit value range), or — for categorical scores — a map from value to a semantic role.
from inspect_ai.viewer import TaskSamplesView, ScoreColorScale
TaskSamplesView(
name="Heat",
score_color_scales={
# named palette anchored to the observed data range
"accuracy": "good-high",
# palette pinned to a known 1..10 rubric so middling values
# aren't paint-clamped when the data clusters at one end
"concerning": ScoreColorScale(palette="good-low", min=1, max=10),
# categorical score → semantic roles
"verdict": {"yes": "bad", "no": "good", "maybe": "warn"},
},
color_scales_enabled=True,
)Numeric palettes map a value’s position in the range to a colour along a gradient (low → high):
| Palette | Low → High | Use when |
|---|---|---|
good-high |
higher is better (e.g. accuracy) | |
good-low |
lower is better (e.g. error rate) | |
neutral |
magnitude only, no good/bad signal | |
diverging |
signed values centred on the midpoint |
Categorical roles assign a fixed colour to each mapped value:
| Role | Colour | Conveys |
|---|---|---|
good |
green | a positive / desired outcome |
bad |
red | a negative / undesired outcome |
warn |
amber | a borderline / needs-attention outcome |
info |
blue | a neutral, informational value |
muted |
grey | a low-salience value |
The swatches above approximate light mode; the actual cell colours are theme variables that adapt to light / dark. Pass/fail and boolean scores ignore this config — their pre-coloured pills already encode the result. color_scales_enabled seeds the toolbar heatmap toggle’s initial state.
Row layout
multiline controls row density: True (the default) gives list-style multi-line rows; False gives compact single-line rows. compact_scores narrows score columns and rotates their headers 45° to fit many scores side by side.
The Score Panel
sample_score_view configures the score panel shown in an individual sample’s detail view (distinct from the score columns in the sample list above). It applies when a sample has three or more scores.
from inspect_ai.viewer import ViewerConfig, SampleScoreView, SampleScoreViewSort
ViewerConfig(
sample_score_view=SampleScoreView(
default="chips",
sort=SampleScoreViewSort(column="value", dir="desc"),
)
)defaultchooses the initial rendering mode:chips(wrapping pills) orgrid(a sortable table). When unset, the viewer picks based on the number of scores.sortsets the initial sort byname(scorer name) orvalue, with a direction ofascordesc.
Scanner Results
scanner_result_view customizes the scanner results sidebar for samples produced with scanners. It is a glob-keyed map from scanner-name pattern to a ScannerResultView, so you can target specific scanners or apply one configuration to all of them:
from inspect_ai.viewer import (
ViewerConfig,
ScannerResultView,
ScannerResultField,
MetadataField,
)
ViewerConfig(
scanner_result_view={
"*": ScannerResultView(
fields=[
ScannerResultField(name="explanation", label="Rationale"),
MetadataField(key="summary", label="Summary"),
"value",
],
exclude_fields=["validation"],
),
}
)Keys are fnmatch-style globs ("*", "audit_*", or exact scanner names). As a shorthand, you can pass a bare ScannerResultView instead of a map to apply a single configuration to every scanner.
fields is an ordered list of sections to render; entries are:
- A ScannerResultField — a built-in section (
explanation,label,value,validation,answer, ormetadata), with an optionallabeloverride andcollapseddefault. - A MetadataField — promotes a single
metadata[key]entry into its own top-level section. - A bare string — shorthand for the matching ScannerResultField name.
exclude_fields subtracts sections from the resolved set. Excluding a MetadataField also removes that key from the generic metadata dump.
Reference
See the inspect_ai.viewer reference for the complete field list of every type described here.

