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

# API Reference

> Complete reference for the Chamber Python SDK

## ChamberClient

The main class for interacting with the Chamber API.

### Initialization

```python theme={null}
from chamber_sdk import ChamberClient

# From environment variable (CHAMBER_TOKEN)
client = ChamberClient()

# From CLI config (~/.chamber/token.json)
client = ChamberClient.from_config()

# Direct token
client = ChamberClient(
    token="ch.your-api-token",
    organization_id="org-123",  # Optional: for multi-org users
    api_url="https://custom.api.example.com/v1",  # Optional: override endpoint
    timeout=60  # Optional: request timeout in seconds
)
```

**Default API URL:** `https://api.usechamber.io/v1`

***

## Auto-Containerize & Run

### run()

Auto-containerize and submit a GPU workload in one call. See the [full guide](/sdk/python/run) for detailed documentation.

```python theme={null}
# Configure registries once
ChamberClient.add_registry("prod", "us-east1-docker.pkg.dev/my-project/prod", set_default=True)
ChamberClient.add_registry("dev", "us-east1-docker.pkg.dev/my-project/dev")

# Submit using default registry
job = client.run("./my-project", gpus=4, team="ml-research")

# Submit to specific registry by name
job = client.run("./my-project", gpus=4, team="ml-research", registry="dev")

# Full URLs still work
job = client.run("./my-project", registry="123456.dkr.ecr.us-east-1.amazonaws.com", team="ml-research")

# Dry run (preview without executing)
result = client.run("./my-project", dry_run=True)
print(result.dockerfile)
print(result.manifest)
```

<Info>
  Requires installation with `pip install chamber-sdk[run]`
</Info>

**Key Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `directory` | str | Path to project directory (required) |
| `gpus` | int | Number of GPUs (default: 1) |
| `gpu_type` | str | GPU type (default: "H100") |
| `team` | str | Team ID (required for submission) |
| `registry` | str | Registry name (e.g., "prod") or URL. Uses default if not specified. |
| `distributed` | str | "auto", "ray", "deepspeed", or "none" |
| `dry_run` | bool | Preview without executing |
| `wait` | bool | Block until workload completes |
| `on_progress` | callable | Progress callback(stage, message) |

**Returns:** `Workload` object (or `DryRunResult` if `dry_run=True`)

See [Auto-Containerize & Run](/sdk/python/run) for the complete parameter reference.

### Registry Management

Static methods for managing container registries. Configuration is persisted to `~/.chamber/config.json`.

#### list\_registries()

List all configured registries.

```python theme={null}
registries = ChamberClient.list_registries()
# {'prod': 'us-east1-docker.pkg.dev/my-project/prod', 'dev': '...'}
```

**Returns:** `dict[str, str]` mapping names to URLs

#### add\_registry()

Add or update a named registry.

```python theme={null}
ChamberClient.add_registry(
    "prod",
    "us-east1-docker.pkg.dev/my-project/prod",
    set_default=True  # Optional: also set as default
)
```

**Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `name` | str | Registry name (e.g., "prod", "dev") |
| `url` | str | Registry URL |
| `set_default` | bool | If True, also set as default (default: False) |

#### set\_default\_registry()

Set the default registry by name.

```python theme={null}
ChamberClient.set_default_registry("dev")
```

**Raises:** `ValueError` if the registry name doesn't exist

#### get\_default\_registry()

Get the current default registry.

```python theme={null}
name, url = ChamberClient.get_default_registry()
# ('prod', 'us-east1-docker.pkg.dev/my-project/prod')
```

**Returns:** `tuple[str, str]` of (name, url) or `None` if not configured

***

## Workload Submission

### submit\_job()

Submit a new GPU workload.

```python theme={null}
job = client.submit_job(
    name="training-job",
    initiative_id="team-id",
    gpu_type="H100",
    requested_gpus=8,
    job_class=JobClass.RESERVED,
    priority=50,
    tags={"experiment": "v1", "owner": "ml-team"},
    external_id="my-tracking-id"
)
```

**Parameters:**

| Parameter | Type | Required | Description |
| - | - | - | - |
| `name` | str | Yes | Human-readable workload name (1-255 chars) |
| `initiative_id` | str | Yes | Team ID |
| `gpu_type` | str | Yes | GPU model (e.g., "H100", "A100") |
| `requested_gpus` | int/float | No | Number of GPUs (optional if using template) |
| `job_class` | JobClass | No | RESERVED or ELASTIC (default: RESERVED) |
| `priority` | int | No | 0-100 (higher = more important) |
| `tags` | dict | No | Key-value pairs for tagging |
| `metadata` | dict | No | Custom metadata dictionary |
| `external_id` | str | No | Your own tracking ID (max 255 chars) |
| `k8s_manifest` | str | No | Custom Kubernetes manifest YAML (max 65536 chars) |
| `template_id` | str | No | Template ID to use for configuration |
| `allocation_id` | str | No | Force specific capacity allocation |

**Returns:** `Workload` object

### Distributed Training

For multi-node distributed training:

```python theme={null}
job = client.submit_job(
    name="distributed-training",
    initiative_id="team-id",
    gpu_type="H100",
    requested_gpus=32,
    gpus_per_pod=8,
    requested_pods=4,
    scaling_mode=ScalingMode.GANG,  # All-or-nothing scheduling
    distribution_mode="auto"
)
```

**Additional Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `gpus_per_pod` | int | GPUs per pod |
| `requested_pods` | int | Number of pods |
| `scaling_mode` | ScalingMode | GANG or ELASTIC |
| `min_pods` | int | Minimum pods for elastic scaling |
| `distribution_mode` | str | "auto" or "manual" |

***

## Workload Management

### get\_workload()

Retrieve details of a specific workload.

```python theme={null}
job = client.get_workload("workload-id")
print(f"Status: {job.status}")
print(f"GPUs: {job.requested_gpus}")
```

**Returns:** `Workload` object

### list\_workloads()

List workloads with optional filters.

```python theme={null}
response = client.list_workloads(
    status=JobStatus.RUNNING,
    initiative_id="team-id",
    submitted_by="user-123",
    limit=50
)

for job in response.items:
    print(f"{job.name}: {job.status}")
```

**Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `status` | JobStatus | Filter by status |
| `initiative_id` | str | Filter by team |
| `submitted_by` | str | Filter by user |
| `is_managed` | bool | True for Chamber workloads, False for discovered |
| `submitted_after` | str | ISO8601 datetime filter |
| `submitted_before` | str | ISO8601 datetime filter |
| `sort_order` | str | "asc" or "desc" |
| `limit` | int | Max results (1-100, default: 20) |
| `next_token` | str | Pagination cursor |

**Returns:** `PaginatedResponse` with `items`, `next_token`, `total_count`

### iter\_workloads()

Iterate through all workloads with automatic pagination.

```python theme={null}
for job in client.iter_workloads(status=JobStatus.COMPLETED):
    print(f"{job.name}: {job.requested_gpus} GPUs")
```

### cancel\_workload()

Cancel a running or pending workload.

```python theme={null}
cancelled_job = client.cancel_workload("workload-id")
print(f"Status: {cancelled_job.status}")  # CANCELLED
```

**Returns:** `Workload` object with updated status

### search\_workloads()

Search workloads with advanced filtering.

```python theme={null}
results = client.search_workloads(
    status=["RUNNING", "PENDING"],
    gpu_type=["H100"],
    priority_min=50,
    submitted_from="2024-01-01T00:00:00Z",
    query="training",
    sort_by="submitted_at",
    sort_order="desc",
    page_size=25
)

print(f"Found {results.total_count} workloads")
for job in results.items:
    print(f"{job.name}: {job.status}")

# Paginate through results
if results.has_more:
    next_page = client.search_workloads(cursor=results.next_cursor)
```

**Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `status` | list\[str] | Filter by status(es) |
| `job_class` | list\[str] | Filter by workload class(es) |
| `gpu_type` | list\[str] | Filter by GPU type(s) |
| `initiative_id` | list\[str] | Filter by team ID(s) |
| `submitted_by` | list\[str] | Filter by user ID(s) |
| `priority_min` | int | Minimum priority |
| `priority_max` | int | Maximum priority |
| `requested_gpus_min` | int | Minimum GPU count |
| `requested_gpus_max` | int | Maximum GPU count |
| `submitted_from` | str | Start date (ISO8601) |
| `submitted_to` | str | End date (ISO8601) |
| `query` | str | Full-text search query |
| `sort_by` | str | Sort field (default: submitted\_at) |
| `sort_order` | str | "asc" or "desc" (default: desc) |
| `page_size` | int | Results per page (1-100, default: 25) |
| `cursor` | str | Pagination cursor |

**Returns:** `WorkloadSearchResult` with `items`, `total_count`, `has_more`, `next_cursor`

### get\_workload\_aggregations()

Get workload counts grouped by a dimension.

```python theme={null}
agg = client.get_workload_aggregations(
    dimension="status",
    initiative_id=["team-ml"]
)

print(f"Total: {agg.total}")
for bucket in agg.buckets:
    print(f"  {bucket.key}: {bucket.count}")
```

**Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `dimension` | str | Group by: status, job\_class, gpu\_type, initiative\_id, submitted\_by, capacity\_pool\_id |
| `status` | list\[str] | Filter by status(es) |
| `job_class` | list\[str] | Filter by workload class(es) |
| `initiative_id` | list\[str] | Filter by team ID(s) |
| `submitted_from` | str | Start date (ISO8601) |
| `submitted_to` | str | End date (ISO8601) |

**Returns:** `AggregationResult` with `dimension`, `buckets`, `total`

### wait\_for\_completion()

Block until a workload reaches a terminal status.

```python theme={null}
result = client.wait_for_completion(
    workload_id="job-id",
    poll_interval=30,  # Seconds between checks
    timeout=3600       # Max wait time in seconds
)
```

**Returns:** `Workload` object with final status

***

## Metrics and Statistics

### get\_workload\_metrics()

Retrieve GPU metrics for a specific workload.

```python theme={null}
metrics = client.get_workload_metrics(
    "workload-id",
    time_range="job_lifetime"
)

print(f"GPU Utilization: {metrics.gpu_utilization.avg:.1f}%")
print(f"Memory: {metrics.memory_utilization.avg:.1f}%")
print(f"Temperature: {metrics.temperature.avg:.1f}C")
print(f"Power: {metrics.power_usage.avg:.1f} W")
```

**Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `workload_id` | str | The workload ID |
| `time_range` | str | last\_1h, last\_6h, last\_24h, or job\_lifetime |
| `metrics` | list\[str] | Specific metrics to retrieve |

**Returns:** `WorkloadMetrics` with `gpu_utilization`, `memory_utilization`, `temperature`, `power_usage`

### get\_global\_metrics()

Get aggregated metrics for your organization.

```python theme={null}
metrics = client.get_global_metrics(
    time_range="last_24h",
    initiative_id="team-ml"
)

print(f"Active workloads: {metrics.active_workloads}")
print(f"Total GPU hours: {metrics.total_gpu_hours}")
print(f"Avg GPU utilization: {metrics.gpu_utilization.avg:.1f}%")
```

**Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `time_range` | str | last\_1h, last\_6h, last\_24h, last\_7d, last\_30d |
| `initiative_id` | str | Filter by team |
| `cluster_id` | str | Filter by cluster |
| `group_by` | str | Group by field (e.g., "initiative\_id") |

**Returns:** `GlobalMetrics` with aggregated data

### get\_batch\_workload\_metrics()

Get metrics for multiple workloads at once.

```python theme={null}
data = client.get_batch_workload_metrics(
    status=["RUNNING"],
    time_range="last_24h",
    sort_by="gpu_utilization",
    limit=10
)
```

**Returns:** Dict with workload metrics ranked by the specified metric

### get\_workload\_stats()

Get aggregated workload statistics.

```python theme={null}
stats = client.get_workload_stats(
    time_range="last_7_days",
    initiative_id="team-id"
)

print(f"Total workloads: {stats.total}")
for status, count in stats.by_status.items():
    print(f"  {status}: {count}")
```

**Returns:** `WorkloadStats` with `total`, `by_status`, `by_job_class`

***

## Teams

### list\_teams()

List all teams accessible to the current user.

```python theme={null}
teams = client.list_teams()

for team in teams:
    print(f"{team.name} ({team.id})")
```

**Returns:** List of `Team` objects

### create\_team()

Create a new team.

```python theme={null}
team = client.create_team(
    name="ML Research",
    description="Machine learning research team",
    tags={"department": "engineering"}
)

print(f"Created team: {team.id}")
```

**Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `name` | str | Team name (1-255 chars) |
| `description` | str | Team description (max 1000 chars) |
| `parent_id` | str | Parent team ID for sub-teams |
| `tags` | dict | Key-value pairs for tagging |

**Returns:** `Team` object

### get\_team()

Get details of a specific team.

```python theme={null}
team = client.get_team("team-id")
print(f"Team: {team.name}")
print(f"Description: {team.description}")
```

**Returns:** `Team` object

***

## Templates

### list\_templates()

List available workload templates.

```python theme={null}
templates = client.list_templates(
    scope="ORGANIZATION",
    include_system=True
)

for template in templates:
    print(f"{template.name}: {template.gpu_type}")
```

**Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `name` | str | Filter by name (partial match) |
| `scope` | str | PERSONAL, PROJECT, or ORGANIZATION |
| `include_system` | bool | Include system templates (default: True) |

**Returns:** List of `Template` objects

### get\_template()

Get details of a specific template.

```python theme={null}
template = client.get_template("template-id")
print(f"Template: {template.name}")
print(f"GPU Type: {template.gpu_type}")
print(f"GPUs: {template.requested_gpus}")
```

**Returns:** `Template` object

***

## Allocations

### list\_allocations()

List capacity allocations for a team.

```python theme={null}
allocations = client.list_allocations(initiative_id="team-id")

for alloc in allocations:
    print(f"{alloc.id}: {alloc.allocated_instances} instances ({alloc.status})")
```

**Returns:** List of `Allocation` objects

### create\_allocation()

Create a new capacity allocation.

```python theme={null}
allocation = client.create_allocation(
    initiative_id="team-id",
    reservation_id="reservation-123",
    allocated_instances=4
)

print(f"Allocated: {allocation.id}")
```

**Returns:** `Allocation` object

### get\_allocation()

Get details of a specific allocation.

```python theme={null}
allocation = client.get_allocation("allocation-id")
print(f"Status: {allocation.status}")
print(f"Instances: {allocation.allocated_instances}")
```

**Returns:** `Allocation` object

***

## Capacity

### get\_capacity()

Check available GPU capacity and budget.

```python theme={null}
capacity = client.get_capacity()

# Budget info
print(f"Allocated: {capacity.budget.allocated} GPU-hours")
print(f"Used: {capacity.budget.used} GPU-hours")
print(f"Available: {capacity.budget.available} GPU-hours")

# Capacity pools
for pool in capacity.pools:
    print(f"{pool.name} ({pool.gpu_type}):")
    print(f"  Available: {pool.available_gpus}/{pool.total_gpus} GPUs")
```

### health()

Check API health status.

```python theme={null}
health = client.health()
print(f"Status: {health.status}")
print(f"Version: {health.version}")
```

***

## Enums

### JobStatus

```python theme={null}
from chamber_sdk import JobStatus

JobStatus.PENDING      # Submitted, awaiting scheduling
JobStatus.QUEUED       # Scheduled, waiting for resources
JobStatus.STARTING     # Resources allocated, starting
JobStatus.RUNNING      # Currently executing
JobStatus.COMPLETED    # Finished successfully
JobStatus.FAILED       # Workload failed
JobStatus.PREEMPTED    # Preempted (elastic jobs)
JobStatus.CANCELLED    # Cancelled by user
```

### JobClass

```python theme={null}
from chamber_sdk import JobClass

JobClass.RESERVED   # Guaranteed capacity, non-preemptible
JobClass.ELASTIC    # Uses idle capacity, can be preempted
JobClass.DISCOVERED # External workload discovered by Chamber
```

### ScalingMode

```python theme={null}
from chamber_sdk import ScalingMode

ScalingMode.GANG     # All-or-nothing scheduling
ScalingMode.ELASTIC  # Can scale between min/max pods
```

### AllocationStatus

```python theme={null}
from chamber_sdk import AllocationStatus

AllocationStatus.ACTIVE    # Currently active
AllocationStatus.RELEASED  # Released by user
AllocationStatus.EXPIRED   # Expired
```

***

## Data Models

### Workload

| Field | Type | Description |
| - | - | - |
| `id` | str | Unique workload ID |
| `name` | str | Workload name |
| `status` | JobStatus | Current status |
| `requested_gpus` | float | Number of GPUs |
| `gpu_type` | str | GPU model |
| `job_class` | JobClass | RESERVED, ELASTIC, or DISCOVERED |
| `priority` | int | Priority level |
| `tags` | dict | Key-value tags |
| `metadata` | dict | Custom metadata |
| `template_id` | str | Template ID if used |
| `initiative_id` | str | Team ID |
| `submitted_by` | str | User ID |
| `submitted_at` | datetime | Submission timestamp |
| `started_at` | datetime | Start timestamp |
| `completed_at` | datetime | Completion timestamp |
| `failure_reason` | str | Failure message (if failed) |

### Team

| Field | Type | Description |
| - | - | - |
| `id` | str | Team ID |
| `name` | str | Team name |
| `description` | str | Team description |
| `parent_id` | str | Parent team ID |
| `tags` | dict | Key-value tags |
| `created_at` | datetime | Creation timestamp |

### Template

| Field | Type | Description |
| - | - | - |
| `id` | str | Template ID |
| `name` | str | Template name |
| `scope` | str | PERSONAL, PROJECT, or ORGANIZATION |
| `description` | str | Template description |
| `gpu_type` | str | GPU model |
| `requested_gpus` | int | Number of GPUs |
| `k8s_manifest` | str | Kubernetes manifest |
| `configuration` | dict | Additional configuration |

### Allocation

| Field | Type | Description |
| - | - | - |
| `id` | str | Allocation ID |
| `initiative_id` | str | Team ID |
| `reservation_id` | str | Reservation ID |
| `allocated_instances` | int | Number of instances |
| `status` | AllocationStatus | Allocation status |
| `created_at` | datetime | Creation timestamp |

***

## Exceptions

All exceptions inherit from `ChamberError`:

```python theme={null}
from chamber_sdk import (
    ChamberError,
    AuthenticationError,
    AuthorizationError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    ServerError,
    DockerError,  # For run() errors
)
from chamber_sdk.run import RegistryAuthError  # Specific registry auth failures

try:
    job = client.get_workload("invalid-id")
except NotFoundError:
    print("Workload not found")
except AuthenticationError:
    print("Invalid or expired token")
except RateLimitError as e:
    print(f"Rate limited: {e.message}")
except ChamberError as e:
    print(f"API error: {e}")
```

| Exception | HTTP Code | Description |
| - | - | - |
| `AuthenticationError` | 401 | Invalid or expired token |
| `AuthorizationError` | 403 | Insufficient permissions |
| `NotFoundError` | 404 | Resource not found |
| `ValidationError` | 400 | Invalid request parameters |
| `RateLimitError` | 429 | Rate limit exceeded |
| `ServerError` | 5xx | Server-side error |
| `DockerError` | N/A | Docker build/push error (for `run()`) |
| `RegistryAuthError` | N/A | Registry authentication/authorization failure (subclass of `DockerError`) |

### Handling `run()` Errors

```python theme={null}
from chamber_sdk import ChamberClient, DockerError
from chamber_sdk.run import RegistryAuthError

try:
    job = client.run("./my-project", registry="...", team="...")
except RegistryAuthError as e:
    # Registry authentication failed (401/403 from registry)
    # e.registry contains the registry URL
    # e.detail contains the error details
    print(f"Registry auth failed for {e.registry}: {e.detail}")
except DockerError as e:
    # Docker not installed, daemon not running, build failed, or push failed
    print(f"Docker error: {e}")
except FileNotFoundError as e:
    # No Python entrypoint found in project
    print(f"Project error: {e}")
except ValueError as e:
    # Missing required parameters (registry, team)
    print(f"Configuration error: {e}")
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.