Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions crates/server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ pub enum RunnerLifecycleMode {
#[default]
Managed,
/// An independent Runner that an operator or a harness started: the gateway only connects
/// to it through `--runner-socket`, and its processes outlive the gateway. Not a supported
/// mode yet.
/// to it through `--runner-socket`, and its processes outlive the gateway. Supported only on
/// the combinations its qualification qualifies (P1R-C06).
Independent,
}

Expand Down Expand Up @@ -135,7 +135,8 @@ pub struct Cli {

/// The UDS Runner's lifecycle: `managed` (default), or `independent` for a Runner that an
/// operator or a harness started, which the gateway only connects to through
/// `--runner-socket` (P1R-C01). `independent` is not a supported mode yet.
/// `--runner-socket` (P1R-C01). `independent` is supported only on the combinations its
/// qualification qualifies (P1R-C06).
#[arg(long, value_enum, default_value_t = RunnerLifecycleMode::Managed)]
pub runner_lifecycle: RunnerLifecycleMode,

Expand Down
2 changes: 1 addition & 1 deletion crates/server/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ impl RuntimeProcess {
previous_controller = claim.previous_controller,
processes = claim.processes.len(),
events_through = claim.events_through,
"claimed an independent Runner; it is not a supported mode yet"
"claimed an independent Runner"
);
warn_recovery_pending(&claim);
Ok((runner, claim))
Expand Down
2 changes: 1 addition & 1 deletion docs/agent-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ Interactive input and cancellation use the same handle:

A live command occupies the workspace. Wait for it to end or terminate it before applying a patch or starting another command. Reads and searches remain available. Long-lived development servers therefore require a workflow that stops them before edits.

`workspace_info.execution.process.capabilities.lifetime` advertises the owner: the runner instance, not the MCP session. Streamable HTTP or MCP client disconnect keeps the process running; reconnect with the saved `process_id`. Losing the UDS worker connection or shutting down the gateway (including stdio EOF) terminates the owned subtree and drops handles. Restart does not restore `process_id`. With an [independent Runner](runner-isolation.md#independent-runner), which is not a supported mode yet, `runner_disconnect` is `keep_running`, and `gateway_shutdown` is `keep_running` when the gateway detaches and `terminate` when it stops the Runner; read `initialize.instructions` for what that gateway does. While that gateway claims its Runner again after a lost connection, it refuses requests with `RUNNER_RECONNECTING`, which sent nothing and consumed no approval: retry after a pause. Then, in a workspace where work was started before, it refuses new commands, patches and approval resumes with `RECOVERY_PENDING` until it has [reconciled](runner-isolation.md#reconciliation) that workspace with the Runner; its message says whether retrying after a pause helps. A process it finds running there holds the workspace as before. If the gateway loses the Runner itself, it answers `process_status` and `read_process` for that Runner's processes from its records, with `lost_reason`, refuses other requests that need the Runner with `RUNNER_DISCONNECTED`, and keeps their workspaces refused, with `RECOVERY_PENDING` in the next gateway, until an operator releases them ([Runner loss](runner-isolation.md#runner-loss)). If the spawn response is lost before you receive `process_id`, do not search with `process_status` and do not start a duplicate command.
`workspace_info.execution.process.capabilities.lifetime` advertises the owner: the runner instance, not the MCP session. Streamable HTTP or MCP client disconnect keeps the process running; reconnect with the saved `process_id`. Losing the UDS worker connection or shutting down the gateway (including stdio EOF) terminates the owned subtree and drops handles. Restart does not restore `process_id`. With an [independent Runner](runner-isolation.md#independent-runner), supported only where [qualified](recovery-qualification.md), `runner_disconnect` is `keep_running`, and `gateway_shutdown` is `keep_running` when the gateway detaches and `terminate` when it stops the Runner; read `initialize.instructions` for what that gateway does. While that gateway claims its Runner again after a lost connection, it refuses requests with `RUNNER_RECONNECTING`, which sent nothing and consumed no approval: retry after a pause. Then, in a workspace where work was started before, it refuses new commands, patches and approval resumes with `RECOVERY_PENDING` until it has [reconciled](runner-isolation.md#reconciliation) that workspace with the Runner; its message says whether retrying after a pause helps. A process it finds running there holds the workspace as before. If the gateway loses the Runner itself, it answers `process_status` and `read_process` for that Runner's processes from its records, with `lost_reason`, refuses other requests that need the Runner with `RUNNER_DISCONNECTED`, and keeps their workspaces refused, with `RECOVERY_PENDING` in the next gateway, until an operator releases them ([Runner loss](runner-isolation.md#runner-loss)). If the spawn response is lost before you receive `process_id`, do not search with `process_status` and do not start a duplicate command.

## Confirm a held mutation

Expand Down
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ If helper application fails, the Runner attempts per-file snapshot restoration.

## Process lifetime

MCP request completion does not end a managed process. Clients continue with its `process_id`. Server restart loses those handles. In UDS mode the gateway owns the worker: internal disconnect/shutdown ends the worker and its children, with no reconnect. An [independent Runner](runner-isolation.md#independent-runner), not a supported mode yet, outlives its gateways instead, and a gateway that lost its connection to it claims it again and reconciles what earlier controllers left before it starts new work where they did. When the Runner itself is lost, the gateway answers for its executions from their records, and their workspaces wait for an operator ([Runner loss](runner-isolation.md#runner-loss)). See [runner isolation](runner-isolation.md) for the distinct transport and isolation boundaries.
MCP request completion does not end a managed process. Clients continue with its `process_id`. Server restart loses those handles. In UDS mode the gateway owns the worker: internal disconnect/shutdown ends the worker and its children, with no reconnect. An [independent Runner](runner-isolation.md#independent-runner), supported only where [qualified](recovery-qualification.md), outlives its gateways instead, and a gateway that lost its connection to it claims it again and reconciles what earlier controllers left before it starts new work where they did. When the Runner itself is lost, the gateway answers for its executions from their records, and their workspaces wait for an operator ([Runner loss](runner-isolation.md#runner-loss)). See [runner isolation](runner-isolation.md) for the distinct transport and isolation boundaries.

## Planned execution coordination

Expand Down
2 changes: 1 addition & 1 deletion docs/devguard-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ Default participation remains `off`; `required` is an explicit operator choice i

## Initial Gateway recovery scope

**Status, P1-RECOVERY (owner directive 2026-10-14):** P1-RECOVERY is implemented one pull request per unit, as re-baselined in DevGuard's [P1-RECOVERY plan](https://github.com/novelKR/DevGuard/blob/165cb84a991fbc941b822681b47ef7dd07363878/docs/planning/milestones/P1-RECOVERY.md#re-baseline-2026-10-14). Its first unit, P1R-C01, adds the [independent Runner](runner-isolation.md#independent-runner), an opt-in mode that is not supported yet: an operator or a harness starts the Runner, and its processes, output and timeouts outlive each gateway, which detaches from it or stops it as its exit intent says. The second unit, P1R-C02, adds [process records](runner-isolation.md#process-records): the gateway records each execution in its operations database before it sends the execution to the Runner and follows it to its end, as the database's only writer. The third unit, P1R-C03, adds the [Claim](runner-isolation.md#claim): one connection at a time controls the Runner, under a controller epoch that each request changing a process or the workspace carries, and a gateway that lost its connection claims the Runner again instead of being restarted. While no gateway controls the Runner, any process of the same user that can reach its socket can claim it, an exposure the [Runner's documentation](runner-isolation.md#claim-exposure) states. The fourth unit, P1R-C04, adds [reconciliation](runner-isolation.md#reconciliation): after each Claim, the gateway compares its records, what the Runner holds and remembers, and for a `required` execution its DevGuard attempt, which the Runner looks up, and refuses new executions, patches and approval resumes with `RECOVERY_PENDING` only in the workspaces where an earlier controller left work, until it has reconciled them. A process found running holds its workspace again, an approval left resuming is consumed with the process the Runner created for it or granted again when the Runner proves that it created none, and a workspace whose accounts do not agree, or whose record names another Runner, stays refused for an operator. The fifth unit, P1R-C05, adds [Runner loss](runner-isolation.md#runner-loss): when the Runner is killed, crashes or stops, or the host restarts, the gateway answers `process_status` and `read_process` for its executions from their records, with a `lost_reason`, and each execution that had not ended becomes `unknown` and holds its workspace until an operator finds its processes and releases its record with `codespace-mcp records` ([Operations](operations.md#runner-loss)). The operator releases a `required` execution's record only once DevGuard no longer charges its attempt, which only DevGuard's administrator quiescence shows, since DevGuard answers a lookup only to the attempt's own instance; until then DevGuard keeps the lost Runner's instance, so a new Runner cannot register as the `codespace` consumer's one instance. The mode is supported only once the last unit qualifies it. In this mode the Runner is DevGuard's execution owner and reads the consumer secret from its own credential file, as DevGuard's [ADR-001](https://github.com/novelKR/DevGuard/blob/165cb84a991fbc941b822681b47ef7dd07363878/docs/planning/decisions.md#adr-001--one-registration-by-the-execution-owner) now provides; its gateway admits `required` workspaces only when the Runner states that it registers and launches through a launch helper. The rest of this section is the scope as planned.
**Status, P1-RECOVERY (owner directive 2026-10-14):** P1-RECOVERY is implemented one pull request per unit, as re-baselined in DevGuard's [P1-RECOVERY plan](https://github.com/novelKR/DevGuard/blob/165cb84a991fbc941b822681b47ef7dd07363878/docs/planning/milestones/P1-RECOVERY.md#re-baseline-2026-10-14). Its first unit, P1R-C01, adds the [independent Runner](runner-isolation.md#independent-runner), an opt-in mode: an operator or a harness starts the Runner, and its processes, output and timeouts outlive each gateway, which detaches from it or stops it as its exit intent says. The second unit, P1R-C02, adds [process records](runner-isolation.md#process-records): the gateway records each execution in its operations database before it sends the execution to the Runner and follows it to its end, as the database's only writer. The third unit, P1R-C03, adds the [Claim](runner-isolation.md#claim): one connection at a time controls the Runner, under a controller epoch that each request changing a process or the workspace carries, and a gateway that lost its connection claims the Runner again instead of being restarted. While no gateway controls the Runner, any process of the same user that can reach its socket can claim it, an exposure the [Runner's documentation](runner-isolation.md#claim-exposure) states. The fourth unit, P1R-C04, adds [reconciliation](runner-isolation.md#reconciliation): after each Claim, the gateway compares its records, what the Runner holds and remembers, and for a `required` execution its DevGuard attempt, which the Runner looks up, and refuses new executions, patches and approval resumes with `RECOVERY_PENDING` only in the workspaces where an earlier controller left work, until it has reconciled them. A process found running holds its workspace again, an approval left resuming is consumed with the process the Runner created for it or granted again when the Runner proves that it created none, and a workspace whose accounts do not agree, or whose record names another Runner, stays refused for an operator. The fifth unit, P1R-C05, adds [Runner loss](runner-isolation.md#runner-loss): when the Runner is killed, crashes or stops, or the host restarts, the gateway answers `process_status` and `read_process` for its executions from their records, with a `lost_reason`, and each execution that had not ended becomes `unknown` and holds its workspace until an operator finds its processes and releases its record with `codespace-mcp records` ([Operations](operations.md#runner-loss)). The operator releases a `required` execution's record only once DevGuard no longer charges its attempt, which only DevGuard's administrator quiescence shows, since DevGuard answers a lookup only to the attempt's own instance; until then DevGuard keeps the lost Runner's instance, so a new Runner cannot register as the `codespace` consumer's one instance. The sixth and last unit, P1R-C06, adds the [qualification protocol](recovery-qualification.md) with its harness suites, and the mode is supported only on the combinations that its run qualifies; none is qualified yet. [Operations](operations.md#independent-runner-adoption) describes how to adopt the mode and roll it back. In this mode the Runner is DevGuard's execution owner and reads the consumer secret from its own credential file, as DevGuard's [ADR-001](https://github.com/novelKR/DevGuard/blob/165cb84a991fbc941b822681b47ef7dd07363878/docs/planning/decisions.md#adr-001--one-registration-by-the-execution-owner) now provides; its gateway admits `required` workspaces only when the Runner states that it registers and launches through a launch helper. The rest of this section is the scope as planned.

P1-RECOVERY introduces an operator-selected independent Runner mode and explicit capability. Existing modes keep their current shutdown/disconnect contracts. InProcess shares the Gateway PID and is excluded from live Gateway restart recovery.

Expand Down
2 changes: 1 addition & 1 deletion docs/ko/agent-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ MCP 클라이언트 SDK로 stdio 또는 Streamable HTTP를 초기화하고, 초

실행 중인 명령은 작업 공간을 점유합니다. 패치를 적용하거나 다른 명령을 시작하려면 기존 명령이 끝날 때까지 기다리거나 종료하세요. 읽기와 검색은 계속 가능합니다. 개발 서버를 오래 실행하는 작업 흐름이라면 수정 전에 서버를 멈추는 절차가 필요합니다.

`workspace_info.execution.process.capabilities.lifetime`은 소유자가 MCP 세션이 아니라 러너 인스턴스임을 알립니다. Streamable HTTP나 MCP 클라이언트 끊김은 프로세스를 유지하므로, 저장한 `process_id`로 다시 연결하면 됩니다. UDS worker 연결이 끊기거나 게이트웨이가 종료되면(stdio EOF 포함) 소유 서브트리가 종료되고 핸들이 사라집니다. 재시작은 `process_id`를 복구하지 않습니다. 아직 지원하는 모드가 아닌 [독립 Runner](runner-isolation.md#independent-runner)에서는 `runner_disconnect`가 `keep_running`이고, `gateway_shutdown`은 게이트웨이가 detach하면 `keep_running`, Runner를 중지하면 `terminate`입니다. 그 게이트웨이가 하는 일은 `initialize.instructions`에서 확인하세요. 그 게이트웨이는 연결을 잃은 뒤 Runner를 다시 Claim하는 동안 요청을 `RUNNER_RECONNECTING`으로 거부합니다. 이 거부는 아무것도 보내지 않았고 승인도 소모하지 않았으므로, 잠시 뒤 재시도하세요. 그 뒤 이전에 작업을 시작한 workspace에서는 Runner와 그 workspace를 [대조](runner-isolation.md#reconciliation)할 때까지 새 명령, 패치, 승인 재개를 `RECOVERY_PENDING`으로 거부합니다. 잠시 뒤 재시도하면 되는지는 그 메시지가 알려 줍니다. 그곳에서 실행 중으로 확인한 프로세스는 지금처럼 workspace를 점유합니다. 게이트웨이가 Runner 자체를 잃으면 그 Runner의 프로세스에 대한 `process_status`와 `read_process`에는 기록으로 `lost_reason`과 함께 답하고, Runner가 필요한 다른 요청은 `RUNNER_DISCONNECTED`로 거부하며, 운영자가 그 기록을 풀 때까지 그 workspace를 계속 거부합니다. 다음 게이트웨이에서는 `RECOVERY_PENDING`으로 거부합니다([Runner 손실](runner-isolation.md#runner-loss)). spawn 응답을 받기 전에 `process_id`를 잃으면 `process_status`로 찾지 말고 명령을 중복 시작하지 마세요.
`workspace_info.execution.process.capabilities.lifetime`은 소유자가 MCP 세션이 아니라 러너 인스턴스임을 알립니다. Streamable HTTP나 MCP 클라이언트 끊김은 프로세스를 유지하므로, 저장한 `process_id`로 다시 연결하면 됩니다. UDS worker 연결이 끊기거나 게이트웨이가 종료되면(stdio EOF 포함) 소유 서브트리가 종료되고 핸들이 사라집니다. 재시작은 `process_id`를 복구하지 않습니다. [qualification](recovery-qualification.md)을 통과한 곳에서만 지원하는 [독립 Runner](runner-isolation.md#independent-runner)에서는 `runner_disconnect`가 `keep_running`이고, `gateway_shutdown`은 게이트웨이가 detach하면 `keep_running`, Runner를 중지하면 `terminate`입니다. 그 게이트웨이가 하는 일은 `initialize.instructions`에서 확인하세요. 그 게이트웨이는 연결을 잃은 뒤 Runner를 다시 Claim하는 동안 요청을 `RUNNER_RECONNECTING`으로 거부합니다. 이 거부는 아무것도 보내지 않았고 승인도 소모하지 않았으므로, 잠시 뒤 재시도하세요. 그 뒤 이전에 작업을 시작한 workspace에서는 Runner와 그 workspace를 [대조](runner-isolation.md#reconciliation)할 때까지 새 명령, 패치, 승인 재개를 `RECOVERY_PENDING`으로 거부합니다. 잠시 뒤 재시도하면 되는지는 그 메시지가 알려 줍니다. 그곳에서 실행 중으로 확인한 프로세스는 지금처럼 workspace를 점유합니다. 게이트웨이가 Runner 자체를 잃으면 그 Runner의 프로세스에 대한 `process_status`와 `read_process`에는 기록으로 `lost_reason`과 함께 답하고, Runner가 필요한 다른 요청은 `RUNNER_DISCONNECTED`로 거부하며, 운영자가 그 기록을 풀 때까지 그 workspace를 계속 거부합니다. 다음 게이트웨이에서는 `RECOVERY_PENDING`으로 거부합니다([Runner 손실](runner-isolation.md#runner-loss)). spawn 응답을 받기 전에 `process_id`를 잃으면 `process_status`로 찾지 말고 명령을 중복 시작하지 마세요.

## 보류된 변경 확인

Expand Down
Loading
Loading