Sign In

Running Jobs

Submit generation jobs, monitor progress, download results, and manage the job lifecycle.

Job Lifecycle

Every generation job progresses through these states:

created -> queued -> running -> succeeded | failed | canceled
  • Credits for an ordinary job are deducted on succeeded. A live OT streaming session is quoted and reserved at submission, then reconciled when the session ends
  • A hash-sealed evidence bundle is written to storage on success; tenant-signed notarization is additionally recorded once your workspace has an evidence signing key
  • A provenance seal is committed to the seal registry on success

Creating a Job

Create a job
from radmah_sdk import RadMahClient

client = RadMahClient(api_key="sl_live_...")

# Synthesize rows from an uploaded dataset
job = client.jobs.create(
    kind="synthesize",
    dataset_id="...",
    rows=100_000,
)

# Wait for completion
job.wait()
print(f"Status: {job.status}")
print(f"Job ID: {job.id}")

Prompt-to-data uses the Fabricate preview workflow

Generating tabular data from a natural-language description is not a generic job kind. It runs through the reviewed Fabricate workflow — create_fabricate_preview(), optional refine_fabricate_preview(), then approve_fabricate_preview() — which enqueues the final generation job only after you approve the previewed contract. See the Fabricate guide.

Job Kinds

The platform automatically selects the appropriate generation pipeline for each job kind. Prompt-to-tabular Fabricate is not a generic job kind — it always runs through the reviewed preview workflow described above.

KindDescription
synthesizeTrained generative model synthesis from uploaded data
simulatePhysics-based SCADA/ICS simulation
analyzeColumn profiling and schema inference on uploaded data
trainTrain a generative model on uploaded data
fitCompute summary statistics for a seal
verifyVerify artifact integrity
scenario_fabricateLLM-authored SCADA/ICS scenario packs
liftTransform raw data into typed WorldState

Monitoring Jobs

Monitor jobs
# Check status
job = client.jobs.get(job_id="...")
print(job.status)  # "running", "succeeded", etc.

# List recent jobs
jobs = client.jobs.list(limit=10)
for j in jobs:
    print(f"{j.id}: {j.status}")

# Wait with timeout
job.wait(timeout=300.0)  # raises TimeoutError after 5 min

Downloading Results

Download results
# As a pandas DataFrame
df = job.to_dataframe()

# List all artifacts for a job
artifacts = client.list_job_artifacts(job.id)
for a in artifacts:
    print(f"{a.artifact_type}: {a.sha256}")

# Download a specific artifact's content
content = client.download_artifact(job.id, artifacts[0].id)
with open("output.csv", "w") as fh:
    fh.write(content)

Canceling and Rerunning

Cancel / rerun
# Cancel a running job
client.jobs.cancel(job_id="...")

# Rerun a completed job (same sealed contract, same seed = identical output)
rerun = client.jobs.rerun(job_id=job.id)
rerun.wait()

Queue Routing

Jobs are automatically routed to the appropriate Celery queue based on job kind and plan tier:

QueuePurpose
radmah-defaultStandard synthesize, analyze, and verify jobs
radmah-gpuGPU-accelerated training jobs
radmah-freeFree-tier jobs (lower priority)
radmah-interactiveChat-triggered quick jobs (low latency)

Credit Estimation

Before submitting a job, you can estimate the credit cost:

Estimate credits
# POST /v1/client/estimate takes the contract dict, not a bare row count
estimate = client.estimate_job(contract, seed=42)
print(estimate["credits_required"])     # total credits at submission
print(estimate["credits_generation"])   # row-based generation cost
print(estimate["requested_records"])    # row count the estimate used

Credit Rate

Generation credit rate: 1 credit = 1,000,000 rows for Fabricate, Synthesis, and CCTP; 1 credit = 500,000 rows for Virtual SCADA and ICS Security. Streaming SCADA/ICS sessions add a duration surcharge. The platform always shows the estimated cost before you confirm.