How the job system works
Understand what a job is, how the queue matches work to workers, and how Programs, pipelines and files fit together.
No setup required. Read this overview first or jump straight to running a script.
A job is a self-contained run of Python code together with its exact inputs, dependency lock, logs, and output files. You can run a job on your laptop in seconds or submit the exact same job to a queue of remote CPU, GPU, or Ray workers.
1. What a job looks like
Every job runs inside a fresh, isolated working directory (attempt directory) and can be written in one of two ways:
A standalone Python script
For quick experiments or one-off scripts, write a standard .py file that reads command-line arguments or staged input files and writes any files you want to keep into results/:
A typed Python function (Program)
When you want a calculation to be reusable across your team or chained into larger workflows, wrap a Python function with strict Pydantic input and output models and publish it as a versioned Program (such as example.double@1):
Whether you submit a script or a published Program, every job captures and produces the same four things:
2. How the queuing system works
When you run ct-cli run, your script executes immediately on your machine with no server involved. When you run ct-cli submit (or client.submit(...) in Python), your job goes through four steps:
- Freeze and admit: The CLI or Python SDK freezes your code and dependency lock, uploads your declared
--inputfiles directly to private S3-compatible storage using short-lived presigned URLs, and registers the job with the backend. You immediately receive aJOB_UUID—you can close your laptop and the job will still run. - Queue and match capacity: The backend hands the job to the scheduler (Hatchet). Your job waits in the queue until an enabled worker matching your requested pool (for example
cpuorgpu), platform (such aslinux-x86_64-py3.13-cpu), and hardware resources (--cpus,--gpus,--memory) has free capacity. - Execute in a clean workspace: The worker claims the job from the queue, creates a fresh temporary directory for that attempt, prepares the Python environment (see Choose code and dependencies), stages your input files, and starts your Python process.
- Collect outputs and clean up: When the Python process exits, the worker compresses and uploads every file matching
results/**along with execution logs, reports the validated return value back to the server, and deletes the temporary scratch directory. Temporary files outsideresults/are not uploaded.
3. Job states and lifecycle
You can check any job from any terminal using its UUID:
A job moves through these states:
Important: A
succeededjob state means the computation finished without crashing. In scientific workflows, process completion alone never establishes that a transition state or reaction pathway is physically valid—scientific acceptance happens in a dedicated verification step.
4. How jobs compose into pipelines and Flows
You never need a separate workflow engine or custom queue for multi-step science. Complex workflows are built by connecting ordinary jobs in the same queue:
Ready to try it hands-on? Continue to Run your first job to execute a script locally and submit it to a worker.