Status: experimental, local-only, read-only
HTTP version prefix: /api/v1
Object schema version: 0.1
Issue: #572
Product surface: idkmesh control-tower
The Control Tower Local API is the first machine-readable product boundary for the Human Control Tower. It exposes already-produced IDKMesh evidence for local human-facing clients without becoming a scheduler, verifier, decision maker, repository writer, or merge authority.
Its first canonical input contract is:
idkmesh-run-evidence-report / schema_version 0.1
Its primary output contract is:
idkmesh-control-tower-snapshot / schema_version 0.1
The corresponding JSON Schema is:
schemas/control-tower-snapshot-v0.1.schema.json
The API and browser UI consume the same Python service layer. Neither is a second source of project truth.
The HTTP prefix and object schema version are intentionally distinct:
HTTP API compatibility line: /api/v1
response schema version: 0.1
Additive compatible response fields may remain under /api/v1 with a new
explicit object schema version only when clients can safely ignore them.
Incompatible HTTP behavior requires a new URL version.
Unknown versions fail explicitly with:
unsupported_api_version
and return the supported version list.
The service binds only to:
127.0.0.1
This is a local process boundary, not a claim that localhost is a complete sandbox against a compromised machine.
Every API request except GET /healthz, GET /readyz, and the HTML document itself requires:
X-IDKMesh-UI-Token: <session-token>
The default token is a random per-process value embedded only in the locally served browser page.
For intentional headless/local automation, callers may provide a stable token through:
IDKMESH_CONTROL_TOWER_TOKEN
The value must contain 32–4096 characters drawn only from ASCII letters,
digits, -, ., _, and ~. Restricting the alphabet keeps the token safe
for both HTTP-header use and embedding into the locally generated HTML/JS. It
is never printed by the server. Environment injection exists so a local client
can know the token without weakening the browser default.
The server also:
Host values;The Control Tower consumes the shared HTTP Service Runtime Baseline v0.1.
Every response carries bounded operational metadata:
X-Request-ID
X-IDKMesh-Service
X-IDKMesh-Service-Version
X-IDKMesh-API-Version
X-IDKMesh-Read-Only
A safe caller-provided X-Request-ID is echoed for correlation. Invalid or
oversized values are replaced rather than reflected. Request IDs are not user
identity, authorization, or evidence.
Optional access logging is enabled with:
IDKMESH_HTTP_ACCESS_LOG=1
Each log line is compact JSON containing request ID, method, path, response status/size, duration, service, and event time. Query strings are stripped and the logging API does not accept request bodies, authorization/session headers, prompts, or secret material. Logging failure does not turn an otherwise valid read-only response into an application failure.
The Control Tower is presentation and inspection only.
A Run Evidence Report is refused unless its authority object is exactly:
{
"canonical_state_write": false,
"git_push": false,
"merge": false,
"automatic_candidate_selection": false
}
and its human decision remains exactly:
{
"status": "pending",
"selected_attempt_id": null,
"integration_authority": "external_human_or_governance"
}
v0.1 therefore cannot:
Those capabilities require separately reviewed contracts and authority.
Requests to the inspection endpoint may use either:
application/json
application/vnd.idkmesh.control-tower.v1+json
Clients may request either through Accept.
If the vendor type is explicitly requested, the server responds with that vendor
media type. Otherwise it returns ordinary application/json.
Unsupported response media types return HTTP 406 with
not_acceptable.
Unsupported request media types return HTTP 415 with
unsupported_media_type.
API responses include:
Vary: Accept
X-IDKMesh-API-Version: v1
X-IDKMesh-Read-Only: true
X-IDKMesh-Content-Digest: sha256:<64-hex>
ETag: "<64-hex>"
The content digest is computed from the canonical JSON value using the same sorted-key/minified UTF-8 SHA-256 rule used by repository provenance code.
The API still sends Cache-Control: no-store; ETag/content-digest headers are
integrity and deterministic-equality signals, not permission to cache sensitive
evidence.
The inspection endpoint is read-only and deterministic.
For the same valid input document and API implementation:
same Run Evidence Report
-> same Control Tower snapshot
-> same response body bytes
-> same snapshot_digest
-> same X-IDKMesh-Content-Digest
-> same ETag
No timestamp, random ID, host information, or mutable repository state is added to the snapshot.
GET /healthzUnauthenticated process-liveness check:
ok
It reveals no evidence/project state.
Supported methods:
GET, HEAD
GET /readyzUnauthenticated service-readiness check. It returns only service/API runtime metadata and no project, WorkUnit, run, evidence, secret, prompt, or identity state.
Representative shape:
{
"status": "ready",
"service": "idkmesh-control-tower",
"service_version": "...",
"mode": "local-read-only",
"api_version": "v1"
}
Liveness and readiness are intentionally separate: a future service may be alive while a required runtime dependency is not ready.
Supported methods:
GET, HEAD
GET /api/v1/statusAuthenticated discovery document.
The response includes:
Representative shape:
{
"api_version": "v1",
"schema_version": "0.1",
"kind": "idkmesh-control-tower-status",
"ok": true,
"service": "idkmesh-control-tower",
"mode": "local-read-only",
"media_types": [
"application/json",
"application/vnd.idkmesh.control-tower.v1+json"
],
"capabilities": {
"run_evidence_inspection": true,
"semantic_timeline": true,
"provenance_chain": true,
"human_decision_recording": false,
"worker_execution": false,
"canonical_state_write": false,
"git_push": false,
"merge": false,
"automatic_candidate_selection": false
}
}
Supported methods:
GET, HEAD
GET /api/v1/openapi.jsonAuthenticated OpenAPI 3.1 discovery document.
It describes:
This endpoint is generated from the same installed Python API constants as the server behavior so client discovery is not maintained as a detached static copy.
Supported methods:
GET, HEAD
POST /api/v1/run-evidence/inspectAuthenticated, read-only inspection endpoint.
Body:
one complete idkmesh-run-evidence-report v0.1 JSON document.
No query parameters are accepted in v1.
The service rejects:
NaN or Infinity;Successful response envelope:
{
"api_version": "v1",
"schema_version": "0.1",
"kind": "idkmesh-control-tower-inspection-response",
"ok": true,
"snapshot_digest": "sha256:...",
"snapshot": {
"kind": "idkmesh-control-tower-snapshot",
"schema_version": "0.1"
}
}
Supported method:
POST
Wrong methods return HTTP 405 with an Allow header. HEAD on a POST-only
resource also returns no body.
The snapshot is a deterministic projection, not a decision object.
The snapshot retains:
source.evidence_report_digest is the canonical digest of the exact complete
Run Evidence Report document presented to the API.
That field is intended to support the later human-decision slice, whose decision record must bind to immutable evidence rather than a filename.
The API independently recomputes from attempts[]:
The report’s own summary is not trusted merely because it is present. Any mismatch fails closed.
The current projection can surface:
Attention items explain why a human should inspect something. They are not scores, rankings, or automatic selections.
Every attempt keeps separate UI/API layers:
worker claim
-> independent verifier evidence/recommendation
-> human authority remains pending
The API deliberately avoids collapsing those meanings into one pass/fail field.
The snapshot exposes deterministic provenance for:
WorkUnit digest
-> worker identity
-> ResultManifest ID/digest
-> verifier identity
-> VerificationResult semantic digest
-> required check outcomes
-> pending human/governance authority
The projection also retains:
Identity distinction and independence remain different concepts.
When worker/verifier identities differ:
identity_distinct_from_worker = true
but the API explicitly does not infer statistical, organizational, model-family, or execution independence from different names alone.
When the same identity appears as worker and verifier, the Control Tower raises a human-attention condition instead of calling the result independent.
Run Evidence Report v0.1 is not a complete wall-clock event stream.
The API therefore derives deterministic sequence events only:
It does not fabricate timestamps.
The response snapshot is frozen by:
schemas/control-tower-snapshot-v0.1.schema.json
The schema constrains:
Focused tests validate the generated sample snapshot against this exact schema.
All API JSON errors use:
{
"api_version": "v1",
"schema_version": "0.1",
"kind": "idkmesh-api-error",
"ok": false,
"error": {
"code": "invalid_run_evidence",
"message": "human-readable explanation",
"retryable": false
}
}
Optional structured error.details may be included when a machine-readable
recovery hint exists, such as supported API versions.
Stable v0.1 codes include:
invalid_host;invalid_session_token;not_acceptable;unsupported_media_type;length_required;invalid_content_length;unsupported_transfer_encoding;payload_too_large;invalid_utf8;invalid_run_evidence;unexpected_query_parameters;unsupported_api_version;method_not_allowed;preflight_not_supported;not_found.Known endpoints return HTTP 405 for unsupported methods and publish the allowed
method set in Allow.
Valid /api/v1/* routes are token-authenticated before normal route behavior,
so unauthenticated local callers cannot use method differences as a substitute
for API access.
Cross-origin OPTIONS preflight is deliberately rejected because v0.1 is a
same-origin local API.
PUT, PATCH, DELETE, TRACE, and CONNECT have no write or
tunneling meaning in v0.1 and are rejected.
Browser mode:
idkmesh control-tower
Open a specific report:
idkmesh control-tower path/to/evidence-report.json
Headless server with a caller-known token:
export IDKMESH_CONTROL_TOWER_TOKEN='replace-with-at-least-32-random-characters'
idkmesh control-tower --no-browser --port 8770
Example status request:
curl \
-H "X-IDKMesh-UI-Token: $IDKMESH_CONTROL_TOWER_TOKEN" \
-H "Accept: application/json" \
http://127.0.0.1:8770/api/v1/status
The environment token is an ephemeral local API session credential. It is not a provider secret or repository credential and should not be committed.
gate-audit-ui and control-tower are complementary.
Gate Audit asks:
How much independent evidence does this verifier panel actually provide?
Control Tower asks:
What happened in this multi-attempt run, what evidence exists, where is there disagreement/failure, how is it bound by provenance, and what still needs a human decision?
Both local UIs share one browser-security helper while retaining separate domain contracts.
Every client must preserve:
worker success != verified correctness
verifier recommendation != human integration decision
multiple recommendations != majority truth
replay equality != correctness
identity distinction != independence
Issue #572 defines later read-first slices:
Write/actuation endpoints are explicitly outside v0.1.