Programmatic harness contracts
The isolated @uppercut-labs/agent-native/harness export defines a provider-neutral
Session -> Turns control plane without runtime dependencies. This initial slice
includes neutral fake-adapter acceptance, a Node-only loopback MCP bridge and an
isolated Codex local adapter with real Luna acceptance.
Importing the neutral contracts starts no provider or inference.
Harness control and capability execution are sibling planes. Starting an agent never grants permission to invoke application capabilities. The existing capability executor and MCP authorization remain authoritative. The local bridge binds only to loopback; cloud configuration must explicitly supply a reachable authenticated endpoint.
Local MCP bridge
The isolated Node-only /harness/mcp-bridge helper serves an application-supplied
MCP handler on literal loopback, preserving its authorization and owning its
listener lifecycle. See bridge configuration and cleanup.
Cloud agents need an explicit reachable authenticated endpoint; no tunnel is created.
Lifecycle
ProgrammaticHarnessAdapter exposes describe, openSession, resumeSession,
runTurn, cancelTurn, and closeSession.
- Call
describe()before use. Its provider, targets (local/cloud), and features (resume,cancel,usage,mcp) describe actual support.assertHarnessSupport(descriptor, target, feature?)raises stable typed failures. Adapters must also check support; negotiation is not authorization. - Local open/resume requests require an explicit workspace. Cloud requests carry only the target; the provider factory must require explicit remote/repository and authentication configuration. No local workspace is implicitly uploaded.
HarnessSessionRefcontains provider, target, and an opaque session ID. Resume receives this complete reference plus target/workspace. IDs are preserved verbatim; no parsing, cross-provider migration, or global lookup is implied.runTurn({ session, prompt })yieldsturn-startedwith an opaque turn ID, optional status/tool/usage events, then exactly one terminal event:completed,failed, orcancelled. A rejected start throwsHarnessError. A stream ending without a terminal event is incomplete, never successful.cancelTurn({ session, turnId })targets one active turn and requirescancel.closeSession({ session })releases only adapter-owned resources and is idempotent for a known closed session. It does not imply deleting provider history. Adapters define whether resume can reattach after local resource cleanup.
Adapters validate provider/target identity, workspace ownership, session state, and concurrent-turn restrictions. Core contracts do not execute capabilities or weaken provider permissions.
Events and failures
HarnessEvent is a closed union: session-started, turn-started, progress,
tool, usage, completed, failed, cancelled.
createHarnessEvent constructs immutable snapshots, projects out extra provider
fields, and validates normalized payloads. createHarnessStatusEvent is the focused
status/tool helper. Message length is 1-240 characters, provider length 1-64,
session ID length 1-1024, and turn ID length 1-128; control characters are rejected.
These limits bound individual events, not total stream length. Consumers must apply
their own turn deadlines and event-count limits.
Status/tool messages must be adapter-authored, reviewed safe summaries. Length checks and field projection do not detect credentials embedded in an allowed string. Never forward raw model output, exception text, environment dumps, credential files, or tool arguments. Treat session IDs as sensitive in external evidence unless provider guidance explicitly permits sharing them.
Usage is a nonnegative safe integer in provider-reported tokens or requests.
Emit it only when advertised and reliable; absence means unavailable, not zero.
It is not a cross-provider price model.
HarnessError.reason is one of unsupported-target, unsupported-feature,
invalid-request, authentication-required, provider-unavailable,
session-not-found, session-closed, turn-not-found, turn-active, timeout,
provider-failed. Messages are fixed by reason and carry no raw provider cause.
Terminal failure events use these same reasons. Adapters translate provider failures
at the boundary; restricted diagnostics stay outside this normalized API.
Acceptance and installation
test/harness.test.mjs checks a fake adapter opening a session, two turns with
same-session resume, targeted cancellation, close, unsupported operations, stream
failures, event bounds, and raw-field exclusion. Type checks reject local requests
without a workspace. npm run check:portability packs and installs a fresh
root/browser/harness consumer with optional peers absent and checks every export.
The export is not re-exported from root/core and has no provider SDK, Node, DOM,
framework, or MCP imports. Import contracts through /harness.
Source/tarball checks do not establish availability of a new registry release.