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

# Research Factory Quickstart

> Create one bounded Factory, preview and confirm a due experiment, inspect its WorkProduct, and stop safely.

This walkthrough creates one private Factory for a bounded Craftax policy
experiment. Craftax is the example, not the product boundary: the same loop
works for any objective with an explicit baseline, metric, evaluator, workspace,
budget, and stopping condition.

<Note>
  This guide targets `synth-ai[research]` 0.16.0 and is bound to release
  source [`c98f5faa`](https://github.com/synth-laboratories/synth-ai/commit/c98f5faa200cced6be33a92278b2aada47844bbb).
  Publish it only with the matching package release and backend Factory routes.
</Note>

## 1. Install and authenticate

```bash theme={null}
uv add "synth-ai[research]==0.16.0"
export SYNTH_API_KEY="sk_..."
export SYNTH_RESEARCH_PROJECT_ID="project_..."
```

## 2. Define bounded work

```python theme={null}
import os
from datetime import datetime, timezone

from synth_ai import SynthClient

client = SynthClient()
research = client.research
control = research.session

project = research.projects.get(os.environ["SYNTH_RESEARCH_PROJECT_ID"])

factory = control.factories.create(
    {
        "name": "Craftax policy factory",
        "description": "Beat the baseline on benchmark-owned held-out reward.",
        "budget_policy": {"limit": 25, "currency": "USD", "period": "month"},
        "cap_policy": {"max_active_runs": 1, "max_active_efforts": 1},
        "publication_policy": {"visibility": "private"},
    }
)

control.factories.link_workspace_project(
    factory.factory_id,
    project.project_id,
    display_name="Craftax evaluation workspace",
)

effort = control.factories.create_effort(
    factory.factory_id,
    name="Improve held-out reward",
    hypothesis_or_topic=(
        "Propose one small policy change and accept it only when the held-out "
        "evaluator beats the pinned baseline."
    ),
    effort_type="optimizer",
    recurrence_policy={"cadence": "daily", "max_active_runs": 1},
    next_wake_at=datetime.now(timezone.utc),
)
```

`SYNTH_RESEARCH_PROJECT_ID` must identify an existing prepared project whose
workspace contains the pinned baseline, evaluator, allowed source,
model/provider references, and output path. Runnable-project creation requires
the deployment-specific runtime and agent-profile contract; this quickstart
does not guess those values. A Factory is not permission to read arbitrary
organization resources.

## 3. Preview, inspect, and confirm

```python theme={null}
preview = research.factories.preview_wake(factory.factory_id, limit=1)

print("preview:", preview.preview_id)
print("ready:", preview.ready)
print("expires:", preview.preview_expires_at)
for item in preview.efforts:
    print(item.effort_id, item.status, item.reason, item.launch_preview)

if preview.ready != 1:
    raise RuntimeError("Expected exactly one ready experiment; nothing launched")

receipt = research.factories.wake_due(factory.factory_id, preview=preview)
print("receipt:", receipt.receipt_id)
print("confirmed preview:", receipt.confirmed_preview_id)
print("launched:", receipt.launched)
```

Keep the opaque preview token in process memory. The typed `wake_due` call
replays the preview’s exact request contract and checks the returned receipt.

## 4. Inspect experiments and outputs

```python theme={null}
status = research.factories.status(factory.factory_id)

print("next wake:", status.next_wake_at)
print("experiment:", status.experiment_observability)
for run in status.latest_runs:
    print("run:", run.run_id, run.public_state)
for product in status.latest_work_products:
    print("work product:", product.work_product_id, product.title, product.readiness)
```

Open a WorkProduct in the dashboard from `/smr/factories`, or through its
authenticated content endpoint. Treat a candidate as unaccepted until the
configured evaluator records the held-out comparison.

## 5. Stop safely

Pause the Effort to prevent future wakes. Archive only resources created for
this rehearsal after any active run reaches a terminal state:

```python theme={null}
control.efforts.pause(effort.effort_id)

# After the active run is terminal:
control.efforts.archive_reference(effort.effort_id)
control.factories.archive(factory.factory_id)
research.close()
```

Pausing a Factory or Effort does not imply that an already-started run was
cancelled. Use the run’s explicit stop control when that is required.

## REST API equivalent

For an already configured Factory, preview and confirm through the same backend
boundary. Keep the opaque token in a shell variable and remove it from displayed
output:

```bash theme={null}
export SYNTH_API_KEY="sk_..."
export FACTORY_ID="factory_..."
export SYNTH_API_URL="https://api.usesynth.ai"

preview=$(curl --fail-with-body --silent --show-error \
  --request POST \
  --header "Authorization: Bearer $SYNTH_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"dry_run":true,"limit":1,"continue_on_error":true}' \
  "$SYNTH_API_URL/smr/factories/$FACTORY_ID/wake-due")

printf '%s' "$preview" | jq 'del(.preview_token)'

confirm=$(printf '%s' "$preview" | jq -c '(.request_contract // {}) + {
  dry_run: false,
  confirmed_preview_id: .preview_id,
  confirmed_preview_token: .preview_token
}')

curl --fail-with-body --silent --show-error \
  --request POST \
  --header "Authorization: Bearer $SYNTH_API_KEY" \
  --header "Content-Type: application/json" \
  --data "$confirm" \
  "$SYNTH_API_URL/smr/factories/$FACTORY_ID/wake-due" \
  | jq 'del(.preview_token)'
```

Do not run the confirmation request when `ready` is zero. Do not write
`preview`, `confirm`, or shell tracing output to an evidence packet because each
contains the opaque token.

## MCP equivalent

Ask your MCP client:

```text theme={null}
Create a private Craftax Research Factory with a $25 monthly budget, one active
run, one daily Effort, and my configured Craftax workspace. Preview exactly one
due experiment and show me the objective, workspace, consequences, expiry, and
ready count. Do not confirm until I approve. After approval, confirm the exact
preview, return the receipt ID, and show the resulting run and WorkProduct.
```

The client should use `smr_preview_factory_wake` before
`smr_wake_due_factory_efforts` and must not print the preview token.

## Evidence boundary

The SDK examples are source-bound to release candidate `c98f5faa`. The release packet,
not this guide, owns the final wheel hash plus the production Craftax run and
WorkProduct receipts. This example does not substitute documentation for those
receipts, claim every objective improves, or claim that long-horizon durability
clocks are complete.
