* feat(gateway): add remote-exec cloud placements
* feat(codex): run cloud turns through remote exec
* fix(sandbox): quote ssh_config path directives containing whitespace
Crabbox lease keys default to ~/Library/Application Support/... on macOS;
unquoted IdentityFile/UserKnownHostsFile/CertificateFile arguments tokenize
on the space and fail as 'extra arguments'. Found via live remote-exec
cloud-worker proof.
* test: consolidate gateway maintenance schedule coverage
* fix(ci): invalidate plugin sdk declarations on state changes
* feat(codex): pass explicit skill selections as structured turn input
Thread OpenClaw-resolved explicit $skill selections through the reply
pipeline to the Codex app-server harness and emit them as structured
UserInput::Skill turn items when the Codex catalog (skills/list) knows the
same SKILL.md path. Codex then injects the skill natively and blocks its
text scanner from double-selecting the same name, while unmatched names
stay scannable for Codex-native-only skills and the prompt instruction
block keeps owning skills Codex cannot see. Catalog misses and RPC errors
fail open to the instruction path; the turn never fails on skill lookup.
Part of #123367
* fix(plugins): defer llama-cpp ssrf-runtime load out of the setup closure
The doctor-contract closure guard forbids the SSRF barrel in the
doctor/legacy-setup closure (cold-loads DNS, proxy state, logging); the
static import landed with the managed llama-server switch (#123105) and
first fails when a PR selects the guard lane. Defer to a dynamic import at
download time per the guard's stated remedy.
Codex byte-scans every turn text input for $name skill mentions and
[@name](plugin://...) links (codex-rs/skills/src/mentions.rs), so historical
$skill tokens inside OpenClaw's projected <conversation_context> block and
inbound quoted-reply/room-backlog context counted as current explicit
invocations and injected skill bodies the user never requested.
Neutralize mention sigils with same-length fullwidth lookalikes (the
escapeCodexChatText technique) in projected history and inbound context;
only the raw current request stays selectable.
Fixes#122812
* fix(sessions): isolated gateways no longer inherit HOME external session catalogs
A gateway on isolated state (custom OPENCLAW_STATE_DIR/CONFIG_PATH/OPENCLAW_HOME,
relocated home, or any named profile) listed, read, continued, archived, and
reopened the operator's real Claude Code/Codex/OpenCode/Pi sessions from the
process HOME. External catalogs now require the default install identity for
process-HOME scans: every catalog verb receives the isolation policy and rejects
HOME-fallback local targets, unknown providers fail closed unless they declare
supportsProcessHomeIsolation, and one structured warning records the skip.
Paired-node hosts and explicitly rooted stores (CLAUDE_CONFIG_DIR, CODEX_HOME,
OPENCODE_DB, Pi session dirs) keep working; default-identity gateways are
unchanged.
* fix(sessions): inject catalog HOME-isolation fact at registry construction
* chore(sdk): regenerate plugin API baselines after rebase
* chore(sdk): regenerate plugin API baselines after rebase
Safely finalize settled Codex turns when an overload arrives after tool completion. Keep other provider failures fail-closed and preserve channel delivery.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(codex): skip mirrors for sessionless runs
* fix(codex): restore openai model provider on media understanding turns
PR #122163 made thread/start modelProvider caller-supplied and updated the
web-search caller but missed media understanding, breaking its tests on main
full runs (cross-lane gap). Pass the provider explicitly and export the
retire binding prod now touches from the shared-client test mock.
* test(codex): align prompt assertions with reworded guidance
PR #121522 reworded the Skill Workshop guidance and cd7b7f639d reworded
the message-tool final-reply text; both updated core tests but missed
these codex mirror assertions (cross-lane gap breaking main full runs).
* test(codex): scope agent-projection fixture session to its agent
PR #114388 made multi-agent session ownership explicit; the atlas-scoped
projection test still used the shared main-scoped session key and now
trips AgentSelectionRequiredError (fourth cross-lane escape on main).
Use the selected harness for isolated title generation, including native Codex auth.
Retry failed dashboard titles from the first user message without overriding manual names.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* refactor: consolidate coercion ownership
Centralize four canonical coercion helpers, migrate exact core and plugin duplicates through narrow Plugin SDK facades, and enforce declaration and plugin-normalization ownership boundaries.
The sweep adds eight focused SDK exports while deleting more production and tooling code than it adds. User-visible behavior is unchanged except for safer equivalent object and UI parsing at existing boundaries.
* fix: guard integer option ownership
Register resolveIntegerOption with the canonical function owner and extend the declaration-guard fixture so future local duplicates fail validation.
* fix: keep integer helpers on numeric facade
Remove the unshipped duplicate string-coerce exports and route every affected plugin consumer through the existing number-runtime contract.
* fix: point numeric coercion to number runtime
Make boundary and declaration diagnostics recommend the canonical numeric facade, with failing-before coverage for both guidance paths.
Per-requester OAuth for HTTP MCP servers: in shared channels each trusted sender connects their own account. New config: mcp.servers.<name>.oauth.identity ("shared" default, byte-identical behavior) and gateway.publicOrigin (HTTPS except loopback) for the new GET /oauth/mcp/callback served on the Gateway HTTP server. Requester tokens are isolated per (channel, account, sender) in mcp_oauth_stores rows (no schema bump); callbacks correlate through a durable state-keyed one-time index with a 10-minute TTL; per-requester servers are fail-closed out of static/scheduled runtimes; unauthenticated senders get a sign-in link with a portable URL button; MCP config mutations clear requester credentials at the canonical owner. mcp status --json keeps the legacy authStatus fields additively. Proven by a two-user self-hosted-Executor E2E through the real gateway callback. Part of #122034.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* feat(agents): rename spawn_task tool to suggest_task
Models across vendors read the name spawn_task as 'starts background
work' and refuse to call it when the user has not asked to start
anything (Claude Sonnet 5, verbatim: 'spawn_task (which actively starts
background work)... Since you didn't ask me to start work, I'm flagging
this as a follow-up instead'). The tool only records a suggestion card,
so the name defeated the feature.
Rename the model-facing tool to suggest_task everywhere (catalog,
descriptors, presets, display config, OpenClawKit tool-display, docs)
and migrate persisted operator state via doctor: config tool policies
and cron SQLite toolsAllow entries that reference spawn_task are
rewritten to suggest_task. No runtime alias remains; runtime exposes
only the canonical name.
Live clean-room matrix on a dev gateway (virgin session per cell):
suggested-task-card phrasing now yields exactly one card on
anthropic/claude-sonnet-5, claude-haiku-4-5, openai/gpt-5.6-sol,
gpt-5.6-luna, and google/gemini-3.1-pro; pre-rename the same bait
produced prose-only follow-ups.
* chore(doctor): keep legacy tool-name predicate module-local
isLegacyTaskSuggestionToolName has no external consumers; the exported
form tripped the knip unused-export gate (deadcode:exports).
* fix(doctor): keep tool-name migration out of plugin-owned config
The rename migration traversed the whole raw config, so any object
carrying a toolsAllow key was rewritten - including opaque
plugins.entries.*.config, which core must not mutate. Scope the apply
pass to the typed core roots (tools, agents, channels, gateway) and pin
plugin config preservation in the test. Plugin-owned tool lists migrate
via the owning plugin's doctor contract instead.
* fix(ci): heal main deadcode and stale Swift protocol mirror
Unrelated main breakage blocking this PR's merge gate, healed here per
landing policy:
- #121653 left dead exports in src/skills/workshop: make
removeSkillCollectionDirectory and SkillCollectionRestoreResult
module-local; register collection-review.ts under the documented knip
ignoreIssues test-only-export convention (production runs it via the
scheduled maintenance loop).
- #121673 added ApprovalResolveParams.reviewer without regenerating the
Swift mirror; regenerate GatewayModels.swift (additive only).
* fix(ci): satisfy generic approval-runtime request signature in resolver test
Third main-heal carried by this PR: #121673 (9935ca3b30) left the
scoped-request mock's concrete inferred type unassignable to the generic
GatewayNativeApprovalRuntime request signature, breaking check-test-types
on main. Cast the mock at the runtime literal; assertions keep the Mock.
* chore(ci): drop approval-test cast superseded by main's typed mock rewrite
* chore(ci): drop duplicate knip entry superseded by main's heal
Keep configured engines selected before the current turn is persisted, then durably advance accepted turns across embedded and CLI paths. Preserve runtime plugin ownership and canonical transcript anchors through prepared execution.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Peter <noreply@anthropic.com>
Keep raw commands, paths, and provider errors out of ordinary chat while preserving explicit raw diagnostics and structured admin history.
Default command progress is status-only; `/verbose full` and `commandText: "raw"` retain diagnostic detail.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(codex): report harness context window as session contextTokens
Codex app-server reports model_context_window per turn. Carry it through the projector into the run result meta so session rows show the real window instead of the catalog's standard-tier input cap (272k vs 1M for gpt-5.6 models).
* improve(ui): compact chat context popover
Inline stat rows replace boxed tiles; zero-value cost rows and the whole cost section when empty are omitted; provider/model provenance lines are removed because the footer already shows the model; and the popover is narrowed to 300px.
* refactor(codex): split attempt-result assembly out of event projector
* fix(codex): seed attempt context window from startup binding
App-server v2 turn/started omits the core model_context_window, so thread/tokenUsage/updated is the only live carrier. Seed usage-less attempts from the retained startup binding rollout/session window so session metadata cannot regress to the catalog fallback.
* fix(codex): prefer native startup context window
Persisted session contextTokens has no source provenance and may contain the catalog fallback. Keep the minimum window for the conservative rotation fuse, but seed the projector from the native rollout when it is available.
* chore(plugin-sdk): regenerate api baseline (new format)
* revert(gateway): "prevent restart replay after final delivery" (broke 5 CI jobs)
Treat message(final=false) as progress and final=true or omission as the terminal source reply. Repeated terminal delivery now returns a non-error outcome without another provider send.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: 宇宙熊Yzx <53250620+849261680@users.noreply.github.com>
Co-authored-by: Markus <markuscontasul@gmail.com>
- forward taskSuggestionDeliveryMode through the Codex app-server dynamic tool build (same sibling-harness omission class previously fixed for clientCaps); spawn_task/dismiss_task silently never existed for GPT-backed sessions
- regression test asserting the forward, mirroring the existing clientCaps case
- spawn_task/dismiss_task descriptions rewritten with usage calibration: when to flag, when not to, scope-vs-flagging, prose-is-lost, operator-phrasing bridge, prompt self-containment, git-checkout cwd, registry ephemerality; param descriptions state where each field renders
Release-note context: GPT-backed sessions can now create suggested-task cards (the tools were silently absent on the Codex harness), and the tools carry much clearer model-facing guidance.