* refactor(anthropic): explore official Claude Agent SDK runtime
* refactor(anthropic): replace handwritten Claude sessions with SDK
* refactor(anthropic): collapse SDK live-session ownership
* refactor(anthropic): simplify SDK ownership and preserve live skills
* fix(anthropic): fence cancelled SDK runs before process startup
* fix(anthropic): harden SDK approvals, lifecycle, and packaging
* refactor(anthropic): own SDK process trees and streamline runtime
* fix(anthropic): repair rebased packaging and legacy test fixtures
Remove the bundled OpenProse plugin and /prose command now that upstream owns the maintained Agent Skill. Preserve /prose as migration documentation and let Doctor clean stale plugin configuration.
BREAKING CHANGE: The bundled OpenProse plugin and /prose command are removed.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
The exec docs claimed a per-call `host=node` request is always allowed
from `tools.exec.host=auto`, gating only `host=gateway` on whether a
sandbox runtime is active. The runtime treats both identically:
`isRequestedExecTargetAllowed` rejects `node` and `gateway` alike from
`auto` while a sandbox is available, and allows both when it is not.
Align the three pages that carried the asymmetric claim with the
test-locked runtime contract, and point readers at the explicit
`tools.exec.host=node` path the rejection error already recommends.
Refs #61009
* fix(dashboard): open widget links through the host instead of sandbox popups
Widget frames granted allow-popups/allow-popups-to-escape-sandbox to every
rendered widget, including grantState "none" widgets that never reach an
operator approval card. CSP has no navigate-to, so a popup bypassed the
connect-src 'none' containment those widgets otherwise run under. Scripted
window.open was blocked only by the document guard's open lock, which is
emitted solely when blockDescendantFrames is set, so two unrelated knobs had
to agree for the boundary to hold.
Restore both sandbox strings and route user-clicked links through the existing
ticket-bound bridge: a trusted click on a ticketed board widget's http(s)
target="_blank" anchor forwards to the Control UI, which opens the tab with
noopener,noreferrer. Links keep working for every rendered widget, the host
owns the scheme filter instead of trusting widget-authored rel attributes, and
scripted popups are impossible by construction rather than by coincidence.
Also collapses the unreachable controlUiBaseUrl branch and corrects both docs
pages, including the claim that links opened for every rendered widget, which
was never true for MCP-App board widgets.
Follow-up to #127315; refs #127314.
* fix(dashboard): open widget links through the Control UI external-url owner
The widget bridge opened links with a local window.open helper, which the
lint:ui:no-raw-window-open boundary guard rejects. Delegate to
openExternalUrlSafe(), the Control UI owner for external navigation: it
applies noopener/noreferrer, detaches the opener handle, and keeps one
canonical open path. The bridge keeps a narrower absolute-http(s) gate,
since widget-supplied links must not reach blob: URLs that the shared
external-link policy permits.
* fix(dashboard): route middle-button widget links and honor canceled clicks
Address ClawSweeper review on #128125.
The wrapper only handled primary click, so with popup permission removed from
both sandbox layers a middle-button activation silently did nothing. It also
listened on capture, so a widget handler's preventDefault could not cancel the
link the wrapper then opened itself.
Match the Control UI activation contract in ui/src/app/native-link-routing.ts:
listen for click and auxclick, gate on !defaultPrevented && !shiftKey &&
!altKey && (click+button 0 || auxclick+button 1), and listen on bubble so
widget cancellation stays effective. A middle click now routes for any widget
link, not just target=_blank, since middle-click always means new tab and
leaving plain links unrouted would keep the same silent-no-op class.
Move the wrapped-document test into src/canvas/wrap.test.ts: it exercises
buildWidgetDocument, so it belongs with its owner, and the added assertions
would otherwise push widget-tool.test.ts past the max-lines cap that AGENTS.md
forbids suppressing.
Reconcile code and command aliases after trusted-policy and hook rewrites so explicit blank or non-string mutations fail closed, including simultaneous valid rewrites. Add owner-boundary regression coverage and document the contract.
Treat blank code and command aliases as absent while preserving mismatch rejection when both aliases contain different instructions. Keep trusted hook and policy rewrites normalized at the Code Mode owner boundary.
Co-authored-by: Marvinthebored <marvin.assistant@lindsey.jp>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix: surface Codex input prompts across runtimes
Codex structured input now reaches bounded Gateway questions in native and ACP runs, with exact turn ownership, explicit unsupported outcomes, and cancellation fencing. Consume the published ACPX elicitation support.
* chore: align elicitation helpers with current guards
Use protocol-specific helper names required by current main and update the reservation regression to the generalized input owner.
* fix: formalize structured input SDK surface
Expose one documented, frozen agent-harness structured-input contract with runtime and subpath coverage, replacing the accidental function-property API.
* fix: satisfy elicitation architecture gates
Register the real-process ACPX fixture as an executable test root and move shared structured-input types into the boundary leaf to keep Knip and Madge clean.
* fix: remove structured input lint suppression
Preserve the rejected control and invisible-character ranges with an explicit code-point check so the production suppression inventory stays closed.
* feat(skills): add custodian-only skill library
* docs: document custodian skill library
* refactor(skills): make custodian skills concrete and non-interactive
Replace docs-link-first playbooks with verified openclaw config/message/infer
one-liners; drop interactive onboard references; encode the in-session
config-write policy boundary (models.*/secrets.* via trusted shell).
* fix(skills): corrections from live A/B testing of custodian skills
--agent required for models list/auth list in multi-agent rosters; drop
hanging channels capabilities probe; telegram target is chatId; roster-safe
prove via agent turn (infer model run has no --agent and dead-ends
multi-agent setups); note expected not-found on pre-setup config get.
* fix(skills): front-load harness plugin check in add-model-provider Gather
A/B timing showed the codex plugin dependency surfacing mid-Prove, at the
most expensive point (approval gate + turn boundary). Checking and
remediating during Gather removes the stall.
* fix(skills): keep status inventory unfiltered while scoping custodian source
buildWorkspaceSkillStatus forwarding agentId activated the loader's agent
allowlist filter, dropping excluded skills from the workshop's status view
(collection-review regression on CI). New closed agentSkillFilter mode lets
agentId scope custodian-source discovery without filtering the entry list,
per the documented status invariant.
* feat(agents): default to eager delegation in the main session
The delegation prompt section now defaults to "prefer" in each agent's
canonical main session and "suggest" elsewhere; explicit config wins in
both directions. The section is rewritten to be token-leaner and now
covers the hidden-vs-visible spawn distinction (hidden subagents are
invisible and auto-archived; deliverable-bearing work spawns
visible=true and replies with the link) plus the run-end notification
contract. The Messaging spawn-mechanics line is suppressed when the
Delegation section renders, and the stable Tooling visible:true hint is
aligned with the new guidance.
* perf(sessions): coalesce session-state wake bursts
Watched-session change notices woke the watcher's main session with the
generic 250ms heartbeat coalesce, so a burst of changes across several
watched sessions produced one wake per change. Wakes now coalesce for
20s; notices are already queued and deduped, so none are lost.
* test(agents): regenerate prompt snapshots after rebase
* test(sessions,agents): update sibling assertions for coalesced wakes and visible guidance
session-state-events tests advance timers past the new 20s wake
coalesce window; the sessions_spawn schema test tracks the updated
visible description.
Skill Workshop could autonomously rewrite or delete handwritten skills and discarded its own drop rationale. Workshop mutations are now gated on ledger-derived ownership (applied create proposals; unknown provenance fails closed to user-owned read-only), ownership claims end at drop and return on restore with failure-safe ordering, legacy backups stay restorable, every reconcile outcome persists with drop reasons in an additive table, and a bounded skill_workshop history action exposes them. Adopt/disown opt-in: #125711.
Co-authored with @jalehman (original ownership design).
Fixes#125652
* feat(dashboard): add session:progress board tile rendering the live progress card
Advertise the core-owned widget kind via hello controlUiWidgetKinds at operator.read.
Render it inline without an iframe from the session-progress-cards store.
Pin it with dashboard tool widget_put using pluginKind session:progress and optional props.sessionKey.
Follow up the progress-card unification from #125125.
* fix(dashboard): surface session progress load failures
Record protected progress-card read failures in the shared per-session store.
Render an actionable board-tile error with retry instead of indefinite loading.
Cover the rejected-read and successful-retry flow at the widget boundary.
* fix(dashboard): honor progress tile access and activity
Avoid progress-card reads while a retained board is inactive.
Distinguish sharing denial from transient load failures and show the correct remedy.
Qualify cross-session pinning docs and cover activation plus denial behavior.
* feat(agents): unify agent status into a durable progress_card
Replace the write-only update_plan to-do tool and the fragmented plan
rendering with one durable status artifact per session: progress_card
({plan?, markdown?}, replace-on-write, 8 KiB markdown / 50-step caps).
Cards persist in a lazy-additive session_progress_cards table in the
per-agent DB (no schema-version bump), broadcast progressCard.changed,
and render from the store with exactly one live placement per view
(session rail when visible, else the composer-adjacent bar); transcripts
collapse to one-line receipts, and the sidebar hovercard shows other
sessions' cards inline (markdown + <progress>, DOMPurify allowlist, no
iframes). The three stream-derived plan renderers and their dedup
heuristics are deleted.
Codex runs disable the native plan tool per thread
(tools.update_plan.enabled=false) and receive progress_card via the
dynamic-tool bridge; compaction restore now reinjects the card (steps +
bounded markdown). Card writes still emit the legacy plan stream event so
native apps and channels keep working until their per-platform
migrations. Policy names map update_plan -> progress_card; the shipped
tools.updatePlan=false kill switch is honored.
Net -277 production LOC; -480 test LOC.
* test(agents): regenerate Codex prompt snapshots for update_plan thread-config disable
* chore(protocol): allowlist progressCard.changed for native apps pending card migration
* fix(ci): repair progress card integration checks
* fix(codex): canonicalize native progress cards
* test(gateway): reconcile progress card method order
* test(codex): stabilize native approval fixture
* docs: document three-layer session ownership
User documentation for the session-ownership feature landed in #125057:
the immutable creator / assignable owner / participant-history model, the
Assign-to-me and Assign-to session menu actions, the sessions tool
assign_owner action, the sidebar Owners facet with Involving-me, the
pair-stack owner avatar, and agent-spawned session receipts (sessionUrl +
owner acknowledgement). Adds the sessions.assignOwner method and ownership
row projections to the protocol reference and a zh-CN glossary entry for
the new link label.
* docs: drop nonexistent header facepile overflow count
The chat header receives the already 4-capped participant projection and no
total count, so its overflow branch cannot render. Describe up to four
avatars instead (ClawSweeper P2).
Show an explicit waiting acknowledgment when sessions_yield ends an otherwise-silent interactive turn, while keeping private resume context out of channel delivery and preserving existing visible replies.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(skills): expand explicit references on agent turns
Route generic Gateway, CLI, webhook, and local agent turns through the same explicit skill-reference renderer as channel auto-replies. Keep original transcript text, preserve unknown slash behavior, and fail visibly for allowlist-hidden skills.
Maintainer review: scoped Option 1 — generic agent turns expand both $skill-name and leading /skill-name args through shared skill rendering; they do not run the channel command dispatcher, and all other slash commands retain their existing behavior.
* fix(skills): bound explicit reference prompts
* fix(skills): prefer allowed reference collisions
* fix(skills): preserve command invocation boundaries
* fix(skills): reject hidden channel slash commands
* perf(skills): skip literal dollar discovery
* fix(browser): support Chrome Web Store native bootstrap
* chore: keep browser release note in PR body
* docs(browser): document Store identity trust boundary
* docs(browser): correct Store recovery guidance
Skill and hook status now preserve OS incompatibility when `always` bypasses runtime requirements, matching existing loader behavior and clarified documentation.
Refs #122271 and #122331.