Hosted environment provider contract
Proposed implementation contract. This document extends the generic environment seam so one manager can drive a local microVM provider or a hosted provider over HTTPS. It does not put provider API concepts on the Cotal wire.
Current contract
Section titled “Current contract”The pending environment contract defines EnvironmentDriver.describeImage, preflight, reserve,
provision, start, adopt, inspect, reconcile, reap, destroy, checkpoint operations and
recoveryEvidence in packages/core/src/environment.ts, EnvironmentDriver. Its plan carries one
local image manifest. Its checkpoint export writes one host path.
The manager constructs that plan, calls describeImage(manifest), and rejects failed checks or missing
seat capabilities in implementations/manager/src/environment-operations.ts,
ManagerEnvironments.plan. It installs the persona, customer inputs and the already minted agent
credential before launch finalization in the same file, ManagerEnvironments.prepareSeat. It calls
exportCheckpoint with a host path, then inspects that path in ManagerEnvironments.operate.
The existing generic launch recipe has a local control socket in
packages/core/src/connector.ts, LaunchSpec. User authentication currently carries a sentinel
credential path and executable bearer command in packages/core/src/connector.ts, LaunchOpts, and
validates the same shape in packages/core/src/launch-material.ts, validate. The manager executes
that command once before launch in implementations/manager/src/manager.ts,
execBearerPreflight.
The manager health command currently reports runtime, custody, agent count, uptime, connector
availability and static reconciliation in implementations/manager/src/manager-service-contract.ts,
ManagerStatus. implementations/manager/src/manager.ts, Manager.managerStatusData, builds that
response from boot inventory and live manager state.
Contract types
Section titled “Contract types”The additive declarations use Hosted*, ProviderEnvironmentLaunchRequest and
ManagedEnvironmentRecord names where the hosted shape differs from the pending local contract.
This keeps the pending EnvironmentPlan, EnvironmentLaunchRequest, CheckpointOutput,
EnvironmentDriver and EnvironmentHandle declarations unchanged when the branches merge. The
module is exported from packages/core/src/index.ts. These declarations do not make environment
records part of the wire spec.
1. Probe capabilities
Section titled “1. Probe capabilities”Decision: HostedEnvironmentPreflight returns one closed HostedEnvironmentCapabilities value and probedAt.
Every provider reports every capability for the selected plan and current deployment. No manager
infers capability from provider name, engine name or status.
interface HostedEnvironmentCapabilities { guestBuild: boolean; custody: boolean; sessionHistory: boolean; materialRenewal: boolean; coldCheckpoint: boolean; memoryCheckpoint: boolean; nested: boolean; pauseKeepsMemory: boolean; snapshot: boolean; export: boolean; gpu: boolean; durableSeatHome: boolean; screen: boolean; exec: boolean; extend: false | { stepMs: HostedPositiveStepMs };}
interface HostedEnvironmentPreflight { checks: HostedEnvironmentPreflightCheck[]; capabilities: HostedEnvironmentCapabilities; probedAt: number;}Reason: deployment support can differ across accounts, regions, hosts and selected templates. A type or product default would turn a deployment fact into an assumption.
Contract:
preflightHosted(plan)probes the selected deployment and returns an epoch-millisecondprobedAt.- The manager persists the returned capabilities with the environment record.
- A required
falsecapability refuses before reservation or credential issuance. pauseKeepsMemory: falsemeans pause is not a memory-retaining lifecycle action.durableSeatHome: falsemeans the manager must not use the seat home as a checkpoint source. A provider checkpoint or explicit history export remains eligible when separately supported.screenmeans a provider can expose the managed seat’s screen surface.execmeans it can run the closed prepared launch. Neither is inferred from general network reachability.- A later probe replaces the full capability value and
probedAt. It does not merge selected fields with an older observation.
2. Image and template references
Section titled “2. Image and template references”Decision: HostedEnvironmentPlan adds a template arm beside the pending local manifest arm. Its
template arm carries a discriminated HostedEnvironmentImageReference.
HostedEnvironmentDriverExtension.describeHostedImage accepts the hosted reference and returns it
unchanged in HostedEnvironmentImageDescription, with a normalized record projection. The pending
local describeImage(manifest) signature stays unchanged.
type HostedEnvironmentImageReference = | { kind: "oci"; manifest: HostedEnvironmentFileReference } | { kind: "template"; ref: HostedEnvironmentRecordText };Reason: an OCI image is selected by a manager-local manifest, while a hosted provider creates from an
opaque template reference. Putting templates in providerOptions would hide the principal immutable
input from preflight, journaling and reconciliation.
Contract:
- The manager selects one reference before preflight.
- An OCI reference retains the current bounded local manifest validation.
- A template
refis opaque nonsecret provider input. It is not an API key, signed URL or bearer. describeHostedImageperforms a bounded read-only inspection and returns the input reference, a normalized{ kind, ref, digest? }record projection, architecture, guest ABI, protocol version, connector pin, bundle digest and system trust digest.- For a template,
bundleSha256is the digest of the Cotal guest bundle measured or attested inside that template. It is not a template ID digest. - The manager rejects a returned reference that differs from the selected reference.
- The environment record later renders either source as
{ kind, ref, digest? }. An OCI record uses a stable image reference and its digest. A template record omitsdigestunless the provider reports a stable content digest.
3. Network mode and lifetime
Section titled “3. Network mode and lifetime”Decision: network selection is part of HostedEnvironmentPlan and is immutable after provision.
The driver also has an extendHosted verb. Providers that do not support extension report
extend: false and the verb refuses.
interface HostedEnvironmentPlan { // existing fields network: string | null;}
interface HostedEnvironmentDriverExtension { extendHosted( ref: HostedEnvironmentReference, op: HostedOperationContext, ): Promise<HostedEnvironmentLifetime>;}
interface HostedEnvironmentLifetime { expiresAt: number | null; observedAt: number;}Reason: a hosted provider fixes its network when it creates the environment. Lifetime extension is a remote effect with its own deadline and uncertain-outcome rules. Hiding it in reconciliation or provider options would make authorization and replay ambiguous.
Contract:
networkis a nonsecret provider-neutral selection key.nullasks the provider for its documented default. The provider records the resolved network and never changes it in place.- A network change requires a new environment. Reconcile observes the recorded selection but does not repair drift by choosing another network.
extendHostedis admitted, journaled and reconciled like other mutating driver operations.- The merged environment operation union includes
extend. extend: { stepMs }carries aHostedPositiveStepMsconstructed only byvalidateHostedPositiveStepMs. One successful call moves the provider deadline by at most that fixed positive step. The manager reaches a longer requested lifetime through bounded repeated calls.extendHostedreturns the provider-observed deadline.expiresAt: nullmeans the provider reported no deadline. It never means an unknown fetch result.- Timeout or cancellation leaves the operation uncertain until reconcile proves the same logical operation’s result.
4. Checkpoint export without a host volume
Section titled “4. Checkpoint export without a host volume”Decision: checkpoint output is a destination request, and export returns the verified destination. A provider file is read through a separate bounded streaming method.
type HostedCheckpointOutput = | { kind: "host-path"; path: string; maxBytes: number } | { kind: "provider-file"; maxBytes: number };
type HostedCheckpointExport = | { kind: "host-path"; file: HostedEnvironmentFileReference } | { kind: "provider-file"; file: HostedEnvironmentProviderFileReference };
interface HostedEnvironmentProviderFileReference { environment: HostedEnvironmentReference; id: string; byteLength: number; sha256: string;}Reason: a hosted provider has no manager-visible volume path. Returning only a provider file ID would also omit the size and digest the manager needs to verify the read-out.
Contract:
exportHostedCheckpointreturnsHostedCheckpointExport. The pending localexportCheckpointand{ path, maxBytes }output remain unchanged.host-pathwrites only the requested path and returns the inspected file reference.provider-filecreates a provider-managed readable object and returns its opaque ID, size and digest. The ID is not a URL or credential.readHostedProviderFileis aHostedEnvironmentHandleExtensionmethod and streams the named bytes under anHostedOperationContext. The guest-side provider channel owns the provider file namespace. The manager enforcesmaxBytes, byte length and SHA-256 while copying to its chosen destination.- The provider authorizes the read from the manager’s current environment operation. It must not return a signed URL, provider credential or host path to the guest.
- The file API is available from the guest-side provider agent or equivalent provider channel. It does not require a volume visible to the manager host.
- Successful export does not delete the provider file. Retention and deletion remain provider operations with durable evidence.
5. Bearer source
Section titled “5. Bearer source”Decision: the environment launch request carries a discriminated HostedEnvironmentBearerSource. The
manager fills it after selecting the deployment and before it stages the closed request.
type HostedEnvironmentBearerSource = | { kind: "socket"; path: string } | { kind: "https"; url: HostedAuthorityHttpsUrl };
interface HostedEnvironmentLaunchAuthentication { bearerSource: HostedEnvironmentBearerSource;}
interface HostedEnvironmentLaunchRequest<Intent> extends ProviderEnvironmentLaunchRequest<Intent> { // every closed base field comes from ProviderEnvironmentLaunchRequest authentication: HostedEnvironmentLaunchAuthentication;}Reason: a local microVM can reach a host-mounted socket. A remote guest cannot. Both sources implement one operation: fetch a fresh bearer for the already bound agent principal.
Contract:
- A local provider uses
socketwith a guest-visible socket path. validateHostedAuthorityHttpsUrlis the only constructor forHostedAuthorityHttpsUrl. It refuses non-HTTPS schemes, userinfo, queries and fragments before launch request construction.- The manager fills
authentication.bearerSourceafter preflight and durable reservation. The existing top-levelcredentialdescriptor remains the sole admitted agent credential and is bound beside that source in the same canonical request. Provider configuration can select a trusted endpoint but cannot override the closed launch request later. - The guest fetch authenticates with the separately installed agent credential. Redirects refuse.
- The response is a short-lived bearer only. Provider and sponsor credentials never participate in the request.
- A provider refuses a source kind it cannot expose. There is no socket-to-HTTPS fallback.
6. Credentials
Section titled “6. Credentials”Decision: ProviderEnvironmentLaunchRequest preserves every closed base launch field. Its top-level
credential names the agent’s own pre-minted, revocable credential material. The manager installs its
bytes through the existing material staging path before prepareLaunch.
authentication.bearerSource tells the guest how to use that credential to fetch a fresh bearer.
Reason: ManagerEnvironments.prepareSeat already requires explicit credential material and installs
it with the other declared inputs. Making it explicit under launch authentication binds the material
to the bearer source without permitting a guest login flow.
Contract:
- The manager mints the agent credential after reservation and issuance admission.
- The descriptor has
purpose: "agent-credential",lifetime: "launch", and null home and environment destinations. - Credential bytes move only through
replaceMaterial. They do not enter argv, provider options, image metadata, the environment record or presence. - The guest starts with the credential already installed. It performs no human login, provider login, sponsor login or credential exchange during seat launch.
- The provider refuses provider API keys, sponsor keys, account tokens, signed URLs or any descriptor other than the one admitted agent credential in this launch slot.
- Revocation targets the agent credential and its lifecycle. It does not require rotating provider account credentials.
7. Environment record
Section titled “7. Environment record”Decision: the presence card’s opaque environment value equals ManagedEnvironmentRecord.id.
The complete record is durable in the manager’s environment journal and is read through the manager
control surface. It is not added to the Cotal wire specification.
interface ManagedEnvironmentRecord { version: "cotal-manager-environment-record/v1"; id: HostedEnvironmentRecordText; provider: HostedEnvironmentRecordText; providerRef: HostedEnvironmentRecordText; space: HostedEnvironmentRecordText; host?: HostedEnvironmentRecordText; arch?: HostedEnvironmentRecordText; engine?: HostedEnvironmentRecordText; volumeId?: HostedEnvironmentRecordText; image: HostedEnvironmentRecordImage; owner: HostedEnvironmentRecordText; createdAt: number; state: "creating" | "running" | "stopped" | "failed"; stoppedAt?: number; expiresAt?: number; network?: HostedEnvironmentRecordText; capabilities: HostedEnvironmentCapabilities; probedAt?: number;}Reason: the Cotal environment ID and the provider handle have different lifetimes. A durable join must survive a provider reissued handle and must place the environment within its space.
Contract:
- The manager mints
idbefore provider reservation and callsreserveHosted(id). The provider returns aHostedEnvironmentReferencewhoseidis unchanged. The ID is globally unique across providers, has no provider-prefix convention, and is never a credential. presence.environment === record.idis the only join. A provider reference, host, volume or image reference is never an alternate join.- The provider exposes
hostedFacts(ref, op)forproviderRef,volumeId, resolvednetwork, provider deadline, state evidence and provider observation time. It does not reportengine: section 8 host enrollment facts are authoritative for engine, so a provider-sourced engine would be a second, non-authoritative source for one record field.volumeIdis absent when the provider did not report the fact.describeHostedImagesupplies the stable image digest when available. - The manager records
id,provider,space,host,owner,createdAt, the selected image reference, normalized architecture, probe result andprobedAt. - The manager maps provider observations to the closed record state.
stoppedAtis present only after a proved stop.expiresAtis absent only when the provider did not report a deadline. host,arch,engineandvolumeIdare absent when their source did not report the fact. Section 8 host enrollment facts remain authoritative forarchandengineand supplyhostas well;hostedFactssuppliesvolumeId.createdAt,stoppedAt,expiresAtandprobedAtare epoch milliseconds.providerRefis opaque and may change after provider reconciliation.idnever changes.- Every record update is appended or replaced through the manager’s durable environment journal before it is served.
- Every record string is a
HostedEnvironmentRecordText. Callers obtain it only throughvalidateHostedEnvironmentRecordText, which bounds it to 2048 UTF-8 bytes and refuses control characters, bearer text, private-key or credential blocks, secret assignment text, URL userinfo and secret-shaped query keys before journal storage. No API key, bearer, credential path, signed URL, control token or launch material ID is allowed. Dashboards may read the whole record.
8. Host enrollment facts
Section titled “8. Host enrollment facts”Decision: the implementation must add an untargeted read command named environment-host-facts to
both the manager contract table and MANAGER_READ_COMMANDS. It uses the existing manager.read
capability class and returns one closed EnvironmentHostFacts value. This lane defines the shape but
does not add manager implementation code.
interface EnvironmentHostFacts { version: "cotal-environment-host-facts/v1"; instanceId: string; host: string; arch: string; os: { platform: string; release: string }; engines: { name: string; version?: string }[]; kvm: { present: boolean; usable: boolean }; headroom: { cpus: number; memoryMiB: number; diskGiB: number; environmentSlots: number; }; observedAt: number;}Reason: spawn placement needs measured machine facts, not a host-name convention. A separate command keeps resource inventory out of the general process-health response and allows independent refresh.
Contract:
hostis the manager’s stable nonsecret enrollment label. It is not a network address unless the operator deliberately chose an address as the label.archandosdescribe the manager machine.engineslists detected environment engines and versions when known.kvm.presentreports device presence.kvm.usablereports the manager’s actual access check.headroomis currently allocatable capacity after manager reservations, not total machine size.observedAttimestamps the completed probe. Probe failure returns command failure, not zero headroom or an empty engine list.- A spawn goal may select a manager instance whose returned facts satisfy its host requirement. The selected manager still runs provider preflight before reservation.
There is a related manager scheduling gap outside this contract. A manager with no usable connector
inventory still serves the spawn anycast class and can terminally refuse a goal that another manager
could run. A later change should either let supervise decline the spawn class or define a
harness-aware negative acknowledgement that leaves the goal available to another instance. This
lane does not define that behavior.
Lifecycle and security rules
Section titled “Lifecycle and security rules”- Every HTTPS provider call is bounded by the original
HostedOperationContextdeadline and abort signal. - An accepted remote request that times out is uncertain. The manager reconciles the same logical operation ID before another mutation.
- Provider references and file IDs are opaque identifiers, never authority.
- Provider options contain selection data only. Trusted callbacks and credential bytes stay in the in-process provider context or staged launch material.
- Unsupported capabilities refuse. No provider reports a successful no-op.
- The manager journal is authoritative for intent, ownership, record identity and operation history. Provider observations are evidence joined to that state.