[ AxiomCore · Documentation ]
Semantic service protocol reference
The axiom-agent-semantic/v1 envelope, snapshots, the 17 operations with their params, results and errors, limits, and the apply and recovery rules.
acore-semantic speaks one protocol, axiom-agent-semantic/v1, over three
transports: MCP (acore-semantic mcp), JSON lines (acore-semantic serve) and
a one-shot command (acore-semantic --root <project> < request.json). The
operations, fields and errors are the same on all three.
The protocol is defined by JSON Schema (draft 2020-12) files, published on this site (see Schema files). The tables marked as generated on this page are produced from those schemas and from the service's capability manifest.
Schema files
Each schema is a static file under
https://docs.axiomcore.dev/semantic-service/schemas/.
index.json lists every file with its URL, $id and title.
| File | Defines |
|---|---|
envelope.request.json | Every request: the envelope fields each operation takes |
envelope.response.json | Every response, success or error |
error.json | The error object and its code vocabulary |
common.json | Ids, workspace and snapshot identity, node references, limits, truncation, coverage, diagnostics |
edits.json | Edit operations, edit options, id maps, relocations, candidates, checks |
operations/<operation>.request.json | The params of one operation (linked from each operation below) |
operations/<operation>.result.json | The result of one operation; x-errors lists its error codes |
Each file's $id has the form
https://schemas.axiomcore.dev/agent-semantic/v1/<file>. The $id is the
schema's identifier, not a download location: nothing is served at
schemas.axiomcore.dev. The files on this site are the authoritative,
published copies. References between files are relative (for example
../common.json#/$defs/path from operations/), and a validator resolves
them against the $id, not against the URL a file was downloaded from. A
validator that fetches references on demand therefore tries
schemas.axiomcore.dev and fails. To validate, either load all 39 schema
files into your validator first, so it finds each one by its $id, or
configure it to map https://schemas.axiomcore.dev/agent-semantic/v1/ to
https://docs.axiomcore.dev/semantic-service/schemas/.
Conventions
- Field names and enum values are
snake_case. Readers ignore fields they do not know; the service rejects unknown fields inside edit operations and apply preconditions, because ignoring a precondition could apply an edit you did not intend. - Paths are relative to the project root with
/separators, exceptworkspace.openroots, which are absolute. - SHA-256 values are lowercase hex. Timestamps are RFC 3339 with an offset.
Diagnostic
lineandcolumnstart at 1; lengths and columns count Unicode scalar values. - Over MCP each operation is a tool named with
_for.(node_find). The tool's arguments are the request envelope withoutprotocolandoperation; the server fillsworkspace. The tool result's structured content is the response envelope.
The examples on this page run in order against a project directory named
task-app whose page is like the quick start
example, with a query and a mutation of a backend contract tasks and a list
of tasks. It also has the contract and the UI lock the Axiom CLI produces, so
it shows the contract fields. Ids, versions and digests from your own project
differ.
module tasks.app.ui
use contract Tasks from "tasks" audience "mobile"
app TasksApp { route "/" => Home }
page Home {
state draft: String = ""
query tasks = Tasks.list_tasks()
mutation create = Tasks.create_task(title: draft)
action submit() {
create.run()
draft = ""
}
view {
View {
Input(value: draft, placeholder: "Add a task")
Button(label: "Add", on_press: submit)
if tasks.pending { Text("Loading...") }
else if tasks.error { Text("Could not load tasks") }
else { List(items: tasks.data, key: |task| task.id, list_type: "single", span_count: 1, scroll_orientation: "vertical") { task => Text(task.title) } }
}
}
}Values in angle brackets, such as <workspace>, stand for ids from earlier
responses. In responses, … marks text left out, including the end of long hashes.
Request envelope
{
"protocol": "axiom-agent-semantic/v1",
"operation": "node.find",
"workspace": "<workspace>",
"snapshot": "latest",
"limits": {"max_bytes": 65536},
"params": {"query": "Add", "limit": 10}
}| Field | Required | Type | Meaning |
|---|---|---|---|
protocol | yes | "axiom-agent-semantic/v1" | Always this value. |
operation | yes | capabilities, workspace.open, project.overview, node.find, node.get, node.edits, graph.query, context.build, impact.analyze, changes.since, node.relocate, change.propose, change.inspect, check.run, change.apply, change.discard, edit.plan | Every operation of v1. The capability manifest says which are implemented. |
workspace | no | string (at most 256 characters) | Opaque workspace handle returned by workspace.open. Scoped to the host process and caller. |
snapshot | no | string (at most 256 characters) | Read operations: the snapshot to read (id or latest). |
base_snapshot | no | string (at most 256 characters) | change.propose and edit.plan: the snapshot the edits are written against. Must be an id, not latest. |
request_id | no | string (at most 128 characters) | Caller-chosen idempotency key, scoped to workspace and caller. Bound to the request's input fingerprint. |
limits | no | object (limits) | Request limits. Omitted fields take the defaults the capability manifest lists. Bytes are authoritative; tokens are never a request limit. |
params | yes | object | Operation arguments; schemas/operations/<operation>.request.json. |
request_id is an idempotency key: the same request_id with the same input
returns the recorded result with replayed: true, and the same request_id
with different input is conflict (request_id_reused). Only edit and apply
operations record it; elsewhere it is echoed.
Which envelope fields each operation takes:
| Operation | workspace | snapshot | base_snapshot | request_id |
|---|---|---|---|---|
capabilities | not allowed | not allowed | not allowed | not allowed |
workspace.open | not allowed | optional | not allowed | not allowed |
project.overview | required | required | not allowed | optional |
node.find | required | required | not allowed | optional |
node.get | required | required | not allowed | optional |
node.edits | required | required | not allowed | optional |
graph.query | required | required | not allowed | optional |
context.build | required | required | not allowed | optional |
impact.analyze | required | required | not allowed | optional |
changes.since | required | required | not allowed | optional |
node.relocate | required | required | not allowed | optional |
change.propose | required | not allowed | required | required |
change.inspect | required | not allowed | not allowed | optional |
check.run | required | required unless params.candidate is given | not allowed | optional |
change.apply | required | not allowed | not allowed | required |
change.discard | required | not allowed | not allowed | optional |
edit.plan | required | not allowed | required | not allowed |
Response envelope
Every response, success or error, has these fields, and exactly one of
result and error:
| Field | Meaning |
|---|---|
protocol, operation | operation echoes the request. |
request_id | Present when the request had one. |
workspace | The workspace id, or null for capabilities and errors raised before a workspace was resolved. |
snapshot | The snapshot the answer describes (for an edit, its base; for a candidate, the candidate's snapshot with overlay set), or null. See Snapshots. |
toolchain | Compiler version and identity, edit rules identity, language_profile and target. |
coverage | completeness (complete, partial or unknown), exhaustive, and gaps, each with a reason. An empty answer proves absence only when exhaustive is true. |
truncation | truncated, the limits applied, bytes used, omissions (each with a reason, a count, up to 50 omitted node ids and expansion refs) and a continuation cursor or null. |
result | The operation's result. |
error | The error object. |
A response never silently drops content. When a limit cuts an answer,
truncation.truncated is true and omissions say what was left out.
max_bytes counts the UTF-8 bytes of the compact JSON of result.
Snapshots and workspaces
A workspace is one attached project root. workspace.open returns its
id; every later request except capabilities names it. The service serves
one root per process: the --root it was started with.
A snapshot is an immutable capture of the project's sources and inputs
(contracts and lock) under one compiler, language profile and target. Its id
is derived from its content. latest captures the files on disk now; the
response names the snapshot it used, so you can keep reading that exact
state. A snapshot's semantic_state says how far compilation got:
syntax: parsed onlyresolved: names resolved, not validatedvalidated: compiled without errorsunavailable: not even parsed
In this build unavailable means there is no node graph, which is not always
a parse failure: a project whose source parses but that lacks its UI lock is
also reported as unavailable (with status needs_preparation). On an
unavailable snapshot, node.find answers compile_failed, node.edits
answers compile_failed (not_validated), and project.overview still
returns the diagnostics.
A read on a syntax or resolved snapshot is partial with a
broken_source gap. Edits need a validated base, except bounded repairs:
an edit on a broken base is accepted when it leaves fewer errors and none
outside the declarations it changed.
When a file changes on disk after a snapshot was captured, reads of that
snapshot still describe the captured state and add snapshot.disk.state: changed with the changed paths. Read latest for the current files.
A node id names a node within one snapshot, for example
element:Home/view/0/1. Do not build or parse ids. To follow nodes to a
newer snapshot, use an edit's id_map, changes.since or node.relocate.
Every node carries a version, a fingerprint of its kind, name, file and
authored text; pass it as expected_node_version to refuse an edit if the
node changed.
A candidate is a proposed change: your operations applied to a private
copy of the base snapshot and compiled. It has an id and a version (1 when
created, increased each time you extend it) and is open, applied or
discarded. Only change.apply writes it to the project.
Operations
The 17 operations, in the order a client usually needs them. Each section lists the params and result fields generated from the schemas, then a real request and response.
- Session and discovery:
capabilities,workspace.open,project.overview - Reads:
node.find,node.get,node.edits,graph.query,context.build,impact.analyze,changes.since,node.relocate - Edits and publication:
edit.plan,change.propose,change.inspect,check.run,change.apply,change.discard
capabilities
The manifest of what this service serves: each operation and edit kind with
its status (implemented, partial or planned), profiles, checks, limits,
publication guarantees and error codes. Call it first, and use only what it
lists. It needs no workspace. acore-semantic --capabilities prints the same
manifest, plus toolchain, without a request (see the
quick start).
Params (schemas/operations/capabilities.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
profiles | no | array of string (at most 64 characters) | Restrict the manifest to these language profiles. |
Result (schemas/operations/capabilities.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
manifest | yes | object | The capability manifest: what this build serves. |
manifest_fingerprint | yes | string | Lowercase hex SHA-256 over a documented canonical input (node version, option fingerprint, input fingerprint). |
manifest fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
protocol | yes | object | Protocol name, status (frozen) and the frozen operations. |
service | yes | object | Service name and version. |
operations | yes | array of object | Every operation with its status (implemented, partial or planned) and the version that first served it. |
edit_kinds | yes | array of object | Every edit family with its status. |
profiles | yes | array of object | Supported language profiles, each with its status and targets. |
limits | yes | object | Request limit defaults and maximums, and the service bounds (see Limits). |
checks | no | array of object | Checks that check.run and change.apply accept, with their status. |
publication | yes | array of object | Publication profiles (local_filesystem) with their status and guarantees. |
error_codes | yes | array of unsupported_operation, invalid_arguments, ambiguous_owner, read_only_origin, stale_snapshot, precondition_failed, compile_failed, conflict, insufficient_context, snapshot_expired, permission_denied, resource_limit, not_found, internal | The error codes this build can return. |
external_writes | no | object | How the service detects writes by editors and tools it does not coordinate (external writers). |
Error codes: internal, unsupported_operation, invalid_arguments, resource_limit.
{"protocol": "axiom-agent-semantic/v1", "operation": "capabilities", "params": {}}{
"workspace": null,
"result": {
"manifest": {
"edit_kinds": [
{
"kind": "set_property",
"status": "implemented",
…
},
{
"kind": "bind_property",
"status": "implemented",
…
},
…
],
"operations": [
{
"name": "capabilities",
"status": "implemented",
…
},
{
"name": "workspace.open",
"status": "partial",
…
},
{
"name": "project.overview",
"status": "implemented",
…
},
…
],
"protocol": {
"name": "axiom-agent-semantic/v1",
"status": "frozen",
…
},
"service": {
"name": "acore-semantic",
"version": "0.1.4"
},
…
},
…
},
…
}workspace.open
Attaches the project root and captures a snapshot. Each project reports a
status: ready, needs_preparation (with preparation steps for you to run
with the Axiom CLI) or unsupported. The result also includes the
manifest. It never installs, extracts or runs anything.
Params (schemas/operations/workspace.open.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
roots | yes | array of object, 1 to 16 items | The project root, as {path} with an absolute path (entry may only be main.acore). This build accepts exactly one root, the one the process was started with. |
language_profile | no | string (at most 64 characters) | Language profile to open the project with. Only acore-ui is served; another value reports the project as unsupported. |
target | no | string (at most 64 characters) | Target to compile for. Only web is served; another value reports the project as unsupported. |
Result (schemas/operations/workspace.open.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
workspace | yes | object | The workspace: its id, its roots and where sources come from. |
projects | yes | array of object, 1 to any items | One entry per project: id (the root directory's name), entry, profile, target, status (ready, needs_preparation or unsupported), preparation steps and diagnostic counts. |
capabilities | yes | object (manifest) | The capability manifest, as capabilities returns it. |
workspace fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
id | yes | string (at most 256 characters) | Opaque workspace handle returned by workspace.open. Scoped to the host process and caller. |
roots | yes | array of object, 1 to any items | Each root with its root_id and canonical absolute path. |
source_authority | yes | local_filesystem | Where sources are read from: always the local filesystem. |
capabilities fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
protocol | yes | object | Protocol name, status (frozen) and the frozen operations. |
service | yes | object | Service name and version. |
operations | yes | array of object | Every operation with its status (implemented, partial or planned) and the version that first served it. |
edit_kinds | yes | array of object | Every edit family with its status. |
profiles | yes | array of object | Supported language profiles, each with its status and targets. |
limits | yes | object | Request limit defaults and maximums, and the service bounds (see Limits). |
checks | no | array of object | Checks that check.run and change.apply accept, with their status. |
publication | yes | array of object | Publication profiles (local_filesystem) with their status and guarantees. |
error_codes | yes | array of unsupported_operation, invalid_arguments, ambiguous_owner, read_only_origin, stale_snapshot, precondition_failed, compile_failed, conflict, insufficient_context, snapshot_expired, permission_denied, resource_limit, not_found, internal | The error codes this build can return. |
external_writes | no | object | How the service detects writes by editors and tools it does not coordinate (external writers). |
Error codes: invalid_arguments, not_found, permission_denied, resource_limit, internal, unsupported_operation, compile_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "workspace.open", "snapshot": "latest",
"params": {"roots": [{"path": "<project-path>"}]}}{
"operation": "workspace.open",
"workspace": "ws-…",
"snapshot": {
"id": "snap-8d409ade6cc9…",
"semantic_state": "validated",
…
},
"result": {
"projects": [
{
"project_id": "task-app",
"semantic_state": "validated",
"status": "ready",
…
}
],
"workspace": {
"id": "ws-…",
"source_authority": "local_filesystem",
…
},
…
},
…
}project.overview
Modules with their owners (pages and components), imports and diagnostic
counts, entry points, imported contracts and diagnostics. Every list is paged
by limits.max_items; pass truncation.continuation back as params.cursor
for the next page. The cursor stays on the same snapshot.
Params (schemas/operations/project.overview.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
projects | no | array of string (at most 128 characters) | Project ids to describe. Default: every project in the workspace (this build has one). |
include | no | array of modules, entry_points, contracts, diagnostics | Which lists to return. Default: all four. |
cursor | no | string (at most 1024 characters) | Opaque continuation token bound to one snapshot and one request shape. Valid until the snapshot expires. |
Result (schemas/operations/project.overview.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
projects | yes | array of object | Each project with its entry, profile, target, semantic state and diagnostic counts. |
modules | yes | array of object | Each module (source file) with its owners (pages and components), imports and error and warning counts. |
entry_points | yes | array of object (nodeSummary) | The pages the app's routes name, in route order. |
contracts | yes | array of object | Imported backend contracts: name, artifact path and SHA-256. |
diagnostics | yes | array of object, 0 to 200 items (diagnostics) | Compiler diagnostics, at most 200. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, stale_snapshot.
{"protocol": "axiom-agent-semantic/v1", "operation": "project.overview", "workspace": "<workspace>",
"snapshot": "<snapshot>", "params": {"include": ["entry_points", "contracts"]}}{
"snapshot": {
"id": "snap-8d409ade6cc9…",
…
},
"truncation": {
"truncated": false,
…
},
"result": {
"contracts": [
{
"name": "Tasks",
"node": "contract_import:Tasks",
"path": ".axiom/dev/contracts/tasks.axiom",
"sha256": "52cd75a52c98…"
}
],
"diagnostics": [],
"entry_points": [
{
"id": "page:Home",
"kind": "page",
"name": "Home",
"path": "main.acore",
"version": "7dd07ff0bbad…"
}
],
"modules": [],
"projects": [
{
"diagnostic_counts": {
"errors": 0,
"warnings": 1
},
"entry": "main.acore",
"language_profile": "acore-ui",
"project_id": "task-app",
"semantic_state": "validated",
"target": "web"
}
]
},
…
}node.find
Finds nodes by a case-insensitive substring of their name, id or a string
literal property value, with optional kind, owner and path filters.
Results are in document order, not ranked. More matches than limit are
reported as an omission: narrow the query.
Params (schemas/operations/node.find.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
query | yes | string (at most 200 characters) | Trimmed, case-insensitive substring of name, id, or a string-literal property value. Empty matches every node. |
kind | no | string (at most 64 characters) | Exact kind filter; an unknown kind matches nothing. |
owner | no | string (at most 1024 characters) | Only nodes owned (transitively) by this page or component. |
path | no | string (at most 1024 characters) | Only nodes whose authored declaration is in this file. |
limit | yes | integer (1..50) | Maximum number of nodes to return (1 to 50). More matches are reported as an omission; narrow the query. |
Result (schemas/operations/node.find.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
nodes | yes | array of object (nodeSummary) | Matching nodes, each with id, kind, name, file and version. |
matches | no | array of object | One entry per node, same order: why it matched. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, stale_snapshot, compile_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "node.find", "workspace": "<workspace>",
"snapshot": "<snapshot>", "params": {"query": "Add", "kind": "element", "limit": 10}}{
"coverage": {
"completeness": "complete",
"exhaustive": true,
"gaps": []
},
"result": {
"matches": [
{
"node": "element:Home/view/0/0",
"reasons": [
"property_value"
]
},
{
"node": "element:Home/view/0/1",
"reasons": [
"property_value"
]
}
],
"nodes": [
{
"id": "element:Home/view/0/0",
"kind": "element",
"name": "Input",
"path": "main.acore",
"version": "47220ffb7c58…"
},
{
"id": "element:Home/view/0/1",
"kind": "element",
"name": "Button",
"path": "main.acore",
"version": "24495d3190bd…"
}
]
},
…
}node.get
Properties, edges, source and an edit summary for up to 50 node ids.
projection (summary, standard, full) and include choose the parts.
Over max_bytes, optional parts are dropped and listed as an omission with
expansion refs.
Params (schemas/operations/node.get.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
nodes | yes | array of string (at most 1024 characters), 1 to 50 items | Node ids to read (1 to 50). |
projection | no | summary, standard, full | Preset. summary: node only. standard (default): properties and edges. full: also body and provenance. |
include | no | array of properties, edges, incoming, body, provenance, edits | Adds to the preset. |
limit | no | integer (1..200) | Caps properties and edges per node independently. |
Result (schemas/operations/node.get.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
nodes | yes | array of object | One entry per requested id: the node with the parts requested (properties, edges, body, provenance, edit summary). |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, stale_snapshot, compile_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "node.get", "workspace": "<workspace>",
"snapshot": "<snapshot>", "params": {"nodes": ["element:Home/view/0/1"]}}{
"result": {
"nodes": [
{
"edges": [
{
"direction": "outgoing",
"kind": "child_of",
"layer": "declared",
"node": "element:Home/view/0"
},
{
"direction": "outgoing",
"kind": "triggers",
"layer": "resolved",
"node": "action:Home.submit"
}
],
"node": {
"id": "element:Home/view/0/1",
"kind": "element",
"name": "Button",
"path": "main.acore",
"version": "24495d3190bd…"
},
"properties": [
{
"editable": true,
"name": "label",
"type": "String",
"value": "Add"
},
{
"editable": false,
"name": "on_press",
"type": "Action",
"value": "submit"
}
]
}
]
},
…
}node.edits
The edits each node accepts now. Every option has an option_id and a
fingerprint bound to the snapshot, the node version and the edit rules;
cite it in change.propose as option and a stale option is refused.
An edit that is not offered is not legal; include_unavailable: true lists
what is not offered.
Params (schemas/operations/node.edits.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
nodes | yes | array of string (at most 1024 characters), 1 to 20 items | Node ids to ask about (1 to 20). |
kinds | no | array of set_property, bind_property, list_element, declaration, set_reference, import, replace_region | Only list options of these edit families. Default: every family. |
include_unavailable | no | boolean | Also list the edit families that are not offered for the node. The service does not say why. |
Result (schemas/operations/node.edits.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
nodes | yes | array of object | Per node: its id, node_version, the legal options (each with option_id and fingerprint) and, if asked, the families not offered. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, stale_snapshot, compile_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "node.edits", "workspace": "<workspace>",
"snapshot": "<snapshot>", "params": {"nodes": ["element:Home/view/0/1"], "include_unavailable": true}}{
"result": {
"nodes": [
{
"node": "element:Home/view/0/1",
"node_version": "24495d3190bd…",
"options": [
{
"accepts": "String",
"fingerprint": "8433d5033595…",
"kind": "set_property",
"option_id": "o1",
"property": "label"
},
{
"accepts": "String",
"fingerprint": "0777d73f1904…",
"kind": "bind_property",
"option_id": "o2",
"property": "label",
"states": [
"state:Home.draft"
]
},
{
"accepts": "Element",
"fingerprint": "b35723f8087a…",
"kind": "list_element",
"ops": [
"remove",
"insert"
],
"option_id": "o3",
"text": "Button(label: \"Add\", on_press: submit)"
}
],
"unavailable": [
{
"code": "unsupported_operation",
"kind": "declaration",
"reason": "declaration is not offered for this node; acore does not report why"
},
{
"code": "unsupported_operation",
"kind": "set_reference",
"reason": "set_reference is not offered for this node; acore does not report why"
},
{
"code": "unsupported_operation",
"kind": "import",
"reason": "import is not offered for this node; acore does not report why"
}
]
}
]
},
…
}graph.query
Relationships from compiler facts: dependencies (outgoing), dependents
(incoming), references (incoming use sites) or paths (from from to
to). Each edge has a kind (reads, writes, triggers and others), a
layer (declared or resolved) and a source site. Edges to code the
compiler cannot see, such as foreign extension actions, are reported as
boundaries with partial coverage.
Params (schemas/operations/graph.query.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
from | yes | array of string (at most 1024 characters), 1 to 20 items | Start node ids (1 to 20). |
mode | yes | dependencies, dependents, references, paths | dependencies: outgoing; dependents: incoming; references: incoming use sites; paths: connecting paths from -> to. |
to | no | array of string (at most 1024 characters), 1 to 20 items | For mode: paths: the end node ids (1 to 20). |
edge_kinds | no | array of string | Restrict to these relations. Omitted: the profile's default dependency relations, disclosed in result.traversed. |
layers | no | array of declared, resolved, observed | Fact layers to follow. This build has declared and resolved facts only. |
transitive | no | boolean | Follow relationships beyond the first step, up to limits.max_depth. |
Result (schemas/operations/graph.query.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
traversed | yes | object | What was followed: direction, edge kinds and layers. |
nodes | yes | array of object (nodeSummary) | Summaries of the nodes the answer mentions. |
edges | yes | array of object | Each relationship found: from, kind, to, layer, depth and source site. |
paths | no | array of object | For mode: paths: each path as a list of node ids. |
boundaries | yes | array of object | Where the walk met something it cannot see through (foreign implementation, unresolved reference). Not an empty dependency set. |
traversed fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
direction | yes | outgoing, incoming, both | outgoing, incoming or both. |
edge_kinds | yes | array of string | Edge kinds that were followed. |
layers | yes | array of declared, resolved, observed | Fact layers that were followed. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, stale_snapshot, compile_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "graph.query", "workspace": "<workspace>",
"snapshot": "<snapshot>", "params": {"from": ["state:Home.draft"], "mode": "dependents"}}{
"result": {
"edges": [
{
"depth": 1,
"from": "mutation:Home.create",
"kind": "reads",
"layer": "resolved",
"site": {
"column": 12,
"line": 10,
"path": "main.acore"
},
"to": "state:Home.draft"
},
{
"depth": 1,
"from": "element:Home/view/0/0",
"kind": "reads",
"layer": "resolved",
"site": {
"column": 7,
"line": 19,
"path": "main.acore"
},
"to": "state:Home.draft"
},
…
],
"traversed": {
"direction": "incoming",
"edge_kinds": [
"reads",
"writes",
"triggers",
"calls",
"invokes",
"navigates_to"
],
"layers": [
"declared",
"resolved"
]
},
…
},
…
}context.build
A bounded slice of the project for a task. purpose selects a fixed recipe
(understand, change_input, change_behavior, diagnose); each item says
why it is included and whether it is required. Required context is never
cut: if it does not fit in max_bytes the answer is insufficient_context
with the bytes it needs and refs you can pass in expand.
Params (schemas/operations/context.build.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
focus | yes | array of string (at most 1024 characters), 1 to 20 items | Node ids the task is about (1 to 20). |
purpose | yes | understand, change_input, change_behavior, change_schema, diagnose | The recipe that chooses what to include. change_schema needs a backend profile and answers unsupported_operation in this profile. |
include | no | array of signature, implementation, input_constraints, callers, consumers, authorization, diagnostics, tests | Kinds of context to add. tests and authorization produce coverage gaps in this profile. |
expand | no | array of string (at most 512 characters), 0 to 50 items | ExpansionRef.ref values from an earlier response on the same snapshot. |
Result (schemas/operations/context.build.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
items | yes | array of object | Each included node with its depth from the focus, whether it is required, and why it is included. |
edges | yes | array of object | Relationships between the included nodes. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, stale_snapshot, compile_failed, insufficient_context.
{"protocol": "axiom-agent-semantic/v1", "operation": "context.build", "workspace": "<workspace>",
"snapshot": "<snapshot>", "limits": {"max_bytes": 4096},
"params": {"focus": ["element:Home/view/0/1"], "purpose": "change_input"}}{
"truncation": {
"truncated": false,
"used": {
"bytes": 1693
},
…
},
"result": {
"items": [
{
"node": {
"id": "element:Home/view/0/1",
…
},
"reasons": [
{
"kind": "focus",
"text": "element:Home/view/0/1: focus of change_input"
}
],
"required": true,
"signature": "Button(label: \"Add\", on_press: submit)",
…
},
{
"node": {
"id": "action:Home.submit",
…
},
"reasons": [
{
"kind": "signature",
"text": "action:Home.submit: element:Home/view/0/1 triggers it",
"via": "element:Home/view/0/1"
}
],
"required": false,
"signature": "submit()",
…
},
…
],
…
},
…
}With a limit smaller than the required context:
{"protocol": "axiom-agent-semantic/v1", "operation": "context.build", "workspace": "<workspace>",
"snapshot": "<snapshot>", "limits": {"max_bytes": 256},
"params": {"focus": ["page:Home"], "purpose": "understand"}}{
"error": {
"code": "insufficient_context",
"message": "the required context of understand on page:Home is 294 bytes, more than limits.max_bytes (256); it is never cut. Repeat with limits.max_bytes of at least 294 (and max_nodes of at least 1), a narrower include, or fewer focus nodes",
"target": {
"nodes": [
"page:Home"
]
},
"diagnostics": [],
"retryable": "none",
"next_actions": [
{
"operation": "context.build",
"reason": "Repeat with limits.max_bytes of at least details.required_bytes, or a narrower include"
}
],
"details": {
"expand": [
{
"estimated_bytes": 272,
"kind": "node",
"node": "page:Home",
"reason": "the item page:Home (required context); pass this ref in params.expand to include it as required",
"ref": "ctx1:8d409ade6cc951e0:node:page:Home"
}
],
"required_bytes": 294,
"required_items": 1
}
},
…
}impact.analyze
Everything that depends on the targets, transitively up to limits.max_depth
levels, with the edge that links each impacted node.
Params (schemas/operations/impact.analyze.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
targets | yes | array of string (at most 1024 characters), 1 to 20 items | Node ids to analyse (1 to 20). |
direction | yes | dependents, dependencies, both | dependents (what a change would affect), dependencies, or both. |
edge_kinds | no | array of string | Only follow these edge kinds. Default: all. |
Result (schemas/operations/impact.analyze.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
impacted | yes | array of object | Each affected node with its depth, the node it was reached from, the edge kind and the layer. |
tests | no | array of object | Test associations. Not returned by this build (no test associations in this profile). |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, stale_snapshot, compile_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "impact.analyze", "workspace": "<workspace>",
"snapshot": "<snapshot>", "params": {"targets": ["state:Home.draft"], "direction": "dependents"}}{
"result": {
"impacted": [
{
"depth": 1,
"edge_kind": "reads",
"from": "state:Home.draft",
"node": {
"id": "mutation:Home.create",
…
},
…
},
{
"depth": 1,
"edge_kind": "reads",
"from": "state:Home.draft",
"node": {
"id": "element:Home/view/0/0",
…
},
…
},
{
"depth": 1,
"edge_kind": "writes",
"from": "state:Home.draft",
"node": {
"id": "action:Home.submit",
…
},
…
},
{
"depth": 2,
"edge_kind": "triggers",
"from": "action:Home.submit",
"node": {
"id": "element:Home/view/0/1",
…
},
…
}
]
},
…
}edit.plan
A dry run of change.propose: the same operations, checked by the same
rules, returning the owners, files and required checks. It stores nothing and
takes no request_id.
Params (schemas/operations/edit.plan.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
operations | yes | array of object or object or object or object or object or object or object or object or object or object or object, 1 to 50 items | Edit operations (1 to 50), as for change.propose. |
Result (schemas/operations/edit.plan.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
outcome | yes | supported, required_but_missing, unsupported | supported; unsupported when an operation is refused as not offered (see reason); required_but_missing when the batch needs an edit family this build does not implement. |
reason | no | string (at most 2000 characters) | Why the outcome is not supported. |
owners | yes | array of object | Pages and components the batch changes, with their files. |
operations | yes | array of object | Per operation: index, kind, file and outcome. |
id_map | no | array of object (idMap) | Optional: the id_map change.propose would return, composed over the batch from base_snapshot; present when the outcome is supported. |
files | yes | array of string (at most 1024 characters) | Files the batch would change. |
required_checks | no | array of string (at most 64 characters) | Checks a candidate of this batch would need to pass. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, stale_snapshot, snapshot_expired, precondition_failed, ambiguous_owner, read_only_origin, compile_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "edit.plan", "workspace": "<workspace>",
"base_snapshot": "<snapshot>",
"params": {"operations": [{"kind": "set_property", "node": "element:Home/view/0/1", "property": "label",
"old_value": "Add", "new_value": "Add task"}]}}{
"result": {
"files": [
"main.acore"
],
"id_map": [],
"operations": [
{
"index": 0,
"kind": "set_property",
"node": "element:Home/view/0/1",
"outcome": "supported",
"path": "main.acore",
"property": "label"
}
],
"outcome": "supported",
"owners": [
{
"kind": "page",
"node": "page:Home",
"path": "main.acore"
}
],
"required_checks": [
"compile"
]
},
…
}change.propose
Applies 1 to 50 edit operations, in order, to a private copy of
base_snapshot, compiles the result and returns a candidate. The batch is
all or nothing: each operation sees the result of the ones before it, only the
final state must compile, and on failure nothing is created and
operation_index names the operation. An operation can name what it creates
with handle, and a later operation refers to it as {"handle": "<name>"}.
To extend an open candidate, pass candidate and expected_candidate_version.
Params (schemas/operations/change.propose.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
candidate | no | string (at most 256 characters) | Extend this open candidate instead of starting one. Its base must equal base_snapshot. |
expected_candidate_version | no | integer (1..) | Required with candidate. |
operations | yes | array of object or object or object or object or object or object or object or object or object or object or object, 1 to 50 items | Edit operations (1 to 50), applied in order, all or nothing. Each kind of operation is described after the error codes of this section. |
checks | no | array of string (at most 64 characters) | Checks to run on the final candidate before returning; compile always runs. |
Result (schemas/operations/change.propose.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
candidate | yes | object (candidate) | The candidate: id, version, state, base snapshot, candidate snapshot, request_id and input fingerprint. |
replayed | yes | boolean | true when this answer is the recorded result of an earlier identical request. |
operations | yes | array of object (operationOutcome), 1 to any items | Per operation: index, kind, outcome, created node and its own id_map. |
id_map | yes | array of object (idMap) | Composed over the batch, from base_snapshot (or the previous candidate version) to this version. |
files | yes | array of object (fileChange), 1 to any items | Files the candidate changes, with SHA-256 before and after. |
diagnostics | yes | array of object, 0 to 200 items (diagnostics) | Diagnostics of the candidate's compile, at most 200. |
checks | yes | array of object (checkResult), 1 to any items | Result of each check run on the candidate. |
evidence | yes | object (evidence) | Evidence of a compile. (compiler_identity, target, sources, dependencies_fingerprint) is the reuse key of a check. |
impact | no | object | Nodes the change affects. |
repair | no | object (repairOutcome) | Present when the base is not validated (syntax or resolved): the accepted repair's base and result states and error counts. |
candidate fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
id | yes | string (at most 256 characters) | Opaque id of a private candidate (change.propose). |
version | yes | integer (1..) | Increases with every successful change.propose on the candidate. |
state | yes | open, applied, discarded, expired | The candidate's state: open, applied, discarded or expired. |
base_snapshot | yes | string (at most 256 characters) | Opaque id of one immutable captured snapshot. Never the reserved word latest. |
snapshot | yes | string (at most 256 characters) | Snapshot id of base plus overlay; readable by the owning caller. |
request_id | yes | string (at most 128 characters) | The request_id of the change.propose that produced this version. |
input_fingerprint | yes | string | Lowercase hex SHA-256 over a documented canonical input (node version, option fingerprint, input fingerprint). |
expires_at | no | string | RFC 3339 with an explicit offset, uppercase T and Z. |
evidence fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
toolchain | yes | object (toolchain) | The compiler identity the candidate was checked with. |
inputs | yes | object | The inputs the compile read, with their digests. |
impact fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
nodes | yes | array of string (at most 1024 characters), 0 to 200 items | Affected node ids, at most 200. |
more | no | boolean | true when more nodes are affected than listed. |
repair fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
base_state | yes | syntax, resolved, validated, unavailable | How far the snapshot got: syntax (parsed only), resolved (names resolved, not validated), validated (compiled without errors), unavailable (not even parsed). |
base_errors | yes | integer (0..) | Number of error diagnostics in the base snapshot. |
result_state | yes | syntax, resolved, validated, unavailable | How far the snapshot got: syntax (parsed only), resolved (names resolved, not validated), validated (compiled without errors), unavailable (not even parsed). |
result_errors | yes | integer (0..) | Number of error diagnostics after the repair. |
touched | yes | array of string (at most 1024 characters), 0 to 50 items | Declarations the candidate changed, as <path>: <kind> <name>. |
regressed | no | array of string (at most 1024 characters), 0 to 50 items | In a refusal's details only: declarations that gained errors outside the broken ones the candidate changed. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, stale_snapshot, snapshot_expired, precondition_failed, ambiguous_owner, read_only_origin, compile_failed, conflict.
The edit operations (generated from edits.json). Every operation carries
an exact precondition, old_value or old_text, copied from node.get or
node.edits:
set_property: Set one authored literal scalar.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "set_property" | Always this value. |
node | yes | string (at most 1024 characters) or object | A node id of the base snapshot, or {handle} naming a node an earlier operation of the same batch created. |
property | yes | string (at most 256 characters) | Name of the property to set, as node.edits lists it. |
old_value | yes | any JSON value | Exact precondition, as node.get returned it. |
new_value | yes | any JSON value | Any JSON value, including null. |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
bind_property: Bind one authored property to a state of the same owner.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "bind_property" | Always this value. |
node | yes | string (at most 1024 characters) or object | A node id of the base snapshot, or {handle} naming a node an earlier operation of the same batch created. |
property | yes | string (at most 256 characters) | Name of the property to bind. |
old_value | yes | any JSON value | Any JSON value, including null. |
target | yes | string (at most 1024 characters) or object | A state node of the element's owner. |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
list_element, op: remove: Remove one element or conditional from a view children list.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "list_element" | Always this value. |
op | yes | "remove" | Always this value. |
node | yes | string (at most 1024 characters) or object | A node id of the base snapshot, or {handle} naming a node an earlier operation of the same batch created. |
old_text | yes | string (at most 4096 characters) | Exact tight-span text (node.edits option text). |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
list_element, op: insert: Insert one view element before or after an anchor.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "list_element" | Always this value. |
op | yes | "insert" | Always this value. |
anchor | yes | string (at most 1024 characters) or object | A node id of the base snapshot, or {handle} naming a node an earlier operation of the same batch created. |
position | yes | before, after | Insert before or after the anchor. |
old_text | yes | string (at most 4096 characters) | The anchor's exact current text, from its node.edits option. |
element | yes | string (at most 16384 characters) | Source of one view element, no indentation on its first line. |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
declaration, op: create: Create a state or action in a page or component.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "declaration" | Always this value. |
op | yes | "create" | Always this value. |
anchor | yes | string (at most 1024 characters) or object | A node id of the base snapshot, or {handle} naming a node an earlier operation of the same batch created. |
position | yes | before, after, first | before or after the anchor, or first in the owner. |
old_text | yes | string (at most 4096 characters) | The anchor's tight text, or the owner's header line for position first. |
declaration | yes | string (at most 20000 characters) | Source of the new state or action declaration (at most 20,000 characters). |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
declaration, op: update: Replace a state or action declaration, keeping kind and name.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "declaration" | Always this value. |
op | yes | "update" | Always this value. |
node | yes | string (at most 1024 characters) or object | A node id of the base snapshot, or {handle} naming a node an earlier operation of the same batch created. |
old_text | yes | string (at most 20000 characters) | The declaration's exact current text. |
declaration | yes | string (at most 20000 characters) | The replacement source of the whole declaration. |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
declaration, op: remove: Remove an unreferenced state or action.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "declaration" | Always this value. |
op | yes | "remove" | Always this value. |
node | yes | string (at most 1024 characters) or object | A node id of the base snapshot, or {handle} naming a node an earlier operation of the same batch created. |
old_text | yes | string (at most 20000 characters) | The declaration's exact current text. |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
set_reference: Point an on_* handler at another action of the same owner.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "set_reference" | Always this value. |
node | yes | string (at most 1024 characters) or object | A node id of the base snapshot, or {handle} naming a node an earlier operation of the same batch created. |
property | yes | string (at most 256 characters) | Name of the handler property, such as on_press. |
old_value | yes | string (at most 256 characters) | The current action identifier. |
target | yes | string (at most 1024 characters) or object | A node id of the base snapshot, or {handle} naming a node an earlier operation of the same batch created. |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
import, op: add: Add one use line to a file.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "import" | Always this value. |
op | yes | "add" | Always this value. |
path | yes | string (at most 1024 characters) | Project-relative file path: forward slashes, no leading slash, no empty, . or .. segment, no backslash or control character. |
import_kind | yes | component, model | What the use line imports: component or model. |
symbol | yes | string (at most 256 characters) | Name of the component or model to import. |
from | yes | string (at most 1024 characters) | Relative path of the module that exports symbol. |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
import, op: remove: Remove one use line whose symbol the file no longer references.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "import" | Always this value. |
op | yes | "remove" | Always this value. |
path | yes | string (at most 1024 characters) | Project-relative file path: forward slashes, no leading slash, no empty, . or .. segment, no backslash or control character. |
symbol | yes | string (at most 256 characters) | Name of the imported component or model to remove. |
old_text | yes | string (at most 1024 characters) | The exact use line. |
handle | no | string | Names this operation's created node for later operations in the same batch (intra-batch handle). |
expected_node_version | no | string | Optional precondition: the node's version from node.get or node.edits. |
option | no | object (optionRef) | Optional: the option_id and fingerprint of the matching node.edits option. A fingerprint that no longer matches is precondition_failed (option_stale). |
replace_region: Fallback: replace the smallest whole-line region around a syntax error, offered by node.edits only on a syntax snapshot. The only operation of its batch (invalid_arguments, region_alone, otherwise); never a whole file.
| Field | Required | Type | Meaning |
|---|---|---|---|
kind | yes | "replace_region" | Always this value. |
path | yes | string (at most 1024 characters) | Project-relative file path: forward slashes, no leading slash, no empty, . or .. segment, no backslash or control character. |
start_line | yes | integer (1..) | 1-based first line of the region. |
end_line | yes | integer (1..) | 1-based last line of the region (inclusive); at most 200 lines in all. |
old_text | yes | string (at most 16384 characters) | The region's exact text (node.edits option region.old_text): lines start_line..=end_line without the last newline. |
new_text | yes | string (at most 16384 characters) | Replaces exactly the region's bytes; at most 200 lines and 16384 bytes (empty removes the lines' text). |
option | yes | object (optionRef) | Required: the region option (option_id r<N> and fingerprint) node.edits offered on this snapshot. |
A proposal whose old_value is not the current value:
{"protocol": "axiom-agent-semantic/v1", "operation": "change.propose", "workspace": "<workspace>",
"base_snapshot": "<snapshot>", "request_id": "rename-add-0",
"params": {"operations": [{"kind": "set_property", "node": "element:Home/view/0/1", "property": "label",
"old_value": "Create", "new_value": "Add task"}]}}{
"error": {
"code": "precondition_failed",
"reason": "old_value_mismatch",
"message": "label is \"Add\", expected \"Create\"",
"operation_index": 0,
"target": {
"node": "element:Home/view/0/1",
"property": "label"
},
"diagnostics": [],
"retryable": "after_refresh",
"next_actions": [
{
"operation": "node.get",
"reason": "Re-read the node and rebuild the operation"
}
]
},
…
}With the current value:
{"protocol": "axiom-agent-semantic/v1", "operation": "change.propose", "workspace": "<workspace>",
"base_snapshot": "<snapshot>", "request_id": "rename-add-1",
"params": {"operations": [{"kind": "set_property", "node": "element:Home/view/0/1", "property": "label",
"old_value": "Add", "new_value": "Add task"}]}}{
"request_id": "rename-add-1",
"result": {
"candidate": {
"id": "cand-…",
"state": "open",
"version": 1,
…
},
"checks": [
{
"check": "compile",
"status": "passed",
…
}
],
"files": [
{
"after_sha256": "6fa9d35dbcf8…",
"before_sha256": "c7ac07a1c507…",
"change": "modified",
"path": "main.acore"
}
],
"id_map": [],
"operations": [
{
"id_map": [],
"index": 0,
"kind": "set_property"
}
],
"replayed": false,
…
},
…
}The same request_id with a different input:
{"protocol": "axiom-agent-semantic/v1", "operation": "change.propose", "workspace": "<workspace>",
"base_snapshot": "<snapshot>", "request_id": "rename-add-1",
"params": {"operations": [{"kind": "set_property", "node": "element:Home/view/0/1", "property": "label",
"old_value": "Add", "new_value": "Add a task"}]}}{
"error": {
"code": "conflict",
"reason": "request_id_reused",
"message": "request_id rename-add-1 was used for a different request (…); use a new request_id",
"target": {
"request_id": "rename-add-1"
},
"diagnostics": [],
"retryable": "none",
"next_actions": []
},
…
}change.inspect
What a candidate changes: a semantic diff (each changed node and property,
with expected: false for a change no operation asked for), a source diff or
full content, affected nodes, risks and checks.
Params (schemas/operations/change.inspect.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
candidate | yes | string (at most 256 characters) | Opaque id of a private candidate (change.propose). |
include | no | array of semantic_diff, source_diff, content, affected, checks | Which parts to return: semantic_diff, source_diff, content (full file content), affected, checks. |
Result (schemas/operations/change.inspect.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
candidate | yes | object (candidate) | The candidate: id, version, state, snapshots, request_id and input fingerprint. |
files | yes | array of object (fileChange), 1 to any items | Files the candidate changes, with SHA-256 before and after. |
semantic_diff | no | array of object | Each changed node: added, removed, modified or relocated, with property values before and after, and whether an operation asked for it (expected). |
source_diff | no | array of object | Per file, the changed lines as hunks. Bounded in size. |
affected | no | array of object (nodeSummary) | Summaries of the nodes the change affects. |
risks | no | array of object | Things to review, each with a kind, a detail and optionally a node. |
checks | no | array of object (checkResult) | Result of each check on the candidate's current version. |
candidate fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
id | yes | string (at most 256 characters) | Opaque id of a private candidate (change.propose). |
version | yes | integer (1..) | Increases with every successful change.propose on the candidate. |
state | yes | open, applied, discarded, expired | The candidate's state: open, applied, discarded or expired. |
base_snapshot | yes | string (at most 256 characters) | Opaque id of one immutable captured snapshot. Never the reserved word latest. |
snapshot | yes | string (at most 256 characters) | Snapshot id of base plus overlay; readable by the owning caller. |
request_id | yes | string (at most 128 characters) | The request_id of the change.propose that produced this version. |
input_fingerprint | yes | string | Lowercase hex SHA-256 over a documented canonical input (node version, option fingerprint, input fingerprint). |
expires_at | no | string | RFC 3339 with an explicit offset, uppercase T and Z. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired.
{"protocol": "axiom-agent-semantic/v1", "operation": "change.inspect", "workspace": "<workspace>",
"params": {"candidate": "<candidate>", "include": ["semantic_diff", "source_diff"]}}{
"snapshot": {
"id": "snap-2d2c561be58b…",
"overlay": "cand-…",
…
},
"result": {
"semantic_diff": [
{
"change": "modified",
"expected": true,
"node": "element:Home/view/0/1",
"properties": [
{
"after": "Add task",
"before": "Add",
"name": "label"
}
]
}
],
"source_diff": [
{
"hunks": [
{
"lines": [
" view {",
" View {",
" Input(value: draft, placeholder: \"Add a task\")",
"+ Button(label: \"Add task\", on_press: submit)",
"- Button(label: \"Add\", on_press: submit)",
" ",
" if tasks.pending { Text(\"Loading...\") }",
" else if tasks.error { Text(\"Could not load tasks\") }"
],
"old_start": 17,
…
}
],
"path": "main.acore"
}
],
…
},
…
}check.run
Runs checks on a candidate, or on a snapshot plus unsaved file contents
(files, each with the SHA-256 of the file it replaces). The checks are
compile and, on a broken base, repair. A failed check is a result with
ok: false, never an error.
Params (schemas/operations/check.run.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
candidate | no | string (at most 256 characters) | Opaque id of a private candidate (change.propose). |
files | no | array of object (file), 0 to 64 items | Overlay files; only with the envelope snapshot. [] checks the snapshot as is. |
checks | yes | array of string (at most 64 characters), 1 to any items | Checks to run: compile or repair. |
Result (schemas/operations/check.run.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
ok | yes | boolean | True when every requested check passed. |
candidate | no | string (at most 256 characters) | Opaque id of a private candidate (change.propose). |
checks | yes | array of object (checkResult), 1 to any items | One result per check: passed, failed, not_run or unavailable, with diagnostics. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, stale_snapshot, snapshot_expired.
{"protocol": "axiom-agent-semantic/v1", "operation": "check.run", "workspace": "<workspace>",
"params": {"candidate": "<candidate>", "checks": ["compile"]}}{
"result": {
"candidate": "cand-…",
"checks": [
{
"check": "compile",
"diagnostics": [
{
"column": 26,
"line": 3,
"message": "development contract `tasks` uses an unsigned local artifact; a production release requires Axiom Cloud signing",
"path": "main.acore",
"severity": "warning"
}
],
"status": "passed",
…
}
],
"ok": true
},
…
}To compile the files on disk now, name a snapshot and pass no files:
{"protocol": "axiom-agent-semantic/v1", "operation": "check.run", "workspace": "<workspace>",
"snapshot": "latest", "params": {"files": [], "checks": ["compile"]}}change.apply
Writes a candidate to the project and returns a receipt. It first rechecks the candidate version, the required checks and that every file it writes still has the base content. See Apply, receipts and recovery.
Params (schemas/operations/change.apply.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
candidate | yes | string (at most 256 characters) | Opaque id of a private candidate (change.propose). |
expected_candidate_version | yes | integer (1..) | The candidate version you reviewed. Another version is precondition_failed (candidate_version_mismatch). |
preconditions | no | array of object, 1 to any items | Explicit content preconditions (sha256 null: the file must not exist). Must include every written file when given. |
require_checks | no | array of string (at most 64 characters) | Checks that must have passed on this exact candidate version. |
Result (schemas/operations/change.apply.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
replayed | yes | boolean | True when this is the recorded receipt of an earlier identical request. |
receipt | yes | object | The receipt: what was written (see Apply, receipts and recovery). |
base_changes | no | array of object (inputChange), 0 to 50 items | Inputs of the candidate's base snapshot that the candidate does not write and that differed on disk when it was applied (allowed by the content rule; a deleted or renamed one is refused instead). The published head is then not exactly the base plus the candidate. Absent when none, and on replays (replayed: true). |
receipt fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
receipt_id | yes | string (at most 128 characters) | Id of this receipt. |
request_id | yes | string (at most 128 characters) | Caller-chosen idempotency key, scoped to workspace and caller. Bound to the request's input fingerprint. |
input_fingerprint | yes | string | Lowercase hex SHA-256 over a documented canonical input (node version, option fingerprint, input fingerprint). |
outcome | yes | applied, not_applied, unknown | applied (files written), not_applied (nothing written) or unknown (send the same request again with the same request_id). |
candidate | yes | string (at most 256 characters) | Opaque id of a private candidate (change.propose). |
candidate_version | yes | integer (1..) | The candidate version that was applied. |
base_snapshot | yes | string (at most 256 characters) | Opaque id of one immutable captured snapshot. Never the reserved word latest. |
result_snapshot | no | string (at most 256 characters) | Captured after publication; present when applied. |
files | yes | array of object (fileChange), 1 to any items | Each written file with its SHA-256 before and after. |
id_map | yes | array of object (idMap) | Every node id the edit changed (completeness guarantee: an unlisted node keeps its id). [] when none. |
journal | yes | object | The apply journal entry: its id and state (committed, rolled_back or pending_reconcile). |
recorded_at | yes | string | RFC 3339 with an explicit offset, uppercase T and Z. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, precondition_failed, conflict, compile_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "change.apply", "workspace": "<workspace>",
"request_id": "apply-rename-add-1",
"params": {"candidate": "<candidate>", "expected_candidate_version": 1, "require_checks": ["compile"]}}{
"request_id": "apply-rename-add-1",
"result": {
"receipt": {
"base_snapshot": "snap-8d409ade6cc9…",
"candidate": "cand-…",
"candidate_version": 1,
"files": [
{
"after_sha256": "6fa9d35dbcf8…",
"before_sha256": "c7ac07a1c507…",
"change": "modified",
"path": "main.acore"
}
],
"id_map": [],
"input_fingerprint": "…",
"journal": {
"id": "jrnl-…",
"state": "committed"
},
"outcome": "applied",
"receipt_id": "rcpt-…",
"recorded_at": "…",
"request_id": "apply-rename-add-1",
"result_snapshot": "snap-2d2c561be58b…"
},
"replayed": false
},
…
}Sending the same request again returns the recorded receipt and writes nothing:
{"protocol": "axiom-agent-semantic/v1", "operation": "change.apply", "workspace": "<workspace>",
"request_id": "apply-rename-add-1",
"params": {"candidate": "<candidate>", "expected_candidate_version": 1, "require_checks": ["compile"]}}{
"request_id": "apply-rename-add-1",
"result": {
"receipt": {
"outcome": "applied",
"receipt_id": "rcpt-…",
"recorded_at": "…",
…
},
"replayed": true
},
…
}change.discard
Closes an open candidate and releases it. It never undoes an applied change; to undo, propose a compensating change.
Params (schemas/operations/change.discard.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
candidate | yes | string (at most 256 characters) | Opaque id of a private candidate (change.propose). |
expected_candidate_version | no | integer (1..) | Optional: the candidate version you expect. Another version is precondition_failed. |
Result (schemas/operations/change.discard.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
candidate | yes | object (candidate) | The candidate, now discarded. |
released | yes | boolean | Overlay resources were freed. |
candidate fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
id | yes | string (at most 256 characters) | Opaque id of a private candidate (change.propose). |
version | yes | integer (1..) | Increases with every successful change.propose on the candidate. |
state | yes | open, applied, discarded, expired | The candidate's state: open, applied, discarded or expired. |
base_snapshot | yes | string (at most 256 characters) | Opaque id of one immutable captured snapshot. Never the reserved word latest. |
snapshot | yes | string (at most 256 characters) | Snapshot id of base plus overlay; readable by the owning caller. |
request_id | yes | string (at most 128 characters) | The request_id of the change.propose that produced this version. |
input_fingerprint | yes | string | Lowercase hex SHA-256 over a documented canonical input (node version, option fingerprint, input fingerprint). |
expires_at | no | string | RFC 3339 with an explicit offset, uppercase T and Z. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, precondition_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "change.propose", "workspace": "<workspace>",
"base_snapshot": "<snapshot>", "request_id": "placeholder-1",
"params": {"operations": [{"kind": "set_property", "node": "element:Home/view/0/0", "property": "placeholder",
"old_value": "Add a task", "new_value": "New task"}]}}{"protocol": "axiom-agent-semantic/v1", "operation": "change.discard", "workspace": "<workspace>",
"params": {"candidate": "<candidate>", "expected_candidate_version": 1}}{
"result": {
"candidate": {
"base_snapshot": "snap-2d2c561be58b…",
"id": "cand-…",
"input_fingerprint": "…",
"request_id": "placeholder-1",
"snapshot": "snap-9243a149fdcd…",
"state": "discarded",
"version": 1
},
"released": true
},
…
}changes.since
What changed between an older snapshot (since) and the request's snapshot:
changed files with digests, and where the nodes you hold (scope.nodes) are
now. history is known, unknown or expired. Node mappings here are
inferred (relation: inferred) from ids, paths and text.
Params (schemas/operations/changes.since.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
since | yes | string (at most 256 characters) | Opaque id of one immutable captured snapshot. Never the reserved word latest. |
scope | no | object | Limit the answer to these node ids and paths. |
cursor | no | string (at most 1024 characters) | Opaque continuation token bound to one snapshot and one request shape. Valid until the snapshot expires. |
Result (schemas/operations/changes.since.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
since | yes | string (at most 256 characters) | Opaque id of one immutable captured snapshot. Never the reserved word latest. |
history | yes | known, unknown, expired | known: deltas below are complete for scope. unknown: since is not related to this snapshot by captured history. expired: since was evicted; deltas are empty. |
files | yes | array of object (fileChange) | Files changed between the two snapshots, with digests before and after. |
nodes | yes | array of object (relocation) | Where each node id you hold went, with the relation and basis (always inferred in this build). |
relevant | yes | boolean | True when anything in scope changed (with scope.candidate: anything the candidate read or wrote). |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, stale_snapshot.
{"protocol": "axiom-agent-semantic/v1", "operation": "changes.since", "workspace": "<workspace>",
"snapshot": "latest",
"params": {"since": "<first-snapshot>", "scope": {"nodes": ["element:Home/view/0/1"]}}}{
"snapshot": {
"id": "snap-2d2c561be58b…",
…
},
"result": {
"files": [
{
"after_sha256": "6fa9d35dbcf8…",
"before_sha256": "c7ac07a1c507…",
"change": "modified",
"path": "main.acore"
}
],
"history": "known",
"nodes": [
{
"basis": "path",
"new_id": "element:Home/view/0/1",
"old_id": "element:Home/view/0/1",
"relation": "inferred",
"status": "ok"
}
],
"relevant": true,
"since": "snap-8d409ade6cc9…"
},
…
}node.relocate
Maps up to 200 node ids from an older snapshot (from_snapshot) to the
request's snapshot, one entry per id in request order. Each entry has a
status, the new_id and the basis of the match (exact, text, path or
missing); this build's matches are always relation: inferred.
Params (schemas/operations/node.relocate.request.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
from_snapshot | yes | string (at most 256 characters) | Opaque id of one immutable captured snapshot. Never the reserved word latest. |
nodes | yes | array of string (at most 1024 characters), 1 to 200 items | Node ids from from_snapshot to map (1 to 200). |
Result (schemas/operations/node.relocate.result.json)
| Field | Required | Type | Meaning |
|---|---|---|---|
relocations | yes | array of object (relocation), 1 to 200 items | One entry per requested id, in request order: the new id or none, with relation and basis. |
Error codes: invalid_arguments, not_found, internal, resource_limit, permission_denied, unsupported_operation, snapshot_expired, stale_snapshot, compile_failed.
{"protocol": "axiom-agent-semantic/v1", "operation": "node.relocate", "workspace": "<workspace>",
"snapshot": "latest",
"params": {"from_snapshot": "<first-snapshot>", "nodes": ["element:Home/view/0/1", "state:Home.draft"]}}{
"result": {
"relocations": [
{
"basis": "path",
"new_id": "element:Home/view/0/1",
"old_id": "element:Home/view/0/1",
"relation": "inferred",
"status": "ok"
},
{
"basis": "exact",
"new_id": "state:Home.draft",
"old_id": "state:Home.draft",
"relation": "inferred",
"status": "ok"
}
]
},
…
}Errors
An error response has error instead of result. Decide what to do from
code, reason, retryable and next_actions; message is for people and
may change.
The one-shot command and serve answer a request that is not valid JSON, is
not a JSON object, or has no protocol field in the service's legacy format:
error.code is invalid_request (not a v1 code), and there is no
operation, retryable or next_actions. serve keeps reading the next
line. For a request without a protocol field, the message is
protocol is missing; it must be "studio/v1".
Over MCP, acore-semantic mcp answers a message that is not valid JSON with
the JSON-RPC parse error -32700.
Ignore the studio/v1 named in that message: send axiom-agent-semantic/v1.
| Field | Required | Type | Meaning |
|---|---|---|---|
code | yes | unsupported_operation, invalid_arguments, ambiguous_owner, read_only_origin, stale_snapshot, precondition_failed, compile_failed, conflict, insufficient_context, snapshot_expired, permission_denied, resource_limit, not_found, internal | One of the closed list of error codes (see Error codes and what to do). |
reason | no | string | Open refinement of code (the protocol reference lists the values in use), for example old_value_mismatch, request_id_reused, external_write. |
message | yes | string (at most 4000 characters) | A sentence for people. Do not parse it; use code and reason. |
operation_index | no | integer (0..) | Index in params.operations of the operation that failed (batched edits). |
target | no | object (target) | What the error is about. |
diagnostics | yes | array of object, 0 to 200 items (diagnostics) | Compiler diagnostics, for example the errors of a candidate that did not compile. |
retryable | yes | none, same_request, after_refresh | none: the same request will fail again. same_request: retry unchanged (transient). after_refresh: re-read (new snapshot, node versions, options) and rebuild the request. |
next_actions | yes | array of object (nextAction), 0 to 10 items | Suggested next requests, each with the operation, why, and params when the service can fill them. |
details | no | object | Code-specific structured data (current value, expansion refs, conflicting paths, receipt). |
retryable is authoritative for each error:
retryable | Meaning | What to do |
|---|---|---|
none | The same request fails again. | Change the arguments, scope, limits or approach. Do not loop. |
same_request | Transient, or an apply that must be resolved. | Send the identical request again, with the same request_id. |
after_refresh | Your view is out of date. | Read again (new snapshot, node versions, options, values), rebuild the request and send it with a new request_id. |
Error codes and what to do
| Code | Meaning | Default retryable | What a client should do |
|---|---|---|---|
stale_snapshot | The base snapshot is not the current one, and a file the edit touches changed (reason base_not_head). | after_refresh | Call changes.since with your old snapshot and the ids you hold, map them, read the values again and propose on the current snapshot with a new request_id. |
precondition_failed | An explicit precondition does not hold. Reasons: old_value_mismatch, old_text_mismatch, node_version_mismatch, option_stale, external_write, candidate_version_mismatch, candidate_closed, candidate_applied, incomplete_graph, check_required. | after_refresh (candidate_applied: none) | Read again with node.get or node.edits and rebuild the operation. On external_write at apply, someone edited the file: discard the candidate and start from latest. |
insufficient_context | The required context exceeds your limits. details.required_bytes and details.expand say what it needs. | none | Narrow include or focus, then pass selected refs from details.expand. Raise max_bytes only up to the manifest maximum. |
compile_failed | The base or the candidate does not compile; diagnostics has the compiler errors. Reasons include not_validated and repair_regression. | none | Read diagnostics and operation_index, fix the operation and propose again. If the base is broken, start from project.overview diagnostics. |
unsupported_operation | The protocol, operation, edit kind or option is not served. Reasons include protocol_unsupported, unknown_operation, not_implemented, edit_not_offered, still_referenced and group_unresolvable. | none | Do not retry. Check capabilities and node.edits for a supported route. For still_referenced, remove the references first. |
invalid_arguments | Malformed or unusable arguments (for example reason schema, no_op, incompatible_target, multiple_roots). | none | Fix the request against the schema. |
ambiguous_owner | No single authored owner (for example reason shadowed_name, duplicate_property). details.owners lists the choices when known. | none | Target one owner from details.owners explicitly, or ask the user. Never choose by text position. |
read_only_origin | The value is generated, inherited or owned by a dependency. | none | Edit the owner that produces the value. |
conflict | request_id_reused, recovery_required (an interrupted apply left files that match neither the base nor the candidate) or concurrent_candidate. | none (concurrent_candidate: after_refresh) | Use a new request_id; for recovery_required stop and show the user the paths; for concurrent_candidate read again and propose again. |
snapshot_expired | The snapshot or candidate was evicted, or was stored by another compiler build. | after_refresh | Read again on latest; propose again if a candidate was lost. |
permission_denied | Outside the attached root, or refused by policy (path_escape, root_not_allowed, not_owner, policy). | none | Do not work around it. |
resource_limit | A service bound was hit; reason names it (see Limits). | none; same_request for queue_full and for a change.apply that hit timeout | Make the request smaller or page it. For an apply timeout, follow After an apply timeout. |
not_found | Unknown node, candidate, snapshot or workspace (for example reason snapshot_unknown, candidate_expired). | none | Find the node again; never guess an id. |
internal | An unexpected failure. | same_request, once | Retry once unchanged, then report it. |
Which operations can return each code (generated from each result schema's
x-errors):
| Code | Operations that can return it |
|---|---|
unsupported_operation | every operation |
invalid_arguments | every operation |
ambiguous_owner | change.propose, edit.plan |
read_only_origin | change.propose, edit.plan |
stale_snapshot | project.overview, node.find, node.get, node.edits, graph.query, context.build, impact.analyze, changes.since, node.relocate, change.propose, check.run, edit.plan |
precondition_failed | change.propose, change.apply, change.discard, edit.plan |
compile_failed | workspace.open, node.find, node.get, node.edits, graph.query, context.build, impact.analyze, node.relocate, change.propose, change.apply, edit.plan |
conflict | change.propose, change.apply |
insufficient_context | context.build |
snapshot_expired | project.overview, node.find, node.get, node.edits, graph.query, context.build, impact.analyze, changes.since, node.relocate, change.propose, change.inspect, check.run, change.apply, edit.plan |
permission_denied | workspace.open, project.overview, node.find, node.get, node.edits, graph.query, context.build, impact.analyze, changes.since, node.relocate, change.propose, change.inspect, check.run, change.apply, change.discard, edit.plan |
resource_limit | every operation |
not_found | workspace.open, project.overview, node.find, node.get, node.edits, graph.query, context.build, impact.analyze, changes.since, node.relocate, change.propose, change.inspect, check.run, change.apply, change.discard, edit.plan |
internal | every operation |
Three more error examples, run after the apply above. An edit on the snapshot from before the apply, touching the file the apply changed:
{"protocol": "axiom-agent-semantic/v1", "operation": "change.propose", "workspace": "<workspace>",
"base_snapshot": "<first-snapshot>", "request_id": "rename-add-2",
"params": {"operations": [{"kind": "set_property", "node": "element:Home/view/0/1", "property": "label",
"old_value": "Add", "new_value": "Add item"}]}}{
"error": {
"code": "stale_snapshot",
"reason": "base_not_head",
"message": "base_snapshot snap-8d409ade6cc9… is not the current snapshot of the workspace (snap-2d2c561be58b…) and the files this request changes differ there",
"target": {
"snapshot": "snap-8d409ade6cc9…"
},
"diagnostics": [],
"retryable": "after_refresh",
"next_actions": [
{
"operation": "node.get",
"reason": "Re-read the nodes on the current snapshot (snapshot.id of this response) and rebuild the request"
}
]
},
…
}An id that does not exist:
{"protocol": "axiom-agent-semantic/v1", "operation": "node.get", "workspace": "<workspace>",
"snapshot": "latest", "params": {"nodes": ["element:Home/view/9"]}}{
"error": {
"code": "not_found",
"message": "element:Home/view/9 is not a node of snap-2d2c561be58b…",
"target": {
"node": "element:Home/view/9"
},
"diagnostics": [],
"retryable": "none",
"next_actions": [
{
"operation": "node.find",
"reason": "Re-find the node on this snapshot"
}
]
},
…
}A protocol version the service does not speak:
{"protocol": "axiom-agent-semantic/v2", "operation": "capabilities", "params": {}}{
"error": {
"code": "unsupported_operation",
"reason": "protocol_unsupported",
"message": "protocol axiom-agent-semantic/v2 is not supported; this service speaks axiom-agent-semantic/v1…",
"diagnostics": [],
"retryable": "none",
"next_actions": [
{
"operation": "capabilities",
"reason": "Read the supported protocol and operations",
"params": {}
}
]
},
…
}Limits
Request limits bound one response; omitted limits take the default, and
values above the maximum are lowered (the response's truncation.limits
shows what was applied). Service bounds are fixed. Generated from the
manifest:
| Request limit | Default | Maximum |
|---|---|---|
max_bytes | 65536 | 4194304 |
max_depth | 2 | 16 |
max_items | 50 | 200 |
max_nodes | 100 | 1000 |
| Service bound | Value |
|---|---|
request_max_bytes | 4194304 |
timeout_ms | 30000 |
group_compile_budget_ms | 20000 |
brackets_max | 8192 |
brackets_total_max | 16384 |
check_content_max_bytes | 2097152 |
check_files_max | 64 |
import_depth_max | 16 |
json_depth_max | 64 |
nesting_max | 256 |
operations_max | 50 |
snapshot_bytes_max | 67108864 |
source_file_bytes_max | 2097152 |
source_files_max | 64 |
sources_bytes_max | 4194304 |
Each bound has one error: resource_limit with a specific reason:
| Reason | Bound |
|---|---|
request_too_large | Request over request_max_bytes |
json_depth_limit | Request nested deeper than json_depth_max |
too_many_operations | More than operations_max operations in change.propose or edit.plan |
content_too_large | check.run file contents over check_content_max_bytes |
nesting_limit, bracket_limit, brackets_total_limit | Bracket nesting or count in a source file, an overlay or a candidate |
file_too_large, sources_too_large, too_many_modules, import_depth_limit | Project source size, file count or import depth |
snapshot_too_large | Captured inputs over snapshot_bytes_max |
budget_exhausted | A batch's intermediate compiles past group_compile_budget_ms |
timeout | A request running past timeout_ms |
queue_full | The service is busy; retry the same request |
A limit violation is never compile_failed or a failed check: the check
could not run. Bounds on single arguments stated in the schemas (for example a
string new_value over 4096 characters) are invalid_arguments with reason
schema.
Apply, receipts and recovery
change.apply publishes a candidate to the local filesystem:
- It checks the candidate version, that the required checks passed on that
version, and that every file it writes still has the base content (a file
the candidate creates must not exist). If not, it writes nothing:
precondition_failed(external_write) for a file edited since,conflict(concurrent_candidate) for a file another candidate on the same base wrote. - It writes a journal and backups, then replaces the files one at a time (write, sync, rename). Each file is replaced atomically; the set of files is not atomic for other readers.
- It returns a receipt:
receipt_id,request_id,input_fingerprint,outcome, the candidate and its version,base_snapshot,result_snapshot(when applied), each file's SHA-256 before and after, theid_map, the journal entry and the time.
outcome is applied, not_applied or unknown. unknown means the
service could not tell whether writing finished, for example after an
interrupted rename; its journal stays pending_reconcile. The next
change.apply with the same request_id reconciles first: it returns the
recorded receipt if the files match the candidate, applies the candidate if
they match the base, and otherwise answers conflict (recovery_required)
without writing.
Inputs of the base that the candidate does not write are checked too: one
deleted or renamed since is precondition_failed (external_write), and one
edited since is accepted and listed in the result's base_changes.
After an apply timeout
The time limit answers the client; it cannot undo or finish what the apply
was doing. A change.apply past timeout_ms is answered with:
code: resource_limit,reason: timeout,retryable: same_request;target: thecandidateand therequest_id;next_actions:change.applywith the same params;details:outcome,timeout_ms, andreceiptwhen one exists.
details.outcome is about this attempt:
not_applied: this attempt stopped before it started writing and can no longer start. An earlier attempt with the samerequest_idmay still have applied the change.unknown: this attempt had started writing, or reconciling an earlier attempt, and the service cannot tell how far it got. The files may already hold the candidate.details.receiptis theunknownreceipt when the journal was written.
In both cases, send the same change.apply again with the same
request_id. The server process exits after a timed-out request, so start
it again first (for an MCP client, reconnect the server if its tools are gone). The answer is the recorded
receipt with replayed: true, or the interrupted apply is reconciled from its
journal and the candidate is applied once. A resend with the same
request_id is never request_id_reused and never applies twice. Do not
propose again, use a new request_id, or edit the files by hand to retry an
apply: after the change was applied, a new request_id for the same candidate
is precondition_failed (candidate_applied).
Guarantees and their limits
Publication is proven against process kills at every step: after a kill the apply ends applied, rolled back, or reported as needing attention, with no half-written file. It is not proven against power loss or operating system crashes, and there is no remote publication. The full list of guarantees is in the Support matrix.
Compatibility
The manifest's protocol.status is frozen, and protocol.frozen_operations
lists the operations frozen in v1: capabilities, workspace.open,
project.overview, node.find, node.get, node.edits, graph.query,
context.build, impact.analyze, changes.since and node.relocate. Read
that list from capabilities rather than from this page. Error code is a
closed list; reason is an open string that can gain values. A client sends
an optional field only when capabilities lists the operation as
implemented. A planned operation or edit kind answers unsupported_operation
(not_implemented).
Related pages
- Quick start: the same flow as shell commands.
- Support matrix: status and limits per operation and edit family.
- Agent skill: the workflow for coding agents.
Semantic service quick start
Create a one-file Acore UI project, connect acore-semantic to Claude Code or Codex, then make a first read and a first checked edit from the command line.
Semantic service support matrix
Which acore-semantic operations, edit families, checks and publication guarantees are implemented or partial, with their limits and exclusions.