---
title: Guides
description: Task-shaped walkthroughs - get images in, label them, reshape the set, train a model, and serve it.
section: Guides
order: 0
---
Each guide answers one question end to end. In order, they follow the path a dataset
actually takes.

| Guide | The question it answers |
| --- | --- |
| [Upload a directory of images](/docs/guides/upload.md) | How do I get a directory of images in? |
| [SAM3 auto-annotation](/docs/sam3-auto-annotation.md) | How do I label them without drawing every shape? |
| [Tile and augment](/docs/guides/augment.md) | How do I reshape the set before training? |
| [Train a model](/docs/guides/train.md) | How do I get weights out? |
| [Deployments](/docs/deployments.md) | How do I serve the model behind a URL? |
| [Export & conversion](/docs/export-conversion.md) | How do I get my data out, or someone else's in? |
| [Local inference](/docs/local-inference.md) | How do I run a trained model on my own machine? |

For a single REST call - one image, one export, one training run - go to the
[API reference](/docs/api-reference.md) instead.

## Methods that chain several calls

Some steps have a one-call method that does the whole thing: walking a directory, polling
a job, waiting on an export. Each lives on the resource that owns its noun, so everything
hangs off the `client` you already have.

```python
from pictograph import Client, TrainingRun

client = Client()

client.images.upload_from_directory(
    dataset_name="road-signs",
    directory="./road_signs",
)
client.auto_annotate.dataset(
    dataset_name="road-signs",
    classes=[("stop_sign", "bbox"), ("yield", "polygon")],
)
client.exports.create(
    dataset_name="road-signs",
    name="road-signs-v1",
    format="pictograph",
    include_images=True,
    wait=True,
)
run: TrainingRun = client.training.create(
    dataset_name="road-signs",
    export_name="road-signs-v1",
    pipeline_type="yolox",
    name="road-signs-detector",
)
print("model:", run.model_id or run.status)
```

| Method | What it chains | Guide | Source |
| --- | --- | --- | --- |
| `client.images.upload_from_directory` | walk directory → bulk upload | [Upload](/docs/guides/upload.md) | [`images.py`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/images.py) |
| `client.auto_annotate.dataset` | list images → SAM3 batch → save | [SAM3](/docs/sam3-auto-annotation.md) | [`auto_annotate.py`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/auto_annotate.py) |
| `client.images.tile` | download → slice into a grid → upload tiles | [Tile and augment](/docs/guides/augment.md) | [`images.py`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/images.py) |
| `client.images.augment` | download → augment → upload variants | [Tile and augment](/docs/guides/augment.md) | [`images.py`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/images.py) |
| `client.training.create` | train a completed export | [Train](/docs/guides/train.md) | [`training.py`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/training.py) |

`client.annotations.import_coco`, `client.annotations.import_pascal_voc` and
`client.annotations.import_yolo` bring existing labels into a dataset - see
[Export and conversion](/docs/export-conversion.md).

Everything they do is also reachable one call at a time on the same resources; these just
save you the loop. "Workflow" means one thing only: the composable
[node-graph resource](/docs/api-reference/workflows.md) (`client.workflows`).

## What they return

These methods do not raise on partial failure. Each returns a dataclass with counts, a
`success` flag and a `failures` list, because agents and CI jobs need to act on a partial
outcome rather than unwind on the first 4xx. The report types are top-level exports
(`from pictograph import UploadReport`).

```python
report = client.images.upload_from_directory(
    dataset_name="road-signs",
    directory="./road_signs",
)
if report.success:
    print(f"Uploaded {report.images_uploaded}")
else:
    for failure in report.failures:
        print(failure.path, failure.reason)
```

`success` means zero failures **and** at least one item processed, so an empty run
reports `success=False` rather than a silent pass.

Exceptions are still raised for unrecoverable errors before any work happens -
`NotFoundError` on a missing dataset, `ValidationError` on a bad pipeline name. See
[Error handling](/docs/error-handling.md).