Skip to main content

Common Contexta Workflows

This guide focuses on the day-to-day tasks most users care about once a workspace already contains canonical data.

The safest default remains:

  • start with Contexta
  • bind it to one workspace
  • use facade methods first
  • move to direct store or recovery APIs only when you need more control

If you have not created a working workspace yet, finish Getting Started first.

Open One Workspace

Most workflows begin by opening one workspace through one facade:

from pathlib import Path

from contexta import Contexta
from contexta.config import UnifiedConfig, WorkspaceConfig

ctx = Contexta(
config=UnifiedConfig(
project_name="guide-proj",
workspace=WorkspaceConfig(root_path=Path(".contexta")),
)
)

Use one workspace per logical project or experiment family. That keeps run refs, reports, and recovery actions easier to reason about.

Inspect One Run

If you already know a canonical run ref, the fastest read path is a run snapshot:

snapshot = ctx.get_run_snapshot("run:guide-proj.demo-run")

print(snapshot.run.run_id)
print(snapshot.run.status)
print(len(snapshot.stages))
print(len(snapshot.records))
print(len(snapshot.artifacts))

Use this workflow when you want to answer:

  • what happened in this run?
  • which stages were present?
  • how much evidence exists in the workspace already?

Compare Two Runs

Run comparison is the next most common workflow once you have more than one execution to inspect:

comparison = ctx.compare_runs(
"run:guide-proj.demo-run",
"run:guide-proj.demo-run-v2",
)

print(comparison.summary)
print(len(comparison.stage_comparisons))

If you are comparing multiple candidate runs and want one best run by a metric:

best = ctx.select_best_run(
[
"run:guide-proj.demo-run",
"run:guide-proj.demo-run-v2",
],
metric_key="accuracy",
higher_is_better=True,
)

print(best)

Use compare when you want to inspect:

  • metric changes
  • stage-level differences
  • report-level differences
  • best-run selection for one metric

Build Reports

Once the data is in canonical form, report generation stays under the same facade:

snapshot_report = ctx.build_snapshot_report("run:guide-proj.demo-run")
compare_report = ctx.build_run_report(
"run:guide-proj.demo-run",
"run:guide-proj.demo-run-v2",
)
project_report = ctx.build_project_summary_report("guide-proj")

Reports can then be materialized into formats that fit the downstream task:

markdown_text = snapshot_report.to_markdown()
html_text = snapshot_report.to_html()
json_payload = snapshot_report.to_json()

Use report generation when you want output that is easier to:

  • review
  • share
  • archive
  • render into HTML or export workflows later

Inspect Diagnostics

Diagnostics are useful when you want the system to point at incomplete or suspicious states:

diagnostics = ctx.diagnose_run("run:guide-proj.demo-run")

for issue in diagnostics.issues:
print(issue.severity, issue.code, issue.summary)

Use diagnostics when you want a quicker answer to:

  • what looks incomplete?
  • what looks inconsistent?
  • which issues should I inspect first?

Trace Lineage

Lineage helps when the question is about relationships rather than one run in isolation:

traversal = ctx.traverse_lineage(
"artifact:guide-proj.demo-run.model",
direction="outbound",
max_depth=3,
)

print(len(traversal.edges))
print(len(traversal.visited_refs))

Use lineage when you want to ask:

  • where did this artifact come from?
  • what depends on this result?
  • what sits upstream or downstream of this subject?

If the question is about run-to-run movement instead of a single comparison, use a trend query:

trend = ctx.get_metric_trend(
"accuracy",
project_name="guide-proj",
)

print(trend.metric_key)
print(len(trend.points))

Trend workflows are useful for:

  • metric drift across runs
  • project-level progress over time
  • identifying values worth deeper comparison

Runtime Capture From Actual Work

The runtime capture surface is most meaningful when the signal is produced by the operation under observation:

"""Train a real regression model and capture its measured evidence."""

import pickle
from pathlib import Path

from sklearn.datasets import load_diabetes
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score
from sklearn.model_selection import train_test_split

from contexta import Contexta
from contexta.capture import LocalJsonlSink


features, targets = load_diabetes(return_X_y=True)
train_x, test_x, train_y, test_y = train_test_split(
features, targets, test_size=0.2, random_state=42
)

workspace = Path(".contexta")
ctx = Contexta(workspace=str(workspace), config={"project_name": "diabetes-regression"})
local_sink = next(sink for sink in ctx.sinks if isinstance(sink, LocalJsonlSink))
model = LinearRegression()

with ctx.run("linear-regression", dataset_ref="dataset:sklearn.diabetes") as run:
run.event(
"dataset.loaded",
message="Loaded the scikit-learn diabetes dataset",
attributes={"rows": len(features), "features": features.shape[1]},
)
with run.stage("train"):
model.fit(train_x, train_y)

with run.stage("evaluate") as stage:
predictions = model.predict(test_x)
r2 = r2_score(test_y, predictions)
mae = mean_absolute_error(test_y, predictions)
stage.metric("r2", r2, unit="ratio")
stage.metric("mae", mae)

model_path = workspace / "models" / "linear-regression.pkl"
model_path.parent.mkdir(parents=True, exist_ok=True)
model_path.write_bytes(pickle.dumps(model))
run.register_artifact("model", str(model_path), attributes={"format": "pickle"})

records_path = local_sink.file_path_for("RECORD").relative_to(Path.cwd())

print(f"Captured run: {run.ref}")
print(f"Measured r2: {r2:.3f}; mae: {mae:.3f}")
print(f"Records: {records_path.as_posix()}")
print(f"Model artifact: {model_path.as_posix()}")

Use runtime capture when you want:

  • live instrumentation in application code
  • scope-aware event and metric emission
  • one product surface for lifecycle and capture behavior

The displayed programs are covered by automated tests, so their captured metrics remain tied to executable behavior.

When To Use Something Else

Stay with the facade when your goal is:

  • inspect one run
  • compare runs
  • build reports
  • diagnose problems
  • trace lineage

Move to the advanced guide when you need:

  • explicit config resolution
  • direct store access
  • backup or restore planning

Where To Go Next

Continue with: