Status: experimental design contract
Date: 2026-09-22
Authority: configuration/dispatch interface only; this API grants no acceptance or merge authority.
Cross-cutting conventions: every endpoint below follows the frozen
API Conventions v0.1 (error envelope, status
mapping, pagination, idempotency, concurrency, deprecation —
ADR-0018). This
document’s paths were drafted 2026-09-22, one day before ADR-0016 settled the
/api/v1 product namespace; they are corrected here to that namespace so this
specification does not describe a second, undocumented one. None of the
paths below are implemented.
This specification defines the first product-facing API for connecting repositories, coding agents, model providers and execution backends to IDKMesh.
It does not replace WorkUnit, ResultManifest, EvaluatorPlan, VerificationResult, compute offers, or the existing A2A/MCP bindings.
worker_completed; candidate_ready requires a separately normalized candidate reference and still never implies acceptance.Configuration/API objects use:
idkmesh.io/v1alpha1
The HTTP prefix is:
/api/v1
The HTTP prefix is intentionally decoupled from alpha object-schema naming so future compatible fields do not require a new URL for every additive change.
Example:
{
"api_version": "idkmesh.io/v1alpha1",
"id": "jules-main",
"kind": "agent",
"driver": "jules",
"enabled": true,
"auth": {
"secret_ref": "env:JULES_API_KEY"
},
"settings": {
"source": "sources/github/MSKazemi/idkmesh",
"starting_branch": "main",
"require_plan_approval": true
},
"policy": {
"task_classes": ["coder"],
"allowed_risk": ["low"],
"max_concurrency": 1,
"external_processing": true,
"project_spend_usd_max": 0
}
}
api_version;id;kind;driver;enabled.scm;agent;model;execution.auth.secret_ref;settings;policy.Unknown top-level fields should be rejected in the first implementation unless the schema explicitly provides an extension namespace.
Initial schemes:
env:VARIABLE_NAME
A future implementation may add explicit resolvers such as:
vault:...
onepassword:...
aws-secrets-manager:...
without changing connection semantics.
Prohibited:
{
"api_key": "actual-secret-value"
}
A connection may be stored even when its secret is unavailable; its probe state then reports a configuration/authentication failure and it is ineligible for routing.
Example:
{
"connection_id": "jules-main",
"status": "healthy",
"checked_at": "2026-09-22T12:00:00Z",
"driver": {
"id": "jules",
"version": "0.1"
},
"observed": {
"source": "sources/github/MSKazemi/idkmesh",
"capabilities": ["coder", "git", "tests", "remote_sandbox"]
},
"auth": {
"configured": true
},
"warnings": []
}
Probe statuses:
healthy;degraded;unavailable;disabled.A probe must never return credential values.
The C1 inspection CLI projects the same probe semantics through:
idkmesh connections probe <connections.json>
idkmesh doctor <connections.json>
At the C1-H stage these commands use offline fake drivers only. They do not contact live providers or materialize secret references. A configured secret reference is therefore reported as unavailable until the secret-admission service is composed by a later integration slice.
doctor summarizes observed connector readiness as PASS/WARN/FAIL. This is
an operator diagnostic only; PASS does not grant dispatch, verification,
acceptance, or merge authority.
POST /api/v1/work-units:preview
Purpose:
Example request:
{
"project_id": "MSKazemi/idkmesh",
"source": {
"type": "github_issue",
"number": 123
}
}
Response contains:
Issue text is untrusted input and cannot set connector credentials, executable paths, secret refs, merge authority, or repository administration permissions.
POST /api/v1/routes:resolve
This is advisory/deterministic routing, not execution.
Request:
{
"project_id": "MSKazemi/idkmesh",
"work_unit": { "...": "canonical WorkUnit" }
}
Response:
{
"eligible": [
{
"connection_id": "jules-main",
"reasons": ["task_class_supported", "risk_allowed", "capacity_available"]
}
],
"ineligible": [
{
"connection_id": "local-goose",
"reasons": ["required_model_unavailable"]
}
],
"selected": null
}
The endpoint should not select a connector unless the caller explicitly asks for the project’s deterministic auto-routing policy to be applied.
The same read-only decision can be inspected locally with:
idkmesh route explain <connections.json> <routing-decision.json>
The command performs zero external work. Connector capability comes from the registered driver declaration/probe result and is intersected with any configuration claim, so a profile cannot upgrade itself to a stronger tier. Runtime connector cost may be supplied explicitly for explanation; unknown connection IDs fail closed.
The route response should carry or reference one canonical RoutingDecision with at least:
A connector is never eligible merely because its provider/model is powerful. It must satisfy task class, risk, runtime/tool, secret, external-processing, spend, source-binding, capacity, and authority gates.
GitHub labels and GUI badges are projections of this object, not independent routing authorities.
See Model-Tier Dispatcher and Connector Routing.
POST /api/v1/runs
Request:
{
"project_id": "MSKazemi/idkmesh",
"work_unit": { "...": "canonical WorkUnit" },
"connection_id": "jules-main",
"approval": {
"dispatch_approved": true
}
}
Response:
{
"id": "run-...",
"state": "dispatched",
"work_unit_id": "wu-...",
"work_unit_digest": "sha256:...",
"connection_id": "jules-main",
"source_revision": "<commit-sha>",
"external_ref": {
"provider": "jules",
"id": "sessions/..."
}
}
Creating a run does not approve any future code change.
States:
created;admitted;dispatched;waiting_for_agent;worker_completed;candidate_ready;verification_pending;verified;verification_failed;awaiting_human_decision;integrated;rejected;cancelled;failed.worker_completed means only that the selected worker/provider reports the attempt finished. It does not prove that a usable candidate exists. candidate_ready requires a concrete provider-neutral candidate reference bound to an immutable candidate revision or digest.
State transitions must be monotonic except for explicitly modeled retry/attempt records.
A retry creates a new attempt identity; it must not rewrite historical evidence.
GET /api/v1/runs/{run_id}
Minimum response fields:
GET /api/v1/runs/{run_id}/events
Events are append-only observations such as:
run.created;run.dispatched;agent.plan_ready;agent.progress;agent.completed;candidate.discovered;result.normalized;verification.started;verification.completed;human.decision_recorded;run.failed;run.cancelled.agent.completed records worker completion only. It cannot synthesize candidate.discovered, result.normalized, verification, or human-decision events.
Provider-specific payloads belong under an extension namespace and must not redefine canonical state.
POST /api/v1/runs/{run_id}:cancel
Cancellation means:
Cancellation is best effort for external systems whose API cannot guarantee immediate stop.
GET /api/v1/connections
POST /api/v1/connections
The API accepts secret references only.
GET /api/v1/connections/{connection_id}
POST /api/v1/connections/{connection_id}:probe
POST /api/v1/connections/{connection_id}:enable
POST /api/v1/connections/{connection_id}:disable
Deleting a connection should not delete historical run/evidence records.
Minimum:
GET /api/v1/projects;POST /api/v1/projects;GET /api/v1/projects/{project_id}.Project record should include:
Project policy never contains provider API keys.
POST /api/v1/webhooks/github
Requirements:
X-Hub-Signature-256;Initial accepted event families can be limited to:
Start with label/manual dispatch, not every event.
A run may point to one of:
{
"type": "github_pull_request",
"repository": "MSKazemi/idkmesh",
"number": 999,
"head_sha": "..."
}
or:
{
"type": "artifact_bundle",
"locator": "file://...",
"digest": "sha256:..."
}
A provider-returned URL or provider output object is a discovery hint, not by itself a canonical candidate. For a GitHub pull request, candidate readiness requires repository identity, pull-request number, and exact head SHA resolved through the SCM boundary. For an artifact bundle, it requires a stable locator plus content digest.
Only after that provider-neutral reference exists may the run advance from worker_completed to candidate_ready. The normalizer then converts the external candidate into canonical ResultManifest/artifact evidence.
{
"api_version": "idkmesh.io/v1alpha1",
"id": "gemini-compat",
"kind": "model",
"driver": "openai-compatible",
"enabled": true,
"auth": {
"secret_ref": "env:GEMINI_API_KEY"
},
"settings": {
"base_url": "https://generativelanguage.googleapis.com/v1beta/openai/",
"model": "<configured-model>"
},
"policy": {
"external_processing": true,
"project_spend_usd_max": 0
}
}
Local Ollama can use the same driver with localhost base URL and no secret reference when its local policy permits that.
{
"api_version": "idkmesh.io/v1alpha1",
"id": "goose-local",
"kind": "agent",
"driver": "cli",
"enabled": true,
"settings": {
"preset": "goose",
"model_connection_id": "ollama-local",
"execution_connection_id": "idkmesh-node-local"
},
"policy": {
"task_classes": ["coder", "researcher"],
"allowed_risk": ["low"],
"network": "disabled"
}
}
The preset resolves to maintainer-controlled executable/arguments. WorkUnit content must not inject or replace those command templates.
Reference implementation: idkmesh.connector_errors provides the stdlib-only error vocabulary, retryability defaults, JSON envelope, and recursive credential/header redaction boundary used by connector implementations.
Example:
{
"error": {
"code": "rate_limited",
"message": "Connector is temporarily rate limited.",
"retryable": true,
"connection_id": "jules-main",
"run_id": "run-...",
"details": {
"retry_after_seconds": 120
}
}
}
Initial error codes:
configuration_error;authentication_error;authorization_error;rate_limited;quota_exhausted;provider_unavailable;source_not_connected;sandbox_failure;agent_failed;timeout;cancelled;result_normalization_error;policy_denied;verification_failed;conflict;not_found.Do not include secrets or raw authorization headers in details.
Any mutating HTTP call should support an idempotency key.
Required first:
If a retry arrives with the same idempotency key and equivalent request digest, return the existing object.
If the same key is reused for different content, fail with conflict.
Bootstrap local mode may bind only to localhost and rely on local user access.
A networked/hosted control plane requires explicit authentication/authorization before it can mutate connection or run state.
Do not expose an unauthenticated write-capable control service.
GitHub webhook authentication is separate from operator/API authentication.
Retain:
Do not retain provider credentials.
Provider prompts/responses should be retained only to the extent required for provenance/replay and permitted by data policy; prefer bounded task/evidence artifacts over storing unnecessary conversational material.
This API is a control surface above the existing semantic contracts:
Connector API
-> WorkUnit
-> WorkerAdapter / external agent
-> ResultManifest
-> EvaluatorPlan
-> VerificationResult
-> Evidence Report
-> human decision
A change to this control API must not silently change the meaning of those canonical objects.
The connector implementation has a deterministic offline integration fixture in tests/test_jules_candidate_pipeline.py. It composes the real C2 service boundaries with fake transports/SCM observations:
trusted ScmRevisionBinding
-> Jules Source validation
-> Session creation (requirePlanApproval=true)
-> Session observation
-> COMPLETED => worker_completed
-> JulesPullRequestHint
-> trusted GitHub exact-head resolution
-> CandidateReference
The fixture is intentionally not live-provider acceptance. It performs no network access, uses no API key, creates no external Jules Session, and opens no PR.
It proves the following preconditions before C2-G may use credentials:
worker_completed;C2-G remains a separate live low-risk smoke gate. Passing the offline fixture must never be reported as evidence that a real Jules credential, Source, remote sandbox, candidate PR, or live verification path is healthy.
Jules Session creation currently names a mutable GitHub starting branch. IDKMesh must not treat a caller-supplied branch name or revision string as proof that the branch actually resolves to that revision.
idkmesh/github_branch_reader.py introduces the provider-neutral source-identity boundary:
authorized repository + branch
-> untrusted GitHub ref observation
-> GitHubBranchHeadReader
-> exact repository + branch + immutable commit object id
The reader requires the returned ref to equal the exact requested refs/heads/<branch>, requires the target object type to be commit, and validates a 40- or 64-character hexadecimal Git object id. Request identity is validated before source I/O.
The resulting GitHubBranchHeadBinding is identity evidence only. It deliberately has no verified, dispatch, candidate-ready, verification, acceptance, merge, or integration-authority field.
A higher orchestration layer may construct Jules ScmRevisionBinding(verified=True) only after it has independently compared the authorized requested revision with this exact SCM observation. Merely possessing a syntactically valid SHA is not sufficient.
idkmesh/jules_lifecycle.py composes the already-separated Jules Session, observation, candidate-discovery, and SCM candidate-binding services into one bounded application boundary.
The state progression is intentionally non-collapsing:
waiting_for_agent
-> worker_completed
-> provider PR hints
-> exact SCM candidate resolution
-> candidate_ready
A Session in COMPLETED state remains worker_completed when no candidate hint exists. A discovered hint does not become readiness by itself. candidate_ready is emitted only when every retained hint has resolved through the trusted SCM CandidateReference boundary.
If multiple PR candidates exist, the service retains all of them and makes no selection. If any candidate binding fails, the inspection fails instead of returning a partially ready snapshot.
The service also rechecks Session name/id and hint Session/repository identity at the composition boundary. A descriptive provider candidate count that differs from the deduplicated hint count becomes a warning, not hidden state.
The service composes existing boundaries and adds no source-identity authority of its own. JulesLifecycleService.start delegates to JulesSessionService, which still refuses an unverified ScmRevisionBinding; constructing ScmRevisionBinding(verified=True) from an exact GitHubBranchHeadBinding remains the caller’s responsibility, outside this service.
JulesLifecycleSnapshot contains no verifier result, acceptance, selected candidate, human decision, merge authorization, or integration authorization.
idkmesh connections import <profile> --store <path> validates a connector-profile
document and persists the safe, normalized metadata into a local SQLite store.
idkmesh connections stored --store <path> reads that metadata back. Both accept
--json and emit the §19 error envelope on failure.
Only non-secret metadata is persisted. A profile’s credential material is never
written: the stored row records auth_ref_configured as a boolean and nothing else
about the secret. An inline secret is rejected before any write, and the rejection
does not echo the value.
Error codes on these paths distinguish the two failure domains, because a caller branching on the code needs to know which side to fix:
| condition | code |
|---|---|
| profile document is invalid | the profile’s own code, e.g. unknown_field |
| store missing, unreadable, or not a database | connector_store_error |
| an OS-level store failure, such as a non-directory parent path | connector_store_error |
a stored row whose metadata_json is not valid JSON |
connector_store_error |
The last row is the one that is easy to get wrong in implementation. json.loads
raises json.JSONDecodeError, which is a ValueError; the fix belongs in the store,
which wraps it as a store error, and not in the caller. Widening a caller’s
except to ValueError would also catch ConnectorProfileError, which is itself a
ValueError, and would silently reclassify every profile fault as a store fault.
Known limitations, so an operator is not surprised by them:
connections import is not atomic. It uses one transaction per profile, so a
failure partway through a multi-profile document leaves earlier profiles committed.database is locked. This is a
development-mode store, not a shared production one.connections stored writes to its target even though it only reads. Measured:
pointed at an unrelated SQLite database, it added the connections, idempotency,
probes, routes and runs tables and exited 0. It does not create a missing
parent directory on this path – that exits 2 – but it will migrate any existing
SQLite file it is given. Point it at a path you intend to be an IDKMesh store.