Navigace
ELOWEN · Dokumentace

Poslední aktualizace: 20. října 2026

Procházet dokumentaci · Managed project execution

Tento článek zatím není přeložen. Je dostupný v angličtině.

Developer reference

Managed project execution

Interactive web terminals

Bundled Terminal resolves ctx.control('sandbox').openShell({project,cols,rows}) inside a verified signed-in web API request. Sandbox loads the Project and membership itself and returns {kind,displayCwd,start()}. The single-use start() returns a TerminalChannel with sanitized byte output, framed input and resize, queued-input length, an exit promise and immediate shell cancellation. Without a live Sandbox provider the caller reports unavailable. Host targets use Bash's existing direct or bubblewrap preparation.

Terminal reserves both its four-shell account slot and its 32-shell instance slot before the first asynchronous request read or shell preparation; every failed open releases the reservation. On attach, only the ring's absolute offset supplies replay, replacing any unsent bytes queued for the previous socket. A paused socket has one repeating drain check until it falls below the low-water mark, so producers resume even after prolonged backpressure.

For managed Projects, preparation uses the same ready, authorization, admission and durable lease owners as prepareExecution. Deferred start rechecks membership, runtime generation, admission and cancellation before launching. A stopped environment answers ENVIRONMENT_STOPPED. The fixed isolated Python helper is installed by digest through ensure-guest-file-helper with helperKind:'pty'; the worker admits its exact argv under lifetime:'connection' in a separate 32-session terminal pool. It has no 15-minute execution deadline. Initial shell argv, guest cwd, size and the account environment travel only in the first stdin frame. Eligible GitHub credentials follow Bash's account mapping rules and output redaction. Sandbox heartbeats the lease every five seconds; close, membership revocation and transport loss retain verified guest-unit cancellation and lease retirement. Sessions do not survive a daemon restart.

The internal preparation actor carries the managed-shell size and the host credential Project reference. Public prepareExecution rebuilds its actor from the exact admitted keys and does not forward either field. This adds one helper installation per machine and digest, one streaming worker session and one lease per terminal; ordinary command preparation is unchanged. Operators must install matching root helper files before starting the updated daemon, as described in deployment.

Local execution through Sandbox

src/plugins/environmentTypes.ts owns SandboxLocalExecution and its target, turn, binding and request types alongside the managed file controls. It imports only shared contracts; plugin-api re-exports the same definitions and SandboxControl composes them. Core file consumers such as GuestFileSandbox in managedArtifacts narrow localFiles from this low-level seam rather than importing the full plugin API. This keeps artifact and upload dependencies acyclic without copying method signatures or adding runtime work. The optional local method grants no provider by itself: a missing live Sandbox still refuses local I/O, and managed consumers retain their existing file controls.

Local targets and turn bindings

Use ctx.control('sandbox') for a local ProjectExecutionRef. Await its resolveLocalTarget({target,accountUserId}), bindLocalTurn({target,accountUserId,sessionId,parentSessionId?}), localFiles({...turn,operation},{signal}?) and localRequest({...turn,plugin,tool,operation},{signal,onResult}?) calls. Targets contain projectId,targetId,label,cwd,home,platform,arch,shell,connected; local refs name the Project id. Resolve the current account and scope through awaited ctx.currentAccountUserId() and ctx.currentAccess() before calling. Files and Terminal await target metadata before choosing native path and shell semantics. A computer's connected reports the authenticated connection-ready handshake, not the bare socket: a connection that is attaching, or has not acknowledged the current retry policy, reads false and is refused as offline.

await bindLocalTurn(...) returns {target,signal,release()}. Hold it through the admitted turn, including model-only work. In the daemon it pins the actual connection; a fresh turn for a computer with no live connection throws LOCAL_TARGET_OFFLINE (status 409) instead, while a missing or aborted existing or parent pin stays LOCAL_EXECUTION_LOST. In a runner, Sandbox validates the inherited target and account against both the dispatch and current policy account, requires the active policy session or a child admission from that parent, and subscribes to ctx.localExecutionTurn().signal. Runner release removes that subscription; the daemon retains its socket pin until the delegated call settles. Core's unchanged withLocalExecution uses either binding for startup instruction reads and channel turns, aborts the existing PI session on loss and releases in finally. Each runner binding costs one abort subscription and no RPC or provider request. Missing or aborted dispatch refuses admission. Socket identity stays in the daemon's core connection owner (src/remoteCli/connections.ts); reconnect cannot replace an admitted connection.

Local prepared execution and lease kinds

prepareExecution may return mode local with a local reference and one-shot start() returning ManagedExecutionSession. Its optional cwd readable carries Terminal's existing shell directory reports alongside stdout/stderr. Shell and argv commands share canonical LocalExecutionCommand. files, terminal, mcp, lsp and editor leases are supported; others answer LOCAL_TARGET_UNSUPPORTED. LOCAL_EXECUTION_LOST leaves dispatched mutation effects unknown and forbids replay. Core's runProjectCommand waits for stdout/stderr to drain as well as the exit verdict, so a client process that exits before its prepared session arrives still retains its buffered output. This adds transport work per operation and no provider request. Runner admission checks the live tool owner, every delegated scope and current account tool grants for Files, Terminal, LSP and MCP. Sub-agent's WorkflowStart may only read definition files. A read-only LSP/MCP tool must also be declared read-only in the live registry and may launch argv servers and send their protocol stdin, while file mutations and shell launches remain refused.

Artifact files on a computer

Core artifact operations use the separate sandboxArtifacts.artifactFiles control. Sandbox carries its explicit artifact:true intent across runner IPC without borrowing the active tool's identity; daemon routing invokes the same core-only control used for in-daemon capture. The selected computer's ~/.elowen confines both source and destination, including under read-only delegated Bash. The intent comes only from core's artifact call site. A model-supplied path reaching localFiles stays ordinary file I/O even if it names that namespace. Missing artifact authority fails persistence explicitly; this path adds no connection, retry or provider call.

Terminal timeouts

Bundled Terminal obtains { defaultTimeoutMs, maxTimeoutMs } once at registration from ctx.host.terminalTimeouts(). This read-only accessor is restricted to Terminal and projects only its two values from the daemon's frozen harness snapshot. It performs no I/O, exposes no path or configuration mutator and does not raise root execution caps. Embedded hosts use the core schema defaults. Runner boot carries the same snapshot, so later runners keep the daemon generation even if the operator edits the file. See harness limits.

One-shot commands through runCommand

SandboxControl.runCommand(input, actor?, options?) executes one bounded command over the plugin's prepareExecution result. Core supplies this method when resolving the Sandbox control; providers implement preparation, not a second runner. Input is the existing command/cwd/leaseKind/projectRef shape. An explicit actor carries accountUserId and roots and retains preparation's confinement and tenancy rules. Without an actor the existing turn scope applies. Example: sandbox.runCommand({ command: { type: 'argv', file: 'git', args: ['status'] }, cwd, leaseKind: 'editor', projectRef }, { accountUserId, roots: [] }, { timeout: 30000, outputLimit: { combined: 8 * 1024 * 1024 } }).

Core owns capture, 5-second lease heartbeats, cancellation and release. The default timeout is 10 seconds and the default limit is 1 MiB per stream; callers may instead specify a combined byte limit. Decode and sanitize captured stdout/stderr after collection. Completed commands resolve with stdout, stderr, code and signal, including nonzero exits. Timeout, abort, overflow, transport and cleanup failures reject with SandboxCommandError and sanitized partial output; they never invent an exit code. Completed nonzero commands release their lease without being cancelled again. Cleanup failures remain failures. Missing Sandbox resolves undefined and callers report unavailable. This seam is for one-shot commands such as Editor Git reads; long-lived LSP services retain prepareExecution's raw session.

SandboxCommandOptions.onPrepared receives the prepared execution before launch, so the owning domain can admit or refuse it. A throw refuses the command, and core cancels its preparation lease. Cancellation and lease release stay with core.

Foreground detach controls

Terminal, Subagent and Workflow register the shared DetachControl on their existing control keys. Core awaits control.detachForeground({ sessionId, principal }), which returns Promise<{ detached: number }>. Providers match both the origin conversation and principal; a foreign or already-background run contributes zero. The work continues after its foreground waiter is released. Subagent awaits its progress persistence before releasing that waiter, so a failed write cannot report a successful background handoff.

Computer Project editor files

Use the same sandbox.projectFiles({project,accountUserId,operation}) binding as a managed editor, with project:{kind:'local',projectId}. No session id is required. Core authorizes canExecute, holds a daemon connection binding for each operation and counts completed file mutations on the device. Shared guestFiles helpers retain CAS versions, chunking and source pins. Offline and older clients throw typed LOCAL_TARGET_OFFLINE and LOCAL_CLIENT_OUTDATED errors, both status 409; a non-member, including an administrator, receives local_target_forbidden with status 403. Missing Sandbox is unavailable. Registry Editor is the consumer; local Git and commit inspection use its existing editorExecute wrapper with leaseKind:'editor', local ref, explicit account and bounded capture. See paired computers for the binding lifetime.

Project Git reads

Use ctx.host.git().projectRemotes(root, options?) for repository detection without worktree status. It returns { isRepo: boolean, remotes: { name, fetchUrl, pushUrl }[] }. Fetch and push URLs share the snapshot reader's sanitization of URL credentials, query strings and fragments; SCP-style SSH remotes remain intact. One remote costs four Git processes: repository probe, remote list, fetch URL and push URL. A managed read uses one guest execution session per process. A checkout without remotes costs two processes; a non-repository stops after its probe. No call means no Git work.

The registry GitHub plugin uses this read for its repository panel and mapping suggestions. For a host Project, authorize the Project and pass its checkout path. For a managed Project, pass its canonical guest root and explicit authority:

const { remotes } = await ctx.host.git().projectRemotes(root, {
  managed: { project: { kind: 'managed', projectId }, accountUserId },
  signal,
});

Declare reads: ['git'] and, for managed reads, consumesControls: ['sandbox']. The host checks the current account and selected Project before dispatch, and the environment provider rechecks live membership. Managed reads use the existing strict Git executor and never fall back to a host checkout. Only Git's exit 128 with its non-repository diagnostic returns { isRepo: false, remotes: [] }; launcher, runtime, remote lookup and transport failures propagate. Missing host wiring or an absent environment provider throws. Host reads retain the reader's existing lax recovery. Captured output is bounded; cancellation and lease release use the shared managed command runner. Plugins requiring this method declare core 0.29.100 or later.

Privileged transport and worker protocol

The Sandbox control's prepareExecution() returns the union SandboxPreparedExecution: LocalPreparedExecution for direct or confined host execution, or ManagedPreparedExecution for a managed Project. Managed preparation exposes start(): Promise<ManagedExecutionSession> and cancel(); the session provides stdin, stdout, stderr, and a settled closed promise. The session that start() resolves to is ManagedExecutionSession: stdin, stdout, stderr and closed (src/plugins/api.ts, ManagedExecutionSession). Managed consumers must use this start() contract and must not expect the { launch, stdin, cancel } shape, which belongs only to LocalPreparedExecution (direct or confined execution, src/plugins/api.ts).

The host supplies privilegedTransport to buildBrainCore explicitly; the daemon forwards it through buildApp. Without it, Sandbox machine-runtime calls reject locally with no privileged transport in this process, and daemon-mode Sites gateway calls report unavailable with that detail. Runners receive only the machine gateway: the delegated runner builds its core with role: 'runner' (src/subagent/runner.ts), which leaves the plugin-service manager and the published Sites control null (src/daemon/brainCore.ts). Registry loading never deactivates the published gateway because Sites is absent, disabled, or failed to load. These controls still enforce their existing consumer restrictions and stamp their own domains; a supplied transport does not broaden plugin access.

The machine runtime gateway runs managed sessions through the persistent privileged worker. Worker protocol 2 uses framed control messages plus direct socket-stdio attachment with exec-start, exec-accepted, exec-attach, exec-started, exec-exit, and exec-cancel. onInterrupted records interruption before the execution promises settle. The core-only sandboxArtifacts control is composed with the Sandbox control only inside core; plugins cannot resolve it directly.