Skip to main content

Forge API

Create training datasets from a memory bank: submit forge jobs, preview Atulya Training Records (ATR), export JSONL.

Overview

For concepts, recipes, and ROI, read Data Forge first.

All endpoints are scoped to a single bank: /v1/default/banks/{bank_id}/forge/...


Endpoints

MethodPathPurpose
GET/forge/recipesList recipes, exporters, domain profiles, stages
POST/forge/jobsStart async forge job
GET/forge/recordsPaginated ATR preview
POST/forge/exportExport via adapter (JSONL in response body)
GET/forge/jobs/{operation_id}/lineageLineage manifest for a completed job

Forge jobs are async operations. Poll status with Operations:

  • GET /operations/{operation_id}
  • GET /operations/{operation_id}/result — includes quality_summary on completion

List recipes

curl "http://localhost:8000/v1/default/banks/my-bank/forge/recipes?domain_tags=startup_ops"

Response shape:

{
"recipes": [
{
"recipe_id": "temporal_qa",
"version": "1",
"title": "Temporal Q&A",
"description": "Multi-hop questions with recall + reflect and cited memory IDs.",
"requires_ingest": false,
"cost_tier": "medium",
"training_signal": "Temporal reasoning with citations"
}
],
"exporters": [
{
"adapter_id": "atr_jsonl",
"version": "1",
"title": "ATR JSONL",
"description": "Canonical Atulya Training Record format."
}
],
"domain_profiles": [
{
"id": "startup_ops",
"title": "Startup ops",
"description": "Customer calls, deals, incidents, product decisions."
}
],
"suggested_recipes": ["agent_trace", "temporal_qa", "consolidation_pairs"],
"stages": [
{ "id": "ingest", "label": "Ingesting source" }
]
}

Submit forge job

curl -X POST "http://localhost:8000/v1/default/banks/my-bank/forge/jobs" \
-H "Content-Type: application/json" \
-d '{
"recipe_id": "consolidation_pairs",
"domain_tags": ["startup_ops"],
"quality_threshold": 0.6,
"wait_consolidation": true,
"repo_commit_on_complete": false,
"source": {
"source_type": "scenario",
"payload": {
"scenarios": [
{
"id": "deploy-1",
"facts": [
{
"id": "f1",
"key": "deploy_region",
"value": "us-east-1",
"timestamp": "2026-01-05T09:00:00Z"
}
]
}
]
}
}
}'

Request body

FieldTypeDefaultDescription
recipe_idstringrequiredRecipe from catalog
domain_tagsstring[][]Domain profile hints
sourceobjectoptionalIngest source; omit for bank-only recipes
quality_thresholdfloat0.6Minimum score for exportable
wait_consolidationbooltrueWait for consolidation before recipe
max_recordsintoptionalCap rows per job
repo_commit_on_completeboolfalseSnapshot dataset to memory repo
commit_messagestringoptionalRepo commit message
optionsobjectoptionalRecipe-specific (e.g. scenario_payload for synthetic_expand)

Source object

FieldDescription
source_typescenario | chat | timeseries | bank_only
payloadAdapter-specific JSON (empty for bank_only)

Response:

{
"operation_id": "550e8400-e29b-41d4-a716-446655440000",
"deduplicated": false
}

Validation errors

Invalid requests return 400 with structured detail:

{
"detail": {
"error": "forge_validation_error",
"field": "source.payload.scenarios",
"message": "Scenario source has no ingestible facts."
}
}

List forge records

curl "http://localhost:8000/v1/default/banks/my-bank/forge/records?operation_id=550e8400-e29b-41d4-a716-446655440000&limit=50"
Query paramDescription
operation_idFilter to one forge job
limit / offsetPagination

Response:

{
"records": [
{
"record_id": "atr-abc123",
"recipe_id": "temporal_qa",
"quality_score": 0.85,
"exportable": true,
"record": { }
}
],
"total": 12,
"exportable_total": 10,
"limit": 50,
"offset": 0
}

Export

curl -X POST "http://localhost:8000/v1/default/banks/my-bank/forge/export" \
-H "Content-Type: application/json" \
-d '{
"operation_id": "550e8400-e29b-41d4-a716-446655440000",
"adapter_id": "openai_chat_jsonl",
"quality_threshold": 0.6
}'
FieldDescription
operation_idCompleted forge job
adapter_idatr_jsonl | openai_chat_jsonl | graph_intelligence_jsonl
quality_thresholdOverride threshold at export time
optionsAdapter-specific options

Response includes content (JSONL string), record_count, exportable_count, and quality_summary.

Export errors (no records, threshold blocks all rows) return 400 with forge_export_error.


Lineage

curl "http://localhost:8000/v1/default/banks/my-bank/forge/jobs/550e8400-e29b-41d4-a716-446655440000/lineage"

Returns recipe ID, bank ID, record counts, quality summary, and provenance metadata for audit trails.


Operation result payload

When a forge job completes, GET .../operations/{id}/result includes:

{
"status": "completed",
"operation_type": "forge_job",
"result": {
"quality_summary": {
"total": 12,
"exportable": 10,
"held_back": 2,
"pass_rate": 0.833,
"avg_score": 0.78,
"issue_counts": {
"answer present without memory citations": 2
}
},
"records_total": 12,
"records_exportable": 10
}
}

Admin CLI

uv run atulya-admin forge run \
--bank my-bank \
--recipe consolidation_pairs \
--source-file ./source.json \
--domain-tag macro \
--wait

See Admin CLI.