> ## Documentation Index
> Fetch the complete documentation index at: https://docs.evolvingmachines.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload a job

> Bring a job you ran elsewhere onto the platform as a finished job.

A job you ran elsewhere, in the Harbor job layout, uploads as a terminal job. Its trials, traces and rewards become a job you read like any other.

```bash theme={null}
evolve upload ./job-2026-08-27__12-00-00 -d terminal-bench-4@4.0
```

`upload` takes the job directory, or its `.tar.gz`. With `--from <url>` it takes instead a public https URL of the archive, which the server fetches itself. `-d name[@version]` links the uploaded trials to a published dataset version by task name. The command follows the import until the job exists.

`--no-wait` returns at once with the import id.

```bash theme={null}
evolve job imports --status RUNNING
evolve job import <import-id> --watch
```

`job imports` lists your uploads, newest first. `job import --watch` re-attaches to one and follows it to the job, or to its typed failure. A large upload resumes after a dropped connection, and its import id is available before the transfer ends.

## What lands

The trials' facts, never a re-judgment: a rewarded trial arrives `SCORED` with its rewards untouched, a trial with no rewards arrives `INDETERMINATE`, and an errored trial keeps its exception. The trajectory, the agent's logs and home folder, and the verifier log land where a native trial's do, so every trace and artifact read works unchanged. Prior `analysis.json`, `lock.json`, `artifacts/` and `steps/` content are not imported.

The ingested job carries `upload`: the archive's own `original_job_id` and `original_job_name`, `uploaded_at`, the uploader's `reported_totals`, and `task_links`. It is null on every job this platform ran. Resume, retry and regrade refuse an uploaded job with `job_uploaded`; analyze works on it unchanged.

An uploaded job never claims an execution: its `sandbox_provider` is null, the CLI prints `ported`, and the metered spend and token fields stay null. The archive's own figures ride `trial.upload.reported_agent_result` and `upload.reported_totals`, and `job show` prints them as `reported $X.XX (N/M trials reporting)`.

## Task linkage

Every trial's `lock.json` names its task by a content hash, and every task the platform imports carries the same hash, so an uploaded job links to the dataset it ran against by itself. A linked trial's analyses run with the task folder; an unlinked trial's run without it, and the record says why: `hash_mismatch`, `task_not_in_dataset`, `no_task_digest`, `no_hash_match`, `no_dataset_named` or `dataset_ambiguous`. A name alone never links.

`-d` is the override: it links by task name to that one version, whatever the hashes say, and settles an ambiguous hash. A hint you cannot use fails the import. The outcome is printed by the upload follow, repeated by `evolve analyze` before it spends, and recorded on the job's `upload.task_links`, the import's `task_links` and each trial's `upload.link`.

## Bounds and duplicates

The only size limit is the archive ceiling published as `limits.uploads.job_archive_bytes` (`upload_too_large` past it). A trial with a single file over 5 GiB, or a trajectory too large to parse, is skipped instead of failing the job: the import lists it under `skipped_trials` as `trial_too_large`, and `job import` prints one line per skipped trial. A trial whose `result.json` cannot be read fails the whole import with `invalid_trial`.

Re-uploading a job you already uploaded fails with `job_already_uploaded`, naming the existing job; delete it, then upload again. Another user uploading the same archive gets their own copy.

<Card title="upload reference" icon="terminal" href="/cli-reference/upload">
  Every flag of `evolve upload`.
</Card>
