Skip to content
Merged
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ V2 development is paused; V1 is the active product line and is not feature-froze
- When two designs satisfy the current need, choose the one with fewer concepts, states, configuration paths, and maintenance costs.
- For model-facing execution, prefer structured process/argv and durable Job/observation primitives over shell-text orchestration. Keep shell as an escape hatch; structured lifecycle state is the source of truth for retry safety.
- Treat demonstrated host features such as MCP App orchestration as optional adapters. Core execution and Job semantics must remain protocol-, UI-, transport-, and OS-neutral.
- Never assume a model-facing HTTP/MCP request has stable model-window or Workflow Session identity. Treat requests as stateless unless that exact adapter/protocol contract explicitly supplies a stable `ClientWindow`. Stateless MCP 2026 must not derive hidden continuity from `Mcp-Session-Id`, connection state, credentials, project identity, or prior requests. Transport/audit/session correlation ids are not Workflow Session, model-context-retention, or authority proofs by themselves; use explicit durable task/session ids and recorder metadata only under their own contracts.

Product direction: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).

Expand Down
9 changes: 9 additions & 0 deletions crates/webcodex-core/src/shell_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,8 @@ pub struct ShellJobValidationMetadata {
pub effective_timeout_secs: u64,
pub sync_wait_secs: u64,
pub adapter: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub validation_target_id: Option<String>,
}

impl ShellJobValidationMetadata {
Expand All @@ -2163,6 +2165,12 @@ impl ShellJobValidationMetadata {
|| !self.steps[0].is_canonical()
|| self.effective_timeout_secs < 1
|| self.sync_wait_secs > self.effective_timeout_secs
|| self.validation_target_id.as_deref().is_some_and(|value| {
let Some(suffix) = value.strip_prefix("target:") else {
return true;
};
suffix.len() != 24 || !suffix.as_bytes().iter().all(u8::is_ascii_hexdigit)
})
{
return false;
}
Expand Down Expand Up @@ -4344,6 +4352,7 @@ mod filter_canonical_tests {
effective_timeout_secs: 1800,
sync_wait_secs: 10,
adapter: tool.to_string(),
validation_target_id: None,
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/webcodex-runner/src/main_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ fn runner_recovery_context_rejects_cross_product_go_test_metadata() {
effective_timeout_secs: 1800,
sync_wait_secs: 10,
adapter: "go_test".to_string(),
validation_target_id: None,
});
let context = context.clone();

Expand Down
20 changes: 12 additions & 8 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ is the id registered by that Runner in its `projects.d` registry.
## Task / Job / session continuity

- **Task** — a bounded unit of project work created by the model and reviewed
by a human. A project-bound Connector binds a chat window to its active task,
so follow-up instructions continue the same repository context. Tasks are
durable and can be resumed.
by a human. Tasks are durable and can be resumed. A project-bound Connector
may bind an active task only when its exact adapter/protocol supplies a stable
`ClientWindow`. Stateless MCP 2026 has no hidden window continuity: each
`task_start` is independent and existing work continues explicitly with its
durable `task_id` through `task_resume`.
- **Job** — a long-running command or validation that continues after the
initiating call returns. A single execution is promoted to a Job with the
same `job_id` when it outlives the synchronous grace period; it is never
Expand Down Expand Up @@ -117,11 +119,13 @@ See [SECURITY.md](../SECURITY.md) and [AUTH_MODEL.md](AUTH_MODEL.md).
## Persistence and recovery

The Server persists users, tokens, projects, audit entries, and OAuth rows in a
SQLite database. Task history and per-repository window mappings are durable.
Process-local "currently viewed project" state is deliberately discarded on
restart; a client that retains its transport window identity restores the
matching repository on its next `task_start`, and an explicit durable task id
recovers it otherwise.
SQLite database. Task history is durable. Per-repository window mappings exist
only for adapters that explicitly provide a stable `ClientWindow`; they are not
inferred from credentials, connections, or project identity. Process-local
"currently viewed project" state is deliberately discarded on restart.
Stateless MCP 2026 restores no hidden window mapping: callers continue exact work
with an explicit durable task id. A stateful adapter may restore only its exact
window/repository mapping under that adapter's own contract.

Runner Job state is reconciled from the Runner's inventory on reconnect.
Ordinary Jobs remain owned by the Runner process, so a Runner process restart
Expand Down
13 changes: 9 additions & 4 deletions docs/MCP.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,15 @@ code_impact

The Connector context already binds the configured repository. Start with
`task_start`; do not call project-discovery, session, or runtime tools, and do
not put a runtime project id in the prompt. The same chat window continues the
current repository automatically. `task_list` and `task_resume` are explicit
recovery tools when a client can no longer present its transport window
identity.
not put a runtime project id in the prompt. On Stateless MCP 2026, each
`tools/call` is application-stateless with respect to chat/window continuity:
`task_start` returns a durable `task_id`, and a later `task_start` begins
independent work even if the client sends a legacy `Mcp-Session-Id`. Continue
exact existing work explicitly with `task_resume(task_id)`; use `task_list` to
recover a task identity when needed. Do not infer continuity from the same chat,
connection, credential, project, or transport header. Older stateful adapter
contracts may expose a stable `ClientWindow`, but that is not a general MCP
property and is not Workflow Session or model-context identity.

## Golden coding loop

Expand Down
11 changes: 8 additions & 3 deletions docs/MCP.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,14 @@ code_impact
```

Connector context 已绑定配置的仓库。用 `task_start` 开始;不要调用项目发现、
session 或 runtime 工具,也不要在 prompt 里放 runtime project id。同一个聊天窗口
会自动延续当前仓库的工作。`task_list` 与 `task_resume` 是客户端无法再提供传输
窗口身份时的显式恢复工具。
session 或 runtime 工具,也不要在 prompt 里放 runtime project id。在 Stateless
MCP 2026 中,每次 `tools/call` 对聊天/窗口连续性而言都是应用层无状态请求:
`task_start` 会返回 durable `task_id`,后续再次 `task_start` 会开始独立工作,即使
客户端仍发送旧的 `Mcp-Session-Id` 也不能形成隐藏连续性。要继续现有工作,必须显式
调用 `task_resume(task_id)`;需要恢复 task identity 时可使用 `task_list`。不要从同一
聊天、连接、credential、project 或 transport header 推断连续性。旧的 stateful
adapter 契约可以显式提供 stable `ClientWindow`,但这不是 MCP 的普遍属性,也不是
Workflow Session 或 model-context identity。

## 黄金 coding 循环

Expand Down
12 changes: 12 additions & 0 deletions docs/agent/manual-window-collaboration.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ Retention is explicit. Each retained message carries internal latest-revision bo

Message observation is **not** a delivery receipt, **not** proof of model-context retention, **not** a subscription/stream, and **not** an orchestrator wake-up. It never automatically wakes a model or spawns/routes work. Room/Discussion remains only a future additive direction; this Workflow Session primitive does not create Room, participant, presence, typing, scheduler, worker-pool, or routing state.

## Runtime Collaboration Console

The Server-hosted `/runtime` page presents the same authoritative runtime and Workflow Session state without creating a second Session store or collaboration truth. It keeps a bounded Server overview, a focused per-Runner machine view, one compact/searchable Project selector, compact Workflow Session activity, and retained collaboration messages. The narrow Human Join composer is the only collaboration mutation affordance: it posts bounded Session messages through the canonical kernel path described below. Existing Project and Workflow Session console reads retain their `project:read` boundary; Server-wide/Runner-wide facts and full collaboration message/observation/post routes require `runtime:read` and still re-authorize the exact target Session/project.

The collaboration panel establishes an observation baseline before reading the retained snapshot, then uses bounded long-polls and merges deltas by `message_id`. `has_more` is drained before the next wait, while `history_lost` causes a retained-board reload and a new baseline rather than claiming complete history. Manual Refresh reports visible refreshing/success/failure state and preserves prior usable data; a healthy live collaboration loop is not restarted merely because Refresh was clicked, while a paused/failed loop performs a retained reload, new baseline, and bounded reconnect. Session liveness is derived only from WebCodex facts such as a running call, owned running Job, or recent retained activity; it never claims to know whether the host/model is processing, frozen, or present. All aggregate counts remain bounded/truncation-aware. Browser observation remains UI refresh only: it is not a model wake-up, subscription, participant-presence mechanism, scheduler, worker claim, or execution lease.

## Provenance is metadata, not authority

A completed answer can identify the independent worker with `author_session_id`. That value is derived first from the trusted recording Session that owns the completion tool evidence, then from the trusted current-Session binding only when no recording Session exists. It is not a caller-authored claim. In stateless MCP 2026, `recording_session_id` is explicit wrapper provenance metadata, not a transport Session and not an authority grant; the legacy `mcp-session-id` header remains irrelevant.
Expand Down Expand Up @@ -119,6 +125,12 @@ Do not treat todo state, `reply_to`, `completion_key`, `author_session_id`, or `

When multiple workers operate on the same source, use normal Git/WebCodex Project isolation and revalidate current state before acting on collaboration messages.

## Human join and acknowledgement ergonomics

The hosted Runtime Console may post `note`, `guidance`, `question`, and `todo` messages into an exact authorized Workflow Session through the same `post_session_message` kernel path. This is a browser affordance, not a Participant entity, membership record, presence signal, or identity-spoofing surface. The browser route keeps the current collaboration metadata authority policy (`runtime:read`) and still applies the stored Session/project authority fence.

High-priority Guidance may opt into `requires_ack`. A Stateless MCP 2026 caller can echo the visible message id in `ack_session_message_ids` on an otherwise ordinary recorded tool call. The original tool executes normally whether the ACK is present, missing, unknown, foreign, or stale. A valid ACK suppresses that Guidance body only for the same request/response. If the model later omits the ACK while the Guidance remains open, the Server may piggyback the bounded body again. The first observed ACK timestamp is observability only; it must never be described as delivered, read, or currently remembered. Durable completion still requires normal message resolution.

## Bounded payload guidance

Keep todos and answers small enough to be useful as handoff state. Prefer stable references over copied authoritative objects:
Expand Down
Loading
Loading