> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo-platform/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo-platform/_mcp/server.

# Run an Anonymizer Job

This tutorial walks through the `anonymizer.run` job: defining a run spec, submitting it to the NeMo Platform Jobs worker, and loading the parquet artifacts it produces.

For detection, rewrite, and replacement strategy details, see the [open-source library documentation](https://github.com/NVIDIA-NeMo/Anonymizer/tree/main/docs).

## Prerequisites

Complete the [tutorials prerequisites](/documentation/anonymize-data/tutorials#prerequisites), which cover:

* A running NeMo Platform cluster with the `nemo anonymizer` CLI available (see [Setup](/documentation/get-started)).
* An inference provider configured (default examples use `nvidia-build`).
* A fileset named `anonymizer-inputs` with `anonymizer-input.csv` uploaded.

## What `run` Does

`anonymizer.run` executes the full Anonymizer pipeline on every record of an input file and writes the output as job artifacts.

The CLI exposes one run command:

| Command               | Where it runs             | Local paths | `model_configs` required | Artifacts                                                                      |
| --------------------- | ------------------------- | ----------- | ------------------------ | ------------------------------------------------------------------------------ |
| `nemo anonymizer run` | NeMo Platform Jobs worker | Rejected    | Required                 | Stored in NeMo Platform job artifact storage; pull with `download_artifacts()` |

Job artifacts (under the `artifacts/` directory):

| File                  | Description                                                         |
| --------------------- | ------------------------------------------------------------------- |
| `dataset.parquet`     | User-facing anonymized dataframe (replace/rewrite output).          |
| `trace.parquet`       | Internal trace dataframe with detection details.                    |
| `metadata.json`       | Run metadata (includes the original text column name).              |
| `failed_records.json` | Per-record failures with reasons. Only written when records failed. |

## Step 1: Build an `AnonymizerRequest`

`AnonymizerRequest` contains the execution fields shared by preview and run (`config`, `data`, `model_configs`, and `selected_models`). A run processes the full input file, so it does not include `num_records`:

```python
import os
from anonymizer.config.anonymizer_config import AnonymizerConfig
from anonymizer.config.replace_strategies import Redact
from data_designer.config import ModelConfig
from nemo_anonymizer_plugin.app.input import AnonymizerInputSpec
from nemo_anonymizer_plugin.app.task_config import AnonymizerRequest

WORKSPACE = os.environ.get("NMP_WORKSPACE", "default")
MODEL_PROVIDER = os.environ.get("NMP_ANON_PROVIDER", "nvidia-build")

config = AnonymizerConfig(
    replace=Redact(format_template="[REDACTED_{label}]"),
)

model_configs = [
    ModelConfig(alias="gliner-pii-detector", provider=MODEL_PROVIDER, model="nvidia/gliner-pii"),
    ModelConfig(alias="gpt-oss-120b", provider=MODEL_PROVIDER, model="openai/gpt-oss-120b"),
    ModelConfig(alias="nemotron-30b-thinking", provider=MODEL_PROVIDER, model="nvidia/nemotron-3-nano-30b-a3b"),
]

request = AnonymizerRequest(
    config=config,
    data=AnonymizerInputSpec(
        source=f"fileset://{WORKSPACE}/anonymizer-inputs#anonymizer-input.csv",
        text_column="biography",
        id_column="id",
    ),
    model_configs=model_configs,
)
```

## Step 2: Write the Spec to YAML

The CLI run command reads a YAML spec file. Serialize the `AnonymizerRequest` directly:

```python
import yaml
from pathlib import Path

spec_path = Path("/tmp/anonymizer-run.yaml")
spec_path.write_text(yaml.safe_dump(request.model_dump(mode="json", exclude_none=True)))
```

## Step 3: Run the Job

Submit the spec to the NeMo Platform Jobs worker:

```bash
nemo anonymizer run \
  --spec-file /tmp/anonymizer-run.yaml \
  --workspace "${NMP_WORKSPACE:-default}" \
  --base-url "${NMP_BASE_URL:-http://localhost:8080}"
```

The command prints the assigned job name. You need that name to poll status and download artifacts in Step 4.

The SDK equivalent is `sdk.anonymizer.run(request)`. It posts the request to the plugin's `/jobs/run` endpoint and returns an `AnonymizerJobResource`:

```python
import os
from nemo_platform import NeMoPlatform

sdk = NeMoPlatform(
    base_url=os.environ.get("NMP_BASE_URL", "http://localhost:8080"),
    workspace=WORKSPACE,
)
job = sdk.anonymizer.run(request)
```

The run path rejects local file paths in `data.source` — use a fileset reference (`<fileset>#<path>`) or `http(s)` URL. It also requires explicit `model_configs` referencing Inference Gateway providers.

## Step 4: Get Results

Track the platform job first. The job is ready for artifact download when its status is `completed`:

```bash
# Replace with the job name printed by `nemo anonymizer run`.
nemo jobs get-status <job-name> --workspace "${NMP_WORKSPACE:-default}"
nemo jobs get-logs <job-name> --workspace "${NMP_WORKSPACE:-default}"
```

To download from the CLI, fetch the `artifacts` result and extract it:

```bash
nemo jobs results download artifacts \
  --job <job-name> \
  --workspace "${NMP_WORKSPACE:-default}" \
  --output-file /tmp/anonymizer-artifacts.tar.gz

mkdir -p /tmp/anonymizer-artifacts
tar -xzf /tmp/anonymizer-artifacts.tar.gz -C /tmp/anonymizer-artifacts
ls /tmp/anonymizer-artifacts/artifacts
```

Then point `AnonymizerJobResults` at the extracted `artifacts` directory:

```python
from pathlib import Path

from nemo_anonymizer_plugin.sdk.job_results import AnonymizerJobResults

results = AnonymizerJobResults(Path("/tmp/anonymizer-artifacts/artifacts"))

dataset = results.load_dataset()
trace   = results.load_trace()
failed  = results.load_failed_records()
```

If you used the SDK, use the `AnonymizerJobResource` methods directly. `get_job_status()` reads the current status, `check_if_complete()` tests whether artifacts are ready, `wait_until_done()` blocks until a terminal state, and `download_artifacts()` downloads and extracts the result:

```python
job = sdk.anonymizer.run(request)

status = job.get_job_status()
is_done = job.check_if_complete()

job.wait_until_done()
results = job.download_artifacts()

dataset = results.load_dataset()
trace   = results.load_trace()
failed  = results.load_failed_records()
```

`AnonymizerJobResults` exposes `load_dataset()`, `load_trace()`, `load_failed_records()`, and `display_record()` over the same underlying files. See [SDK Resources](/documentation/anonymize-data/sdk-resources#anonymizerjobresults).

## How the Job Compiles

For each request, the plugin:

1. Validates the Anonymizer library `AnonymizerConfig`.
2. Validates the input source (rejects local paths; checks fileset refs).
3. Validates that `selected_models` overrides also have `model_configs`.
4. Resolves `model_configs` providers through the Inference Gateway.
5. Renders a unified `model_configs` YAML body for the library.
6. Stores the resolved providers and YAML in the internal `AnonymizerStepConfig` consumed by the Jobs worker.

Provider endpoints are re-resolved at runtime so the job uses the in-cluster Inference Gateway address rather than the address captured at submission time.

## Next Steps

* Iterate faster with [preview](/documentation/anonymize-data/tutorials/preview-a-config) before scaling to a full job.
* Refer to [SDK Resources](/documentation/anonymize-data/sdk-resources) for `AnonymizerJobResource` and `AnonymizerJobResults` details.
* Replacement strategy parameters and rewrite mode are documented in the [library docs](https://github.com/NVIDIA-NeMo/Anonymizer/tree/main/docs).