Metadata-Version: 2.4
Name: trajectory-sdk
Version: 0.10.0
Summary: Generated Trajectory API client and high-level workflows
Project-URL: Documentation, https://docs.trajectory.ai
Project-URL: Cookbook, https://github.com/Trajectorylabs/trajectory-cookbook
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx2>=2.13.1
Requires-Dist: pathspec>=0.12
Requires-Dist: pydantic>=2.0
Requires-Dist: tqdm>=4.67
Dynamic: license-file

# Trajectory SDK

Generated Python client for the Trajectory API, with high-level workflows for uploading
trajectories, telemetry, and runtime-backed specs (benchmarks).

## Install

```bash
pip install trajectory-sdk
```

The SDK installs a Trajectory skill for coding agents at
`share/doc/trajectory-sdk/skills/trajectory/SKILL.md` in its Python environment. Print its path:

```bash
python -c "import importlib.metadata as m; print(next(f.locate().resolve() for f in m.files('trajectory-sdk') if f.name == 'SKILL.md'))"
```

Copy that file into your spec repo at `.agents/skills/trajectory/SKILL.md` for Codex or
`.claude/skills/trajectory/SKILL.md` for Claude Code.

## Start here

The [Trajectory docs](https://docs.trajectory.ai) cover the SDK. Start with the
[quickstart](https://docs.trajectory.ai/quickstart), then
[bring a spec](https://docs.trajectory.ai/guides/spec),
[evaluate](https://docs.trajectory.ai/guides/evaluations),
[train](https://docs.trajectory.ai/guides/training), and
[deploy](https://docs.trajectory.ai/guides/deployments).
The SDK also installs these guides next to the skill. The [cookbook](https://github.com/Trajectorylabs/trajectory-cookbook)
has worked integrations for different harnesses and graders.

## Quick start

Set `TRAJECTORY_API_KEY`, then create a client:

```python
from trajectory import Client

client = Client()
benchmarks = client.benchmarks.list(limit=10)
```

For task execution, follow the [native spec harness](#native-spec-harness) and
[registration and image builds](#registration-and-image-builds) examples below.

SDK-owned API clients use a 600-second read/write/pool timeout and a 5-second connection timeout.
Supplying `http_client=` inherits that client's timeouts, including a bare HTTPX client's 5-second
default. An explicit `Client(timeout=...)` overrides the supplied client; a resource method's
`timeout=` overrides that request. `timeout=None` disables timeouts. Retry counts are unchanged.

Blob store uploads through signed URLs default to a one-hour timeout (3,600 seconds), configured
separately from API requests. Set `upload_timeout=...` on `push()`, `start_push()`, or
`start_task_diagnostic()`, or `timeout=...` on `put_files()`. Pass `None` to disable blob store
timeouts. These apply to individual HTTP operations against the blob store, not the total upload
duration or signed-URL expiry.
`push()` and `start_push()` retry each upload request up to `upload_max_retries` times (default
`32`, within 4.5 minutes of waiting), separately from the client's `max_retries`.

The generated resource methods map directly to the public HTTP API. Spec submission
and file-upload workflows are available from `trajectory.lib`.

## Native spec harness

A task's `run_command` starts your program inside its runtime. This self-contained example uses
an inline question and expected answer for clarity. Inputs and references may come from files or
other sources; ensure the agent and its tools cannot access private reference data. `input_messages`
is stored task metadata; the native runtime does not send it to the model or to your program's
stdin. Your harness reads the input, calls the model, grades its answer, records the reward, and
completes the trajectory before exiting. The SDK has no `trajectory` CLI executable.

Managed runs supply `TRAJECTORY_API_KEY` and `TRAJECTORY_BASE_URL`.
Use `Client()` without embedding credentials in the image. `trajectories.create()` returns the
precreated trajectory ID; pass that ID explicitly to model, reward, and completion calls. Model
requests use the same client and API key, while the Backend resolves the model endpoint.

```python harness.py
from trajectory import Client

client = Client()
question = "What is 2 + 2?"
expected_answer = "4"

tid = client.trajectories.create().tid

response = client.chat.completions.create(
    model="policy",
    messages=[{"role": "user", "content": question}],
    x_trajectory_id=tid,
)

model_answer = response.choices[0].message.content or ""
reward = float(model_answer.strip() == expected_answer)

client.trajectories.log_reward(
    tid,
    name="accuracy",
    value=reward,
)
client.trajectories.complete(tid, termination_reason="ENV_DONE")
```

Package this file and its dependencies in your Dockerfile. For example, copying it to
`/app/harness.py` makes `python /app/harness.py` the task's `run_command`. A wrong answer gets
reward zero and `ENV_DONE`. Process exit alone does not complete a trajectory.

## Registration and image builds

Define a `BenchmarkSpec` named `benchmark` with your tasks, distinct `train`/`test` splits,
and a runtime such as `DockerfileBuild("Dockerfile")`. With the Dockerfile and harness under
the local `benchmark/` directory,
[choose or create an agent](https://docs.trajectory.ai/agent), then register the
spec and build its runtime. Replace `YOUR_AGENT_NAME` with that agent's name:

```python registration.py
from pathlib import Path

from trajectory import Client
from trajectory.lib import push

client = Client()
result = push(
    client, benchmark, agent_name="YOUR_AGENT_NAME", root=Path("benchmark"), build_images=True
)
```

The spec name comes from `manifest.name`: reusing a name under the same agent pushes
a new version.
Every new submission returns a new spec ID. Uploads do not accept a spec ID.

`push()` calls `start_push()` and waits for registration, returning a spec result
with `bench_id`. Both upload files with progress and accept the same arguments. Image builds
are off by default; pass `build_images=True` to include them and receive build failures
through the ingestion operation.

Use `start_push()` when you want control over waiting: it uploads files before returning
a `BenchmarkOperation`, while server processing continues. Call `operation.result()` to wait,
or save `operation.id` and reconnect later with `get_operation(client, operation.id)`.
It is a regular Python function; it does not require `await`.

`push()` raises `BenchmarkOperationError` on a failed build; inspect its `failures`
for the affected runtime and build error. Once the runtime is ready, follow the
SDK spec guide's diagnostic and evaluation steps; uploading does not execute
the tasks. Start evaluation or training with `agent_name` and `benchmark_name`
to select the latest version, or `bench_id` to select a specific version.
Run this registration code with your organization's API key.

## Development

```bash
uv run pytest
uv run ruff check .
uv run ruff format --check .
```

The generated client lives in `src/trajectory/`. Handwritten workflows live in
`src/trajectory/lib/`, and tests live in `tests/`.

## License

Apache License 2.0.
