Skip to main content
The job execution API lets you drive MirrorNeuron directly from Elixir without touching the CLI. You validate a job bundle on disk, submit it for execution, and optionally block until it reaches a terminal state. These three functions form the foundation of any programmatic integration with the MirrorNeuron runtime.

MirrorNeuron.validate_manifest/1

Loads and validates a job bundle folder from disk. Use this to verify that a manifest is structurally correct before attempting to run it. It does not start any processes or modify runtime state.
MirrorNeuron.validate_manifest(input)
input
String.t()
required
Absolute or relative path to a job bundle folder. The folder must contain a manifest.json file and an optional payloads/ subdirectory.

Return values

Returns {:ok, bundle} when the bundle loads and validates without errors.
{:ok, bundle}
bundle
map
A bundle struct describing the loaded job.

Example

case MirrorNeuron.validate_manifest("examples/research_flow") do
  {:ok, bundle} ->
    IO.puts("Manifest valid: #{bundle.manifest_path}")

  {:error, reason} ->
    IO.puts("Validation failed: #{inspect(reason)}")
end
Run validate_manifest/1 in your deployment pipeline to catch manifest errors before they reach a running cluster. It is safe to call repeatedly and has no side effects.

MirrorNeuron.run_manifest/2

Submits a job bundle for execution. By default, the function returns immediately with the assigned job_id. Pass await: true to block until the job reaches a terminal state.
MirrorNeuron.run_manifest(input, opts \\ [])
input
String.t()
required
Path to a job bundle folder. The function calls validate_manifest/1 internally — you do not need to pre-validate unless you want the bundle struct for other purposes.
opts
keyword list
Options that control submission and wait behavior.

Return values

When await: false (the default), returns as soon as the job is accepted by the runtime.
{:ok, job_id}
job_id
string
Unique job identifier assigned by the runtime. Use this with inspection and control functions.

Examples

Fire and forget — submit and move on:
{:ok, job_id} = MirrorNeuron.run_manifest("examples/prime_sweep_scale")
IO.puts("Job submitted: #{job_id}")
Await completion with a timeout:
case MirrorNeuron.run_manifest("examples/research_flow", await: true, timeout: 60_000) do
  {:ok, job_id, job} ->
    IO.puts("Job #{job_id} finished with status: #{job["status"]}")

  {:error, reason} ->
    IO.puts("Job failed: #{inspect(reason)}")
end
Pass a pre-validated bundle:
{:ok, bundle} = MirrorNeuron.validate_manifest("examples/research_flow")

# Inspect or modify bundle here if needed

{:ok, job_id} = MirrorNeuron.run_manifest(nil, job_bundle: bundle)
When running on a control node, run_manifest/2 automatically routes the call to an available runtime node. You do not need to manage node selection manually.

MirrorNeuron.wait_for_job/2

Blocks the caller until a job reaches a terminal state. Use this when you submitted a job with await: false and want to synchronize on its completion later in your workflow.
MirrorNeuron.wait_for_job(job_id, timeout \\ :infinity)
job_id
String.t()
required
The job identifier returned by run_manifest/2.
timeout
integer | :infinity
default:":infinity"
Maximum time in milliseconds to wait. Pass :infinity to block without a deadline.

Terminal states

wait_for_job/2 returns as soon as the job enters any of the following states:
  • completed — the job finished successfully
  • failed — the job encountered an unrecoverable error
  • cancelled — the job was cancelled by an operator or control call
If a job is already in a terminal state when you call wait_for_job/2, the function reads the persisted record from Redis and returns immediately without polling.

Return values

{:ok, job_map}
job_map
map
The final persisted job record. Key fields include:

Example

{:ok, job_id} = MirrorNeuron.run_manifest("examples/prime_sweep_scale")

# Do other work here...

case MirrorNeuron.wait_for_job(job_id, 120_000) do
  {:ok, job} ->
    IO.puts("Completed with status: #{job["status"]}")
    IO.inspect(job["result"])

  {:error, reason} ->
    IO.puts("Wait failed: #{inspect(reason)}")
end