Jobs object combines a survey with agents, scenarios, and models. Calling by() constructs the execution specification; calling run() executes it.
Think of a job as the complete set of interviews you want to collect. Each interview runs the survey with one agent, one scenario, and one model and produces one result record containing its answers. EDSL runs the combinations for you, so you can compare conditions without writing a separate loop for each one.
Construct a job
This example crosses four respondent profiles with two message conditions. It constructs eight interviews per model and iteration without making model calls.job.by(model).prompts(), and estimate costs. A ModelList expands the job across the selected configurations.
Execute and inspect
After configuring credentials and model access:disable_remote_inference=True for local orchestration; provider calls may still be remote. Use a test model for an offline smoke test as shown in the Run your first survey tutorial.
With one model and iteration, this example returns eight rows. Each row contains a profile’s clarity rating for one message. The selected columns retain the condition and experience level needed to compare those ratings. See Results for filtering, grouping, and exporting them.
Background runs and persistence
Save a job as an.ep package to retain the full run specification. Use Background jobs for long remote work and the CLI Guide to submit, poll, and retrieve results from scripts or coding agents.
Pair inputs or specify assignments
By default,by() crosses agents, scenarios, and models. Use zip_assign() when each agent should receive the scenario at the same position:
strict=True). Each pair is still crossed with the remaining models. job.assign([{"agent": 0, "scenario": 1, "model": 0}, ...]) instead specifies exact combinations using zero-based indices into the job’s component lists.
For a condition over combinations, use job.include_when("{{ agent.role == scenario.required_role }}"). The named fields must exist in your inputs. Calling assign() or zip_assign() replaces an inclusion expression; calling include_when() replaces an assignment plan. Inspect job.interviews() after choosing the design and before running it.
Reuse a cache or run asynchronously
job.using(cache) or job.using_cache(cache) attaches a Cache to the job; passing cache=cache to run() is the explicit per-run alternative. survey.using(cache) and question.using(cache) construct Jobs with that cache attached.
In an asynchronous function or a notebook that supports top-level await, use await job.run_async(...). It accepts run options such as cache, n, disable_remote_inference, and disable_remote_cache. Background submission is a different workflow: see Background jobs.
Common methods
Execution options
Pass these keywords directly tojob.run(). A real model run can incur costs; review model access and costs first.
For a small local run using the eight combinations constructed above:
n=2 repeats each of the eight combinations twice, producing 16 interview records with fixed test answers here. It does not create new profiles or conditions. Select iteration alongside the answers when comparing repetitions. Use background jobs for submission and later retrieval, and remote execution for hosted execution settings.
Package a reusable workflow
AMacro combines an input survey, a job that uses those inputs as scenario fields, and named output formats. Use one when other users should supply a few parameters to a repeatable EDSL workflow.
macro.output() returns a MacroRunOutput; accessing a named format applies the corresponding OutputFormatter to its Results. Provider execution requires credentials and may incur costs. macro.by({"text": "..."}).run() and macro.run(text="...") are parameter-setting shortcuts using the default execution settings; use output() when specifying execution options.
macro.with_output_formatter("rows", OutputFormatter(output_type="ScenarioList").select("answer.feedback").to_scenario_list()) returns a macro with another named output. A macro instance can reuse previously generated results for the same prepared job, so repeated calls are not automatically independent model draws.
For sharing, macro.push(visibility="private") uploads the workflow; Macro.pull(identifier) retrieves a full macro when you have access. Macro("owner/alias") creates a client for a deployed macro and executes it remotely when called. Access to a deployed macro and its underlying definition can differ.