atmon docs

REFERENCE/API/JOBS.MD

JobsService

Hand over work that is bigger than one call: analyze ten thousand rows, move forty thousand files, write to a hundred records. You submit a plan and read receipts; the rows themselves stay on our side and never travel back to you. A job outlives the request that started it, so it is submitted once and read back later.

Every call is a POST to https://api.atmon.ai/automaton.v1.JobsService/<Call> with a JSON body, and authenticates with Authorization: Bearer <your project key>. Field names in JSON are lowerCamelCase, so the field written tool_slug below is toolSlug on the wire. How to call the API has the whole convention.

Calls

CallRequestResponseSummary
SubmitJobSubmitJobRequestSubmitJobResponse
GetJobGetJobRequestGetJobResponse
ListJobsListJobsRequestListJobsResponse
ListJobEventsListJobEventsRequestListJobEventsResponseListJobEvents reads one job's log in sequence order, each entry naming the chain that caused it.
AnswerAskAnswerAskRequestAnswerAskResponseAnswerAsk is how a person answers a question a job addressed to them.
ListAsksListAsksRequestListAsksResponseListAsks reads the questions a project has addressed to people: what is outstanding, who holds it, what was answered and by whom.
GetAskGetAskRequestGetAskResponseGetAsk reads one of them.

SubmitJob

Request SubmitJobRequest, response SubmitJobResponse.

POST /automaton.v1.JobsService/SubmitJob HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "programJson": "{}",
  "idempotencyKey": "...",
  "mode": "...",
  "simulateFirst": true
}

The response:

{
  "job": {
    "id": "...",
    "status": "JOB_STATUS_PENDING_PLAN_APPROVAL",
    "programJson": "{}",
    "programHash": "...",
    "estimate": { ... },
    "planApprovalId": "...",
    "park": { ... },
    "stepReceipts": [{ ... }],
    "receipt": { ... },
    "lastError": "...",
    "createdAt": "2026-01-31T09:15:00Z",
    "updatedAt": "2026-01-31T09:15:00Z",
    "finishedAt": "2026-01-31T09:15:00Z",
    "pendingAsk": { ... },
    "saga": { ... },
    "mode": "...",
    "simulatedFrom": "...",
    "skillSlug": "..."
  }
}

GetJob

Request GetJobRequest, response GetJobResponse.

POST /automaton.v1.JobsService/GetJob HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "id": "..."
}

The response:

{
  "job": {
    "id": "...",
    "status": "JOB_STATUS_PENDING_PLAN_APPROVAL",
    "programJson": "{}",
    "programHash": "...",
    "estimate": { ... },
    "planApprovalId": "...",
    "park": { ... },
    "stepReceipts": [{ ... }],
    "receipt": { ... },
    "lastError": "...",
    "createdAt": "2026-01-31T09:15:00Z",
    "updatedAt": "2026-01-31T09:15:00Z",
    "finishedAt": "2026-01-31T09:15:00Z",
    "pendingAsk": { ... },
    "saga": { ... },
    "mode": "...",
    "simulatedFrom": "...",
    "skillSlug": "..."
  },
  "simulation": {
    "id": "...",
    "status": "JOB_STATUS_PENDING_PLAN_APPROVAL",
    "programJson": "{}",
    "programHash": "...",
    "estimate": { ... },
    "planApprovalId": "...",
    "park": { ... },
    "stepReceipts": [{ ... }],
    "receipt": { ... },
    "lastError": "...",
    "createdAt": "2026-01-31T09:15:00Z",
    "updatedAt": "2026-01-31T09:15:00Z",
    "finishedAt": "2026-01-31T09:15:00Z",
    "pendingAsk": { ... },
    "saga": { ... },
    "mode": "...",
    "simulatedFrom": "...",
    "skillSlug": "..."
  }
}

ListJobs

Request ListJobsRequest, response ListJobsResponse.

POST /automaton.v1.JobsService/ListJobs HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "status": "JOB_STATUS_PENDING_PLAN_APPROVAL",
  "pageSize": 0,
  "pageToken": "...",
  "mode": "...",
  "skillSlug": "..."
}

The response:

{
  "jobs": [{
    "id": "...",
    "status": "JOB_STATUS_PENDING_PLAN_APPROVAL",
    "programJson": "{}",
    "programHash": "...",
    "estimate": { ... },
    "planApprovalId": "...",
    "park": { ... },
    "stepReceipts": [{ ... }],
    "receipt": { ... },
    "lastError": "...",
    "createdAt": "2026-01-31T09:15:00Z",
    "updatedAt": "2026-01-31T09:15:00Z",
    "finishedAt": "2026-01-31T09:15:00Z",
    "pendingAsk": { ... },
    "saga": { ... },
    "mode": "...",
    "simulatedFrom": "...",
    "skillSlug": "..."
  }],
  "nextPageToken": "..."
}

ListJobEvents

ListJobEvents reads one job's log in sequence order, each entry naming the chain that caused it. It is the attribution surface over the engine, and a job of another project reads as missing.

Request ListJobEventsRequest, response ListJobEventsResponse.

POST /automaton.v1.JobsService/ListJobEvents HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "jobId": "..."
}

The response:

{
  "events": [{
    "jobId": "...",
    "seq": 0,
    "type": "...",
    "stepId": "...",
    "at": "2026-01-31T09:15:00Z",
    "payloadJson": "{}",
    "principalChain": ["..."]
  }]
}

AnswerAsk

AnswerAsk is how a person answers a question a job addressed to them.

Request AnswerAskRequest, response AnswerAskResponse.

POST /automaton.v1.JobsService/AnswerAsk HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "jobId": "...",
  "requestId": "...",
  "principalId": "...",
  "continuation": "...",
  "overridesJson": "{}",
  "note": "...",
  "deliveryId": "..."
}

The response:

{
  "job": {
    "id": "...",
    "status": "JOB_STATUS_PENDING_PLAN_APPROVAL",
    "programJson": "{}",
    "programHash": "...",
    "estimate": { ... },
    "planApprovalId": "...",
    "park": { ... },
    "stepReceipts": [{ ... }],
    "receipt": { ... },
    "lastError": "...",
    "createdAt": "2026-01-31T09:15:00Z",
    "updatedAt": "2026-01-31T09:15:00Z",
    "finishedAt": "2026-01-31T09:15:00Z",
    "pendingAsk": { ... },
    "saga": { ... },
    "mode": "...",
    "simulatedFrom": "...",
    "skillSlug": "..."
  }
}

ListAsks

ListAsks reads the questions a project has addressed to people: what is outstanding, who holds it, what was answered and by whom. Until it existed an ask was visible only by listing jobs and reading pending_ask, so an answered one was visible only by reading a log.

Request ListAsksRequest, response ListAsksResponse.

POST /automaton.v1.JobsService/ListAsks HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "state": "ASK_STATE_PENDING",
  "principalId": "...",
  "jobId": "...",
  "standingProgramId": "...",
  "pageSize": 0,
  "pageToken": "..."
}

The response:

{
  "asks": [{
    "pointId": "...",
    "principalId": "...",
    "hopIndex": 0,
    "deliveredPrincipals": ["..."],
    "toolSlug": "...",
    "entityId": "...",
    "toolCallId": "...",
    "deliveredAt": "2026-01-31T09:15:00Z",
    "deadlineAt": "2026-01-31T09:15:00Z",
    "approvalId": "...",
    "exhausted": true,
    "jobId": "...",
    "requestId": "...",
    "state": "ASK_STATE_PENDING",
    "question": "...",
    "answerSchemaJson": "{}",
    "continuations": ["..."],
    "escalation": [{ ... }],
    "askedAt": "2026-01-31T09:15:00Z",
    "decision": { ... },
    "stepId": "...",
    "delivery": "..."
  }],
  "nextPageToken": "..."
}

GetAsk

GetAsk reads one of them.

Request GetAskRequest, response GetAskResponse.

POST /automaton.v1.JobsService/GetAsk HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "jobId": "...",
  "requestId": "..."
}

The response:

{
  "ask": {
    "pointId": "...",
    "principalId": "...",
    "hopIndex": 0,
    "deliveredPrincipals": ["..."],
    "toolSlug": "...",
    "entityId": "...",
    "toolCallId": "...",
    "deliveredAt": "2026-01-31T09:15:00Z",
    "deadlineAt": "2026-01-31T09:15:00Z",
    "approvalId": "...",
    "exhausted": true,
    "jobId": "...",
    "requestId": "...",
    "state": "ASK_STATE_PENDING",
    "question": "...",
    "answerSchemaJson": "{}",
    "continuations": ["..."],
    "escalation": [{ ... }],
    "askedAt": "2026-01-31T09:15:00Z",
    "decision": { ... },
    "stepId": "...",
    "delivery": "..."
  }
}

Messages

AnswerAskRequest

AnswerAskRequest lands one principal's answer to an outstanding ask. The answer selects a continuation the program declared and nothing else, and the answering key comes from the authenticated request: an approval ask resolves its approval through policy, and policy refuses a key without the approver role and the very key whose plan parked there.

FieldType#Notes
job_idstring1
request_idstring2request_id is optional. Naming it refuses an answer to a question the job has already moved past.
principal_idstring3principal_id is the contact answering. An answer from anyone the ask has not reached is refused.
continuationstring4continuation is one of proceed, retry-with, skip, or abort, and it must be one the judgment point declared.
overrides_jsonstring5overrides_json carries a retry-with answer's changes, in the shape the point's answer schema declares.
notestring6
delivery_idstring210delivery_id names the webhook delivery this answer came back on, taken from the X-Automaton-Delivery-Id header of the ask_raised delivery. It is recorded as the answer's surface and authorizes nothing: the answer is authorized by the presented key either way. Empty for an answer given directly, which records the surface as "api". Delivery is at-least-once and answering is at-most-once, so the same question can arrive twice. A second answer to an answered ask is refused, recorded on the job's log as an answer-refused entry, and moves nothing.

AnswerAskResponse

FieldType#Notes
jobJob1

Ask

Ask is one outstanding question addressed to a named principal: who holds it now, the channel call that carried it, and when the engine stops waiting. An ask is a judgment point whose handler is a principal, not a separate mechanism, so what releases the job is still an answer naming one of the continuations the program declared.

The question text is not repeated here. It is on the pending judgment this ask belongs to, and a job carries one of each.

FieldType#Notes
point_idstring1point_id is the judgment point the program declared, or "approval" when the ask is an approval gate the engine addressed to a person.
principal_idstring2principal_id is the contact who holds the question now, which is the last hop the escalation ladder reached.
hop_indexint323
delivered_principalsrepeated string4delivered_principals lists every contact the ask has reached, in hop order. Only these may answer it.
tool_slugstring5
entity_idstring6
tool_call_idstring7tool_call_id is the ledger row the delivery was recorded as.
delivered_atgoogle.protobuf.Timestamp8
deadline_atgoogle.protobuf.Timestamp9deadline_at is when this hop's timeout fires. Unset means the ask waits without a deadline, which is what an approval ask does: no clock approves.
approval_idstring10approval_id is set when the ask is a policy approval gate. Answering it resolves that approval through policy, where separation of duty is enforced.
exhaustedbool11exhausted reports an escalation ladder that ran out with no declared default: nothing more is delivered and a person owns the question.
job_idstring200job_id and request_id are how an answer names this ask: AnswerAsk takes both, and request_id refuses an answer to a question the job has moved past. They and the fields below them are the read surface's (ListAsks, GetAsk); a job's pending_ask leaves them empty, because a job read carries the question on park.judgment beside it.
request_idstring201
stateAskState202
questionstring203question and answer_schema_json are the judgment point's own, repeated here because a reader of an ask list has no judgment beside it to read them from. A form is generated from the schema, so a program declaring a new question shape needs no client change.
answer_schema_jsonstring204
continuationsrepeated string205continuations is what an answer may pick: proceed, retry-with, skip, abort, and only the ones the point declared.
escalationrepeated AskHopSpec206escalation is the declared ladder, whether or not it has been climbed, so a reader sees who this question reaches next and when.
asked_atgoogle.protobuf.Timestamp207
decisionAskDecision208decision is set once the ask was settled, by a person or by the clock.
step_idstring209
deliverystring210delivery is what became of this ask's publication onto the registered ask endpoints: "delivered", "pending", or "dead-letter". Empty means nothing was published to an endpoint, which is what a project that registered none reads on every ask, and the channel call in tool_call_id is a separate surface either way. It is here so an ask that defaulted on its timeout with nobody reached reads differently from one a person did not answer.

AskDecision

AskDecision is the recorded answer to an ask: which continuation it picked, who picked it, and where the answer arrived from. Every surface records the same entry, which is what keeps replay from a recorded answer a pure function.

FieldType#Notes
continuationstring1continuation is one of proceed, retry-with, skip, or abort.
principal_idstring2principal_id is the contact addressed that answered. Empty when the clock decided.
key_idstring3key_id is the API key that presented the answer. A contact id is an address and authorizes nobody; the key is what was authorized, so an audit of "who decided" reads both. Empty when the clock decided, and on answers recorded before this field existed.
surfacestring4surface is where the answer arrived from: "api" for an answer presented on AnswerAsk, "timeout" for the declared default the clock applied.
notestring5
hop_indexint326hop_index is the rung that answered, so "who decided" answers with the hop as well as the principal.
atgoogle.protobuf.Timestamp7

AskHopSpec

AskHopSpec is one rung of a declared escalation ladder: who it reaches and how long they hold the question. The arguments template is not on the wire, since it is the delivery's business and not the reader's.

FieldType#Notes
principal_idstring1
tool_slugstring2
timeout_secondsint323

CompensationReceipt

CompensationReceipt is one act step's unwind, told honestly: how many of its committed rows the saga tried to undo, how many it undid, and the ones it could not, named. A stranded row is an external resource with no owner until a human takes it, which is why the count is never rounded away.

FieldType#Notes
attemptedint321
compensatedint322
strandedint323
stranded_row_keysrepeated string4

Cost

Cost is what a step or a job spent. Model spend is metered in micro-USD (one millionth of a dollar) because one row's map call costs less than a cent, and action_count is external effects, the unit an action budget is written in.

FieldType#Notes
model_micro_usdint641
action_countint322
discarded_model_micro_usdint643discarded_model_micro_usd is the part of model_micro_usd that prices work an attempt paid for and could not report: a step killed between checkpoints spends money nothing durable records, and the resumed attempt charges the rows it re-does twice rather than leaving that spend off the receipt. It is therefore a bound, not a measurement, and model_micro_usd is an upper bound of what the project paid whenever it is above zero.

CostEstimate

CostEstimate is the projection a human approves.

FieldType#Notes
rowsint321
model_micro_usdint642
action_countint323
effectsrepeated ProjectedEffect4

GetAskRequest

GetAskRequest reads one ask. request_id is optional: naming no request reads the ask the job is waiting on now.

FieldType#Notes
job_idstring1
request_idstring2

GetAskResponse

FieldType#Notes
askAsk1

GetJobRequest

FieldType#Notes
idstring1

GetJobResponse

FieldType#Notes
jobJob1
simulationJob94simulation is the job named by job.simulated_from, receipts included, so an approver reads the measured diff beside the projected estimate in one call. Absent when the plan was not simulated first.

Job

Job is the folded state of one job's event log.

FieldType#Notes
idstring1
statusJobStatus2
program_jsonstring3the plan verbatim, as submitted
program_hashstring4
estimateCostEstimate5
plan_approval_idstring6set when the plan parked before step one
parkPark7set while status is PARKED
step_receiptsrepeated StepReceipt8
receiptReceipt9the fold; complete is false until every step reported
last_errorstring10
created_atgoogle.protobuf.Timestamp11
updated_atgoogle.protobuf.Timestamp12
finished_atgoogle.protobuf.Timestamp13
pending_askAsk60pending_ask is the question this job owes an answer to, when it parked on one. It mirrors park.judgment's ask so a reader learns who was asked without walking into the park.
sagaSagaState70saga is what became of the effects this job landed, set once an unwind has compensated anything. A job parked with stranded rows names them here.
modestring92mode is what this submission was allowed to touch: "run" (the default), "simulate" (act steps projected instead of called) or "shadow" (every external call answered from recorded state). Every receipt of a measuring run carries simulated, and a simulated receipt never folds into a real one.
simulated_fromstring93simulated_from names the simulation this plan was measured by, set when the submission asked to be simulated first. Its receipts are the diff an approver reads beside the estimate.
skill_slugstring80skill_slug names the promoted skill whose call submitted this job, empty when a caller submitted the program directly. Everything else about the job is the same either way.

JobEvent

JobEvent is one entry of a job's append-only log, which is the audit answer to "what did this job do". Rows never cross this surface: payload_json is the entry's own payload (a checkpoint, a receipt, a park reason), and the rows a step read or wrote live in collections.

FieldType#Notes
job_idstring1
seqint642seq is dense and 1-based per job, so the order of the page is the order the job walked and a gap means a lost write.
typestring3type is the log's closed vocabulary: submitted, plan-approved, step-started, checkpoint, step-completed, parked, judgment-requested, ask-delivered, judgment-recorded, answer-refused, compensation-applied, resumed, finished.
step_idstring4
atgoogle.protobuf.Timestamp5
payload_jsonstring6
principal_chainrepeated string140Who caused this entry, oldest cause first: "key:<id>", "skill:<slug>", "job:<id>". It is an audit record and never an authorization input.

ListAsksRequest

ListAsksRequest pages one project's asks. Every filter narrows; an empty one does not. Asks of another project are absent rather than forbidden, which is the read rule every surface here follows.

FieldType#Notes
stateAskState1state lists only asks in one state. Unspecified lists every state.
principal_idstring2principal_id lists only the asks this contact has been reached by, which is the inbox read: a question delivered to somebody else is not theirs to answer and is not theirs to see in this list.
job_idstring3
standing_program_idstring4standing_program_id lists the asks raised by the jobs a standing program fired.
page_sizeint325
page_tokenstring6

ListAsksResponse

FieldType#Notes
asksrepeated Ask1asks, newest question first.
next_page_tokenstring2

ListJobEventsRequest

FieldType#Notes
job_idstring1

ListJobEventsResponse

FieldType#Notes
eventsrepeated JobEvent1The whole log in sequence order. A job's log is bounded by its own steps and checkpoints, so the page is the log rather than a window on it.

ListJobsRequest

FieldType#Notes
statusJobStatus1unspecified lists every status
page_sizeint322
page_tokenstring3
modestring95mode narrows the page to one submission mode. Empty lists every mode.
skill_slugstring80skill_slug lists only the jobs one skill submitted, which is how "what has this skill done" is answered from the log. Empty lists every job.

ListJobsResponse

FieldType#Notes
jobsrepeated Job1
next_page_tokenstring2

Park

Park is why a running job stopped. approval_id names an approval in the policy queue, judgment the question a job waits on; both are set when the approval was delivered as an ask.

FieldType#Notes
step_idstring1
reasonstring2
approval_idstring3
judgmentPendingJudgment4
atgoogle.protobuf.Timestamp5

PendingJudgment

PendingJudgment is a declared pause waiting on an answer. It carries the question and the continuations the program declared, never rows: a decision sees counts and reasons.

FieldType#Notes
idstring1
step_idstring2
handlerstring3model, human, or principal
questionstring4
answer_schema_jsonstring5
continuationsrepeated string6proceed, retry-with, skip, or abort
breachesrepeated string7the declared bounds this step exceeded, if any
asked_atgoogle.protobuf.Timestamp8

ProjectedEffect

ProjectedEffect is one line of what a plan would do to the world, derived statically from the program before anything executes. access_class is the catalog's blast-radius class, and a destructive one is what makes a plan park for approval.

FieldType#Notes
step_idstring1
tool_slugstring2
access_classstring3
countint324
compensationbool70compensation marks an effect that only happens on an unwind: the inverse the step declared. An approver reads the forward effects as what the plan intends and these as what undoing it would do.

Receipt

Receipt is the failure-honesty contract: how many rows went in, how many came out, what was dropped and why, whether the producer saw everything it was supposed to, and what it cost. A job receipt is the fold of its step receipts, so it cannot claim more than the steps proved.

FieldType#Notes
rows_inint321rows_in and rows_out are the plan's "in" and "out". They are spelled out here because "in" is a keyword in some generated languages.
rows_outint322
droppedmap<string, int32>3dropped counts rows by reason. Nothing disappears without a reason.
completebool4complete is false when any producer declared a shortfall, and it is the AND over folded receipts.
costCost5
simulatedbool6simulated marks a receipt produced without touching the world. A simulated receipt is never folded into a real one.

SagaState

SagaState is the same account for the whole job: what its act steps landed and still stands, what was undone, and what is stranded. It is derived from the act steps' outcome collections and the log's compensation entries, and it is unset for a job that never unwound anything.

FieldType#Notes
committedint321committed is how many landed rows still stand, including the rows of act steps that declared no inverse.
compensatedint322
strandedint323
stranded_row_keysrepeated string4

StepReceipt

StepReceipt is one step's receipt plus what it produced.

FieldType#Notes
step_idstring1
primitivestring2collect, map, reduce, act, or files
receiptReceipt3
output_handlestring4the collection this step produced, if any
reusedbool5reused reports that the step did not run: an identical fingerprint already had an output collection, so the content address was served instead.
attemptint326
started_atgoogle.protobuf.Timestamp7
finished_atgoogle.protobuf.Timestamp8
compensationCompensationReceipt70compensation is the saga's account of this step's unwind, unset when nothing was unwound. It sits beside the receipt rather than inside it: rows in and rows out count what the step did, and undoing an effect does not touch a row twice.

SubmitJobRequest

FieldType#Notes
program_jsonstring1program_json is the job program. JSON is the surface syntax: SDKs generate it, and any sugar compiles to it. An unknown field is a refusal, so a typo fails at submit time instead of being ignored at hour three.
idempotency_keystring2idempotency_key makes a repeated submission return the original job instead of starting a second run of the same plan.
modestring90mode is what this submission may touch: "run" (default), "simulate" or "shadow". It rides on the request rather than in the program because the same program has to be runnable both ways: the plan a human approves and the plan that then runs are the same bytes.
simulate_firstbool91simulate_first submits two jobs: a simulation that runs now, and this plan, which parks for approval naming it. Two jobs, because a simulated receipt and a real one must never share a fold.

SubmitJobResponse

FieldType#Notes
jobJob1job carries the status the submission reached: running, or pending plan approval with the estimate the approver decides on.

Enums

JobStatus

Value#Meaning
JOB_STATUS_UNSPECIFIED0
JOB_STATUS_PENDING_PLAN_APPROVAL1The plan needs a human decision before step one runs. plan_approval_id names the approval and estimate carries the numbers it was granted on.
JOB_STATUS_RUNNING2
JOB_STATUS_PARKED3Stopped on an approval or a judgment point. park says which, so a parked job is a visible state with an owner rather than a stall.
JOB_STATUS_SUCCEEDED4
JOB_STATUS_FAILED5
JOB_STATUS_CANCELED6

AskState

AskState is what an ask is doing now. exhausted is not a state: an ask whose ladder ran out is still pending or escalated, because it still owes a person's answer, and the exhausted flag says nothing more will be delivered.

Value#Meaning
ASK_STATE_UNSPECIFIED0
ASK_STATE_PENDING1Outstanding, at the first hop.
ASK_STATE_ESCALATED2Outstanding, and the ladder has climbed at least one rung.
ASK_STATE_ANSWERED3A principal answered it.
ASK_STATE_TIMED_OUT4Nobody answered and the declared default applied. No approval ask reaches this state: an approval carries no default, because no clock approves.