docs
Concepts

Agent operations

What an agent operation is, the six kinds, own-harness handoff versus a nima-hosted VM, and how to start, follow and finish one from MCP, Slack or the API.

An agent operation is one unit of agent work that nima tracks from request to result. You start it from Slack, over MCP or over the REST API. There is no page for it in the web app.

Handing a spec to your own coding agent: on for every workspace. Over MCP or the API it needs a key that holds operations:write, which only owners and admins can get. No plan feature is needed.

Running work on a nima-hosted VM: enabled by the nima team on request. See nima-hosted VMs.

What an agent operation is

An agent operation is one unit of agent work on a connected GitHub repository. Each operation has a kind (what to do), a target (who does it), a budget and a state.

  • Kind: one of six, listed below.
  • Target: own_harness (your coding agent does the work, nima hands it a brief) or nima_vm (a nima-hosted VM does it).
  • Budget: AI spend in USD, active minutes and number of sessions. The workspace sets defaults and a maximum.
  • State: one of 14 states, from queued to a terminal state such as published or failed.

Every operation is recorded in the workspace, with its usage, end reason and, when it was started from Slack, the thread it came from. Any member can read every operation's state. See Who can see operations.

Operation kinds

nima has six operation kinds. Only implement_spec can run on your own coding agent. The other five need a nima-hosted VM.

KindWhat it doesInputPublishes
implement_specTurns an approved spec into a draft pull requestdocumentId, repositoryId (pass null to use the spec's repository; the key is required)new_draft_pr on a VM, nothing on your own harness
fix_ciAdds commits to the branch of a failing pull requestrepositoryId, pullRequestNumberappend_to_pr
reproduce_issueTurns a signal into a failing test and a reportrepositoryId, signalIdnothing by default; comment_only or new_draft_pr allowed
run_checksRuns the repository's configured test command and stores the logrepositoryId, pullRequestNumber and branch: send both of the last two keys and set exactly one of them to nullnothing by default; comment_only allowed
browser_checkServes the app in the VM, takes screenshots and runs tests, then reportssame as run_checksnothing by default; comment_only allowed
taskFree-form one-off work (an investigation, a benchmark, try-and-report) that ends in a report, never a pull requestrepositoryId, instruction (1 to 8000 characters), baseBranch (a branch name, or null for the default branch; the key is required), optional requesterMessagenothing, always

Rules that apply across kinds:

  • implement_spec only starts for a spec whose status is approved or in_progress. Any other status is a 409.
  • A publish policy that a kind does not allow is a 409 invalid_publish_policy. nima refuses it; it never downgrades it to a report.
  • task is left out of a workspace's allowedKinds by default. An admin adds it to allow it.
  • A task instruction that looks like a credential is refused with a 400. The VM has no network access, so a pasted credential could not be used anyway.
  • task is for investigation and reports. Feature work goes through a spec and implement_spec.

Two targets: your own coding agent or a nima-hosted VM

An operation runs either on your own coding agent (own_harness) or on a nima-hosted VM (nima_vm). The target decides who does the work, what it can publish and whether the workspace needs hosted compute.

Hand a spec to your own coding agent

The own_harness target needs no plan feature and no hosted compute. It supports implement_spec only, and it never publishes: nima builds a brief and your agent does the work in your environment. The flow uses three MCP tools, and only the requester can call them:

  1. get_operation_brief reads the handoff brief as Markdown. It starts no VM.
  2. claim_operation_handoff marks the handoff as started. The operation moves from queued to active.
  3. report_operation_result records what your agent produced (1 to 100,000 characters). The operation moves to reported.

nima stores the result as an external report. It does not attest that tests passed and does not publish code for it. Passing a publish policy other than none on an own-harness operation is a 409.

Run an operation on a nima-hosted VM

The nima_vm target runs the agent in a nima-hosted, isolated VM. It supports every kind. How VMs are enabled, what they can reach and how results reach GitHub is covered in nima-hosted VMs.

How nima picks the target

nima resolves the target with these rules, in order:

  1. If hosted compute is off for the workspace (the default): asking for nima_vm is a 409 org_disabled; otherwise the target is own_harness, and any kind other than implement_spec is a 409 kind_requires_vm.
  2. If hosted compute is on and you give a target, nima uses it.
  3. If hosted compute is on and you give none: implement_spec uses the workspace's defaultTarget (own_harness unless changed); every other kind uses nima_vm.
  4. For a VM, the kind must be in the workspace's allowedKinds, or the request is a 409 kind_not_allowed.

nima never falls back silently from a VM to your own harness, and never to a different publish policy.

Getting a key that can start operations

A key that can start operations holds the operations:write scope, and that scope comes only from Slack. The API key form in Settings and the OAuth consent screen do not offer it.

An owner or admin messages @nima in a channel or a DM, or runs the /nima slash command:

@nima mcp-key operations

nima replies privately with a Confirm button. After the admin confirms (or tells @nima confirm <code> in the same channel within 5 minutes), nima shows the key once. The key:

  • lasts 30 days;
  • holds operations:write, documents:read and knowledge:read;
  • does not turn on hosted compute or GitHub publishing.

Only a workspace owner or admin can run mcp-key operations, and the key belongs to that person. Members cannot get operations:write. A member can still start work from Slack with agent ..., which needs no key, but only an owner or admin can start operations over MCP or the API and then claim and report an own-harness handoff.

Configuring hosted compute or publishing needs a separate key from mcp-key integrations, which holds only integrations:write. An admin who wants to both configure and start operations needs both keys. mcp-key list shows your active keys and mcp-key revoke <key-id> revokes one. See Members and roles for who counts as an admin.

Starting an operation

You start an operation from MCP, Slack or the API. All three create the same record.

SurfaceHow
MCPCall start_operation with kind and input.
SlackMessage @nima with agent spec <document-id> [repository-id], agent checks <repository-id> <branch> or agent task <repository-id> [base:<branch>] <instruction>. Ids are UUIDs. You can also ask nima's Slack assistant in plain words; it resolves the repository by name, starts one operation per request and publishes nothing unless you ask.
APIPOST /v1/operations, or POST /v1/documents/:id/dispatch as shorthand for implement_spec.

Details of each surface:

  • Scope: an MCP or API caller needs operations:write; a signed-in browser session skips the scope check. Slack needs no key, but the Slack user must be linked to an active member of the workspace, or the command is dropped without a reply.
  • Optional fields: target, publishPolicy, attempts (1 to 10, default 1), note (up to 20,000 characters), budget and idempotencyKey.
  • Attempts: attempts starts that many parallel operations and the response is an array of operations. The fleet caps it (3 by default), and a larger number is a 400.
  • Idempotency: repeat a call with the same idempotencyKey and nima returns the operation it already started. An implement_spec request without a key uses the spec id and version as its key, so dispatching the same spec version again returns the first operation; pass a new idempotencyKey to start another. Reusing a key for a different request, including another member's dispatch of the same spec version, is a 409. A Slack command uses the Slack message as its key, so a Slack retry never starts a second operation.
  • Budget: each budget field must stay within the workspace maximum. A larger value is a 400.
  • Slack limits: the command text is at most 1000 characters. A channel set to silent drops the command without a reply. Refusals such as an unapproved spec come back as a private message to the person who asked.

The full route and field reference is in Operations API, and the tools are in the operation tools reference.

Operation states

An operation moves through 14 states, and five of them are terminal.

GroupStates
Waiting and startingqueued, placing, hydrating
Workingactive
Pausingparking, parked, resuming
Finishingexporting, gating
Terminalpublished, reported, failed, cancelled, expired
  • published: nima pushed commits or opened a pull request.
  • reported: nima stored a report or posted a comment, with no code published.
  • failed: the operation stopped before a usable result. A denied admission also lands here.
  • cancelled: someone cancelled it.
  • expired: it stayed parked longer than the maximum parked time.

An own-harness operation only uses queued, active, reported and cancelled. A terminal operation accepts no further events. list_operations filters by a single state value.

Talking to a running operation

You can message, inspect, raise the limit of or cancel an operation while it runs. These calls need operations:write, except inspect_operation, which needs documents:read.

ActionMCP toolWhat it does
Messagemessage_operationSends a new user turn (1 to 100,000 characters) while the operation is active, hydrating, resuming or parked. It resumes a parked operation, except one paused for its budget or held by nima, which refuses the message with a 409.
Inspectinspect_operationQueues a request for the transcript or git_diff of a live VM. Accepted means queued, not run.
Raise a limitraise_operation_limitSets new absolute caps for aiUsd, activeMinutes or maxSessions. It never lowers a cap and cannot exceed the workspace maximum.
Cancelcancel_operationCancels the operation from any non-terminal state and revokes its run credentials.

Steer, park and resume exist over HTTP only (POST /v1/operations/:id/steer, /park, /resume), with no MCP tool. inspect_operation returns nothing to the caller and works only while the operation is active, exporting or gating.

Only the requester or a holder of operations:write can control an operation. For a task, only the requester can message or steer it, because those messages carry instruction authority. Another holder of operations:write can still cancel or park it.

Operation results and end reasons

Every finished operation records an endReason and an endDetail. The first line of endDetail is nima's own verdict. Text after the line Agent report: is the agent's own account and is untrusted.

endReasonMeaning
checks_passed, checks_failed, checks_timed_out, checks_not_runThe result of a run_checks or browser_check, taken from the test command's exit code: 0 passes, 124 times out, any other non-zero fails, and no command means not run
task_completedA task whose agent reported completion and whose export nima accepted
task_endedA task that ended without a completion report but whose export nima accepted
org_disabled, budget_exhausted, concurrency_limit, daily_limitAdmission denials for a VM operation. Each one is terminal, not queued
compute_disabledAn admin turned hosted compute off while the operation was live
gate_rejectednima's safety gate rejected the result. endDetail lists the rule codes

list_operations cuts endDetail to its first line. get_operation returns it in full (up to 8000 characters, redacted).

Read a task's result

get_operation_result returns a finished task's output: nima's own diff stat (up to 50 files) and a redacted, size-capped patch for display, not for applying. Only the requester or an owner or admin can call it, and it works only for task operations.

  • Size: maxPatchChars accepts 1000 to 120,000 and defaults to 20,000.
  • Missing patch: patchUnavailableReason says why, with values such as not_finished, no_changes, too_large and secret_suspected.
  • Retention: stored patches expire after 90 days.

Agent operations in Slack threads

An operation started from Slack reports back in the thread where you asked. nima posts one status message and edits it in place as the state changes, using plain wording such as "waiting to start", "preparing your workspace", "working" and "paused as requested".

  • Question: if the agent needs input, nima posts the question in the thread. When the requester replies, nima's Slack assistant passes the answer to the operation, which resumes if it was waiting.
  • Result: when the operation ends, nima posts exactly one reply that mentions the requester (edits do not notify). It carries nima's verdict, and for a task it also carries nima's diff stat and the agent's report, labelled as the agent's own account that nima did not verify.
  • Follow-ups: a reply in the thread from the requester goes to nima's Slack assistant, which can message or cancel the operation. It asks which operation you mean when "cancel that" is ambiguous. There is no literal cancel keyword.

Replies from other members also reach nima's Slack assistant, but the assistant reads, messages and cancels only the asker's own operations, so it cannot act on someone else's operation. Silent channels get none of these messages.

Who can see agent operations

Any member whose token holds documents:read sees every operation in the workspace: its state, budget, usage and endDetail. The exceptions are the handoff brief and handoff tools (requester only) and get_operation_result (requester, owner or admin).

Operations run inside one workspace. Reading an operation from another workspace returns 404; the handoff tools return 403 for any operation that is not your own own-harness handoff.

On this page