Learned Tool API

The /api/v1/tools API stores immutable artifacts, registers external executor profiles and records development/repair outcomes. A client can use ordinary HTTPS JSON requests without a compiler, model or local execution runtime. The database stores source and evidence; separately deployed workers generate and test code. These routes do not dispatch programs or publish executable releases.

Use http://localhost:7474 for local Docker. The interactive reference is /docs; OpenAPI describes every request and response. Requests require contract_version: 1, reject unknown fields and share the 65536-byte transport limit. Successful commands and reads return 200, including non-successful worker outcomes. Check the returned state and reason, not only HTTP status. Responses carry Cache-Control: no-store.

Credentials and routes#

Use Authorization: Bearer <credential>. The credential administrator issues separate credentials with explicit capabilities. Existing memory or procedural capabilities do not grant tool access. Bootstrap administrators can issue a tool_admin credential; bootstrap does not implicitly include that capability. Tenant and actor are derived from current credentials, never from request JSON.

Endpoint Capability and additional authority Response
POST /api/v1/tools/executors tool_admin executor
GET /api/v1/tools/executors/{id} tool_admin executor
POST /api/v1/tools/artifacts tool_develop, exact scope artifact
POST /api/v1/tools/artifacts/read tool_read, exact scope artifact
POST /api/v1/tools/development/requests tool_develop, exact scope original receipt
POST /api/v1/tools/development/read tool_read, exact scope current development
POST /api/v1/tools/development/commands with report tool_report, exact scope, registered executor subject original event
Same endpoint with request_cancellation tool_develop, exact scope, original requesting subject original event
POST /api/v1/tools/development/events/read tool_read, exact scope original event

Each response is an envelope with contract_version: 1 and the named field. Shared access requires the same exact grant in the same tenant. Private scope includes the authenticated subject, so a separate worker subject cannot report on another subject's private request. Use a shared scope with explicit grants for separate developer/worker identities. Revoked, rotated-old or expired secrets cannot authorize a later request. An operation already authorized may finish while revocation races with it.

Register an executor and request development#

An administrator posts this synthetic profile to /api/v1/tools/executors:

{
  "contract_version": 1,
  "profile": {
    "id": "worker-v1",
    "subject_id": "worker",
    "runtime_image_digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "environment_revision": "sandbox-v1",
    "permissions_revision": "no-network-v1",
    "max_cost_units": 100,
    "max_latency_ms": 60000
  }
}

Use a real immutable image digest in integration. Preserve the returned executor.profile_digest. Profile IDs are immutable within the tenant; changed content requires a new ID. Profiles contain no endpoints or worker passwords. They declare expected authority and execution context, not a sandbox attestation. Cost units must have a consistent deployment-defined meaning.

A developer posts this to /api/v1/tools/development/requests:

{
  "contract_version": 1,
  "scope": {"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},
  "request": {
    "id": "request-v1",
    "executor_id": "worker-v1",
    "objective": "Develop an identity tool and run its tests.",
    "parent_artifact_id": null,
    "repair_evidence_ref": null
  }
}

The receipt preserves the immutable request, request digest, executor profile digest, tenant/namespace, requesting actor and timestamp. Repeating the same request ID/content by the same subject returns the original receipt, even after completion. Changed content or a different requester conflicts. For a repair, both parent and evidence are required; the parent must exist in the same scope. External evidence references are preserved as declarations, without fetching them.

Creation records intent. It does not dispatch work. A configured worker is given the request ID and shared scope and reads the current state at /api/v1/tools/development/read:

{
  "contract_version": 1,
  "scope": {"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},
  "request_id": "request-v1"
}

Report a candidate or failure#

Post to /api/v1/tools/development/commands with the worker credential. Replace the zero-filled digest with the exact registered executor_profile_digest:

{
  "contract_version": 1,
  "scope": {"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},
  "request_id": "request-v1",
  "command": {
    "event_id": "tests-completed-v1",
    "expected_revision": 1,
    "action": {
      "type": "report",
      "report": {
        "executor_profile_digest": "0000000000000000000000000000000000000000000000000000000000000000",
        "outcome": "succeeded",
        "evidence_ref": "test-run-v1",
        "detail": "Identity cases passed in the configured worker.",
        "cost_units": 10,
        "latency_ms": 100,
        "artifact": {
          "id": "identity-v1",
          "source": "def run(value):\n    return value\n",
          "dependency_lock": "",
          "runtime_image_digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
          "entrypoint": "tool:run",
          "input_schema": true,
          "output_schema": true,
          "source_refs": ["development:request-v1"],
          "parent_artifact_id": null,
          "repair_evidence_ref": null
        }
      }
    }
  }
}

This is a payload example, not measured tool efficacy. Successful reports must match the bound runtime image, parent/evidence and development:<request ID> source reference. The artifact and resulting state are committed atomically with the event. Changed event retries conflict; identical retries return the original event snapshot and actor. Credential rotation is compatible when subject and grants stay the same. New commands require the latest revision.

For a failed or pending report, use outcome failed or pending_or_unknown, set artifact to null, and preserve a diagnostic evidence_ref/detail. Unknown accounting is null. A reported success with unknown accounting remains pending; a known budget violation becomes failure. Known cumulative accounting cannot decrease, including across unknown reports. observed_cost_units and observed_latency_ms retain known lower bounds while current consumption may be unknown. See the complete state contract.

Cancellation and immutable event reads#

The original requester can ask to cancel a nonterminal request:

{
  "contract_version": 1,
  "scope": {"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},
  "request_id": "request-v1",
  "command": {
    "event_id": "cancel-v1",
    "expected_revision": 1,
    "action": {"type":"request_cancellation","reason":"The mission ended."}
  }
}

State becomes cancellation_requested. Only a bound worker report with outcome cancelled confirms cancellation. A complete success can win the race before that confirmation. New commands after a terminal state conflict; old identical receipts remain replayable. No automatic redispatch occurs on timeout or restart.

Read an original receipt at /api/v1/tools/development/events/read:

{
  "contract_version": 1,
  "scope": {"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},
  "request_id": "request-v1",
  "event_id": "cancel-v1"
}

Direct artifacts and response fields#

To import source without claiming development success, post {contract_version, scope, artifact} to /api/v1/tools/artifacts, using the same artifact shape as the worker example. Read it with {contract_version, scope, artifact_id} at /api/v1/tools/artifacts/read.

Artifacts retain proposal, artifact_digest, exact source/dependency SHA-256 digests, actor, timestamp, tenant, namespace and schema version. Executor records retain profile, profile_digest and administrative provenance. Development state retains its original receipt, revision, state, reason, last_event_id, optional exact artifact ID/digest and nullable accounting. Events retain the complete command, reporting actor, resulting record, schema version and timestamp. An old event's snapshot may differ from current state; read the development record for the latest state.

The artifact contract lists byte limits and digest semantics. Objectives/details support 8192 bytes; evidence and cancellation reasons support 2048 bytes. Schemas are stored declarations, not compiled validators. Source, lock files and evidence must contain no credentials. A successful artifact is not automatically published or authorized for invocation.

Errors#

Status/code Meaning
400 invalid_request Unknown fields/version, invalid bounds or malformed report
401 unauthorized Invalid, expired, revoked or replaced bearer secret
403 forbidden Missing capability/grant or wrong requesting/executor subject
404 record_not_found Request, artifact, event or executor absent in authorized scope/tenant
409 revision_conflict A new command used a stale revision
409 idempotency_conflict Changed immutable content, mismatched runtime/provenance/profile, or invalid terminal transition
413 invalid_request Complete request body exceeds 65536 bytes
500 storage_inconsistency Stored identity, digest, state/event or artifact mismatch

Errors use {contract_version, error: {code, message}}. On an ambiguous transport failure, replay the identical request/event ID. Do not invent a new operation ID that could cause duplicate external work. The database's receipts coordinate worker evidence; workers still need their own durable execution identities, isolation and reconciliation protocol.