Skip to main content
When you have multiple agents working on a research problem, they often need to share information — one task produces a result that another task uses as input. Qualia’s task-variable evidence system passes those values between tasks through the qualia package, which is available in every notebook kernel and in every script an agent runs.
This system was previously called Q_VARS. The in-kernel global Q_VARS has been replaced by the qualia package (Python), library(qualia) (R), and Qualia (Julia) — same flow, a real per-language client instead of an injected blob.
Qualia handles capture automatically, but it’s useful to know how the system works.

How it works

The basic flow:
  1. Declare required variables on a task
  2. Assign values in a notebook cell (just use the variable name)
  3. Capture happens automatically when the cell runs
  4. Other agents read values in downstream tasks with qualia.get()

Reading captured evidence

In a downstream task’s notebook, read values captured by upstream tasks. The qualia namespace is already in scope — no import needed:
To recover a value scoped to one task (for example after a kernel reset, or in a fresh subagent), use the typed read:

Capturing variables

In a notebook, variables are captured from cells automatically:
  1. Define required variables when creating a task
  2. Run code that assigns values to those variable names
  3. Qualia captures the values when the cell executes
For example, if a task requires best_model and accuracy:
After this cell runs, both values are captured and available to downstream tasks. You can also be explicit, from the cell that produced the value:
This fans out across every in-progress task on the session that declared the slot name — the same semantics as autocapture. For an interesting value the task did not declare, record it as evidence without filling a slot:
Pass recall_priority ("low" by default, up to "global") when the value is something later agents should be shown rather than have to go looking for. See recall priority.
Captured variables become runtime-captured claims in the Knowledge System, creating a documented trail of data flow.

Capturing from a script

Scripts use the same package. There is no cell boundary, so there is no automatic capture — the script submits before it exits — and it imports the client itself. The qualia methods are async. Notebook cells can await them directly because IPython enables autoawait, but a script has to run them itself: top-level await is a SyntaxError outside a cell.
Calling qualia.submit_variable(...) without await does not capture anything. It builds a coroutine that is never run, and Python only reports it as a RuntimeWarning when the object is garbage collected.
R and Julia work the same way, with one difference worth knowing. Julia cannot read a calling function’s local variables by name, so add_evidence there is a macro:
A script claim points at the line of the script that produced the value, the way a notebook claim points at its cell. That line is re-checked whenever the claim is read, so editing the script past it marks the source as changed.

Provenance: values come from a runtime, full stop

There’s no way to set a variable from outside the running code. Values are captured from real Python/R/Julia assignments, or from submit_variable / add_evidence calls made inside a notebook cell or a running script. add_evidence takes the variable name and reads that variable from the live runtime; agents cannot pass a separate literal evidence value through tool arguments. This is why a computed value is better recorded from the runtime than written to a file and quoted: the runtime holds the actual value, with its real precision and type, while a file only holds however it was formatted on the way out. To leave a declared slot permanently unfilled, the agent skips it with update_task(skip_variables=...) — a state decision, never a value.

When tasks use variable evidence

Most useful when:
  • Chaining experiments: One task trains a model, another evaluates it
  • Aggregating results: Multiple parallel tasks produce metrics, a final task compares them
  • Parameterized workflows: Pass configuration between stages
Example workflow:

Exporting notebooks

When you export a notebook for standalone use, Qualia replaces qualia.get() calls (and the R/Julia equivalents) with their actual values. The exported notebook runs without Qualia — all variable references are resolved to concrete data, so it works in other IDEs such as JupyterLab and VS Code.

Technical details

The qualia package is shipped by the platform as a path overlay — nothing is installed into your environment. In a notebook it is pre-loaded by the kernel attach hook; in a script it is on the path for you to import. It communicates with the backend via authenticated API calls configured when the kernel or the command starts. The system supports:
  • Python, R, and Julia, in notebook kernels and in scripts, with one shared wire contract across all of them
  • Primitive values: numbers, strings, booleans, and homogeneous lists of those. Dicts, DataFrames, and other complex objects are rejected — capture separate scalar variables instead
  • Session-scoped fan-out: a captured value fills the matching declared slot on every in-progress task in the session