Skip to content

docs: add Kubernetes install guide, setup script, and manifests#34492

Merged
sallyom merged 2 commits intoopenclaw:mainfrom
sallyom:k8s-install
Mar 12, 2026
Merged

docs: add Kubernetes install guide, setup script, and manifests#34492
sallyom merged 2 commits intoopenclaw:mainfrom
sallyom:k8s-install

Conversation

@sallyom
Copy link
Copy Markdown
Contributor

@sallyom sallyom commented Mar 4, 2026

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: Starter example for Kubernetes

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #

User-visible / Behavior Changes

List user-visible changes (including defaults/config).
If none, write None.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: Mac(arm), Linux
  • Runtime/container: container/podman

Steps

# requires K8s env
# can run ./k8s/create-kind.sh first for local testing
git clone [email protected]:openclaw/openclaw && cd openclaw
./k8s/setup.sh   # gateway token is in k8s/.env
kubectl port-forward svc/openclaw 18789:18789 -n openclaw
# open http://localhost:18789

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

@openclaw-barnacle openclaw-barnacle bot added docs Improvements or additions to documentation size: L maintainer Maintainer-authored PR labels Mar 4, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 549cba1bcf

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 4, 2026

Greptile Summary

This PR adds a complete Kubernetes deployment setup for OpenClaw, including Kustomize manifests, a deploy.sh script that securely handles secret generation, a create-kind.sh script for local testing, and accompanying documentation. The approach is well-thought-out with good security hardening (read-only root filesystem, dropped capabilities, non-root user) and clear documentation.

Key issues found:

  • OPENROUTER_API_KEY never reaches the containerdeploy.sh stores the key in the Kubernetes Secret and validates it as a supported provider, but deployment.yaml only injects ANTHROPIC_API_KEY, OPENAI_API_KEY, and GEMINI_API_KEY. Users who configure OpenRouter will see their key silently ignored at runtime.
  • The main application image (ghcr.io/openclaw/openclaw:slim) uses a mutable floating tag. The init container was already pinned to busybox:1.37 after a prior review; applying the same treatment to the application image would make the manifest fully reproducible.

Confidence Score: 3/5

  • Safe to merge after fixing the missing OPENROUTER_API_KEY environment variable in deployment.yaml
  • One clear logic bug (OPENROUTER_API_KEY stored in Secret but never injected into the container) would silently break a supported provider for users. Everything else — secret handling, security hardening, documentation, and script logic — is solid.
  • k8s/manifests/deployment.yaml — missing OPENROUTER_API_KEY env var entry

Last reviewed commit: afa728e

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0447568fec

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@sallyom sallyom marked this pull request as draft March 7, 2026 19:27
@sallyom sallyom force-pushed the k8s-install branch 3 times, most recently from 6805e23 to 2595016 Compare March 9, 2026 07:12
@sallyom sallyom force-pushed the k8s-install branch 2 times, most recently from c775e3e to 29482eb Compare March 9, 2026 12:47
@sallyom sallyom marked this pull request as ready for review March 9, 2026 12:51
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: afa728e641

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot bot commented Mar 9, 2026

🔒 Aisle Security Analysis

We found 5 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Unpinned/mutable container images in Kubernetes Deployment (supply-chain risk)
2 🔵 Low Gateway token printed to stdout via --show-token (risk of CI/log leakage)
3 🔵 Low Clipboard command injection risk: unquoted namespace in printed kubectl commands
4 🔵 Low Terminal escape / log injection via untrusted cluster name in create-kind.sh output
5 🔵 Low Potential node/pod DoS via unbounded emptyDir mounted at /tmp (no sizeLimit / ephemeral-storage limits)

1. 🟡 Unpinned/mutable container images in Kubernetes Deployment (supply-chain risk)

Property Value
Severity Medium
CWE CWE-494
Location scripts/k8s/manifests/deployment.yaml:25-53

Description

The Kubernetes Deployment uses mutable image tags without digest pinning:

  • busybox:1.37 for the init container
  • ghcr.io/openclaw/openclaw:slim for the main gateway container

This introduces a supply-chain and reproducibility risk:

  • Tags can be retagged to different content over time (or by a compromised registry/publisher account)
  • Combined with imagePullPolicy: IfNotPresent, a pod can run different image content depending on node cache state (non-reproducible) and can unexpectedly change after rescheduling
  • A compromised/malicious image update would execute inside the cluster with access to mounted volumes (PVC) and network

Vulnerable code:

image: busybox:1.37
imagePullPolicy: IfNotPresent
...
image: ghcr.io/openclaw/openclaw:slim
imagePullPolicy: IfNotPresent

Recommendation

Pin images to immutable digests (preferred) or at minimum to versioned release tags.

Preferred: digest pinning

initContainers:
  - name: init-config
    image: busybox@​sha256:<digest>
containers:
  - name: gateway
    image: ghcr.io/openclaw/openclaw@​sha256:<digest>

If you must use tags, use versioned tags (not slim/latest style) and consider imagePullPolicy: Always for faster rollouts of expected updates:

image: ghcr.io/openclaw/openclaw:2026.3.1
imagePullPolicy: Always

Additionally consider enforcing this cluster-wide with an admission policy (OPA/Gatekeeper/Kyverno) requiring digest-pinned images for production namespaces.


2. 🔵 Gateway token printed to stdout via --show-token (risk of CI/log leakage)

Property Value
Severity Low
CWE CWE-532
Location scripts/k8s/deploy.sh:152-158

Description

The Kubernetes deploy script supports --show-token, which prints the gateway authentication token directly to stdout.

This is an information disclosure risk because stdout is commonly:

  • captured in CI logs
  • stored in terminal scrollback / shared session logs
  • forwarded to centralized log collectors

If the token leaks, anyone who can reach the gateway service can authenticate as an operator (depending on how the token is used by the application).

Vulnerable code paths:

  • During secret creation/update it prints the token from the local variable:
echo "Gateway token: $TOKEN"
  • During deploy it prints the token fetched from the cluster secret:
echo "  $(kubectl get secret openclaw-secrets -n "$NS" -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d)"

Recommendation

Harden token display to reduce accidental leakage:

  • Only allow printing when stdout is a TTY (not in CI/pipes)
  • Print to the controlling terminal (/dev/tty) rather than stdout
  • Require an explicit acknowledgement flag (e.g., --show-token --i-understand)
  • Prefer printf over echo for safer output handling

Example:

if $SHOW_TOKEN; then
  if [[ ! -t 1 ]]; then
    echo "Refusing to print token because stdout is not a TTY. Use: kubectl get secret ..." >&2
    exit 1
  fi

  # Write to the terminal directly (avoids piping into logs)
  printf 'Gateway token: %s\n' "$TOKEN" > /dev/tty
fi

Alternatively, remove --show-token and always instruct users to retrieve the token via kubectl get secret ... (least surprise).


3. 🔵 Clipboard command injection risk: unquoted namespace in printed kubectl commands

Property Value
Severity Low
CWE CWE-74
Location scripts/k8s/deploy.sh:155-158

Description

The Kubernetes deploy helper prints copy/paste-ready shell commands that interpolate the namespace (NS) without safe quoting/escaping.

  • NS is derived from the environment variable OPENCLAW_NAMESPACE (user-controlled).
  • The script prints suggested commands containing -n $NS (unquoted) for users to copy/paste.
  • If OPENCLAW_NAMESPACE contains shell metacharacters (e.g., ;, &&, $(), backticks) or whitespace, a user who copies the printed line into a shell could execute unintended additional commands (clipboard injection pattern).

Vulnerable output examples:

kubectl get secret openclaw-secrets -n $NS -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d && echo
kubectl port-forward svc/openclaw 18789:18789 -n $NS

Note: the script’s actual kubectl invocations correctly quote "$NS"; the risk is specifically in the emitted guidance users are encouraged to run.

Recommendation

Always escape/quote interpolated variables in printed shell commands, or validate inputs before printing.

Option A (preferred): shell-escape with printf %q

printf "  kubectl get secret openclaw-secrets -n %q -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d && echo\n" "$NS"
printf "  kubectl port-forward svc/openclaw 18789:18789 -n %q\n" "$NS"

Option B: strict namespace validation (DNS label)

if [[ ! "$NS" =~ ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ ]] || ((${#NS} > 63)); then
  echo "Invalid namespace: $NS" >&2
  exit 1
fi

(You can also do both: validate + %q.)


4. 🔵 Terminal escape / log injection via untrusted cluster name in create-kind.sh output

Property Value
Severity Low
CWE CWE-117
Location scripts/k8s/create-kind.sh:29-32

Description

The Kind bootstrap script prints user-controlled values (e.g., CLUSTER_NAME from --name) using echo -e in logging helpers.

  • CLUSTER_NAME is taken directly from CLI arguments without validation or sanitization.
  • Logging helpers use echo -e ... $1, which interprets backslash escapes; additionally, terminals will interpret embedded control characters/ANSI escape sequences.
  • A crafted cluster name (e.g., containing \e]8;;...\a OSC-8 hyperlinks, clear-screen sequences, or other control chars) can:
    • Manipulate terminal output / CI logs (hide or spoof messages)
    • Potentially trick users into copying malicious commands from logs (notably the “To recreate it, run: ...” message)

Vulnerable code:

info()    { echo -e "${BLUE}[INFO]${NC}  $1"; }
...
CLUSTER_NAME="$2"; shift 2
...
info "Deleting Kind cluster '$CLUSTER_NAME'..."

Recommendation

Avoid echo -e and neutralize control characters in any user-controlled value before printing.

Option A (recommended): validate cluster names strictly (Kind cluster names can be limited to safe characters):

validate_cluster_name() {
  [[ "$1" =~ ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ ]] || \
    fail "Invalid cluster name. Use lowercase letters, numbers, and hyphens only."
}

# after parsing
validate_cluster_name "$CLUSTER_NAME"

Option B: sanitize output before logging (strip non-printable/control chars):

sanitize_for_terminal() {
  # remove ASCII control chars (incl ESC) and DEL
  LC_ALL=C printf '%s' "$1" | tr -d '\000-\037\177'
}

info() {
  local msg
  msg=$(sanitize_for_terminal "$1")
  printf '%b%s\n' "${BLUE}[INFO]${NC}  " "$msg"
}

Also consider not printing copy/paste-ready shell commands containing untrusted values, or ensure they are safely shell-escaped (e.g., via printf '%q').


5. 🔵 Potential node/pod DoS via unbounded emptyDir mounted at /tmp (no sizeLimit / ephemeral-storage limits)

Property Value
Severity Low
CWE CWE-400
Location scripts/k8s/manifests/deployment.yaml:124-146

Description

The Deployment mounts an emptyDir volume at /tmp with no size limit, and the pod/container does not set ephemeral-storage requests/limits.

Impact:

  • Any component that writes to /tmp (application bugs, untrusted inputs, or deliberate abuse) can consume large amounts of node ephemeral storage.
  • This can trigger DiskPressure and evictions, causing denial of service for this workload and potentially other workloads sharing the node.

Vulnerable code:

volumes:
  - name: tmp-volume
    emptyDir: {}
...
volumeMounts:
  - name: tmp-volume
    mountPath: /tmp

Recommendation

Constrain temporary storage usage by setting emptyDir.sizeLimit and/or container ephemeral-storage requests/limits.

Example:

containers:
  - name: gateway
    resources:
      requests:
        cpu: 250m
        memory: 512Mi
        ephemeral-storage: 512Mi
      limits:
        cpu: "1"
        memory: 2Gi
        ephemeral-storage: 1Gi

volumes:
  - name: tmp-volume
    emptyDir:
      sizeLimit: 1Gi

If /tmp primarily needs to be in-memory and small, consider:

emptyDir:
  medium: Memory
  sizeLimit: 256Mi

Choose values appropriate to expected workloads and node capacity.


Analyzed PR: #34492 at commit 1f4f1e7

Last updated on: 2026-03-12T07:16:36Z

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf35e0ff17

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@sallyom sallyom force-pushed the k8s-install branch 2 times, most recently from 5b4359d to 2200635 Compare March 12, 2026 04:36
@sallyom sallyom force-pushed the k8s-install branch 2 times, most recently from bb08096 to b3dc7e3 Compare March 12, 2026 04:49
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b3dc7e3ac6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@sallyom sallyom force-pushed the k8s-install branch 3 times, most recently from c270a7e to beec344 Compare March 12, 2026 05:10
@sallyom
Copy link
Copy Markdown
Contributor Author

sallyom commented Mar 12, 2026

resolved the 5 security findings

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9ee3f9d3d0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@sallyom sallyom force-pushed the k8s-install branch 2 times, most recently from 4021f1e to 48cae98 Compare March 12, 2026 05:25
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48cae98fe0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@openclaw-barnacle openclaw-barnacle bot added the scripts Repository scripts label Mar 12, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f4f1e7da6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

# ---------------------------------------------------------------------------
# Check if cluster already exists
# ---------------------------------------------------------------------------
if KIND_EXPERIMENTAL_PROVIDER="$CONTAINER_CMD" kind get clusters 2>/dev/null | grep -qx "$CLUSTER_NAME"; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Probe existing Kind clusters across both providers

When both Docker and Podman are running, this script always picks Podman first, then checks cluster existence only through that provider (KIND_EXPERIMENTAL_PROVIDER="$CONTAINER_CMD" kind get clusters). If the user’s openclaw cluster was previously created with Docker, --delete reports it as missing and normal runs try to create a second cluster with the same name/context, which can leave kubeconfig/context state inconsistent and send subsequent deploys to an unexpected cluster.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edge case we don't need to account for

@sallyom sallyom merged commit 8e0e4f7 into openclaw:main Mar 12, 2026
29 checks passed
GGzili pushed a commit to GGzili/moltbot that referenced this pull request Mar 12, 2026
…claw#34492)

* add docs and manifests for k8s install

Signed-off-by: sallyom <[email protected]>

* changelog

Signed-off-by: sallyom <[email protected]>

---------

Signed-off-by: sallyom <[email protected]>
mrosmarin added a commit to mrosmarin/openclaw that referenced this pull request Mar 12, 2026
* main: (120 commits)
  docs: sync Feishu secretref credential matrix
  Subagents: stop retrying external completion timeouts (openclaw#41235) (openclaw#43847)
  Security: require Feishu webhook encrypt key (openclaw#44087)
  Hardening: normalize Unicode command obfuscation detection (openclaw#44091)
  Hardening: tighten preauth WebSocket handshake limits (openclaw#44089)
  Security: preserve Feishu reaction chat type (openclaw#44088)
  Hardening: require LINE webhook signatures (openclaw#44090)
  fix(mattermost): pass mediaLocalRoots through reply delivery (openclaw#44021)
  ci: tighten cache docs and node22 gate
  ci: restore PR pnpm cache fallback
  ci: harden pnpm sticky cache on PRs
  build: align Node 22 guidance with 22.16 minimum
  build: raise Node 22 compatibility floor to 22.16
  build: default to Node 24 and keep Node 22 compat
  Agents: adapt pi-ai oauth and payload hooks
  fix(status): resolve context window by provider-qualified key, prefer max on bare-id collision, solve openclaw#35976 (openclaw#36389)
  fix: carry observed overflow token counts into compaction (openclaw#40357)
  fix(telegram): allow fallback models in /model validation (openclaw#40105)
  feat(mattermost): add replyToMode support (off | first | all) (openclaw#29587)
  docs: add Kubernetes install guide, setup script, and manifests (openclaw#34492)
  ...
steipete pushed a commit to BruceMacD/openclaw that referenced this pull request Mar 13, 2026
…claw#34492)

* add docs and manifests for k8s install

Signed-off-by: sallyom <[email protected]>

* changelog

Signed-off-by: sallyom <[email protected]>

---------

Signed-off-by: sallyom <[email protected]>
palomyates516-alt pushed a commit to palomyates516-alt/lqlopenclaw that referenced this pull request Mar 13, 2026
…claw#34492)

* add docs and manifests for k8s install

Signed-off-by: sallyom <[email protected]>

* changelog

Signed-off-by: sallyom <[email protected]>

---------

Signed-off-by: sallyom <[email protected]>
fabianbaier added a commit to yourclaw/openclaw that referenced this pull request Mar 19, 2026
* Skills: normalize emoji presentation across outputs

* Terminal: consume unsupported escape bytes in tables

* fix(terminal): stabilize skills table width across Terminal.app and iTerm (#42849)

* Terminal: measure grapheme display width

* Tests: cover grapheme terminal width

* Terminal: wrap table cells by grapheme width

* Tests: cover emoji table alignment

* Terminal: refine table wrapping and width handling

* Terminal: stop shrinking CLI tables by one column

* Skills: use Terminal-safe emoji in list output

* Changelog: note terminal skills table fixes

* Skills: normalize emoji presentation across outputs

* Terminal: consume unsupported escape bytes in tables

* fix(gateway): enforce caller-scope subsetting in device.token.rotate

device.token.rotate accepted attacker-controlled scopes and forwarded
them to rotateDeviceToken without verifying the caller held those
scopes. A pairing-scoped token could rotate up to operator.admin on
any already-paired device whose approvedScopes included admin.

Add a caller-scope subsetting check before rotateDeviceToken: the
requested scopes must be a subset of client.connect.scopes via the
existing roleScopesAllow helper. Reject with missing scope: <scope>
if not.

Also add server.device-token-rotate-authz.test.ts covering both the
priv-esc path and the admin-to-node-invoke chain.

Fixes GHSA-4jpw-hj22-2xmc

* fix(gateway): propagate real gateway client into plugin subagent runtime

Plugin subagent dispatch used a hardcoded synthetic client carrying
operator.admin, operator.approvals, and operator.pairing for all
runtime.subagent.* calls. Plugin HTTP routes with auth:"plugin" require
no gateway auth by design, so an unauthenticated external request could
drive admin-only gateway methods (sessions.delete, agent.run) through
the subagent runtime.

Propagate the real gateway client into the plugin runtime request scope
when one is available. Plugin HTTP routes now run inside a scoped
runtime client: auth:"plugin" routes receive a non-admin synthetic
operator.write client; gateway-authenticated routes retain admin-capable
scopes. The security boundary is enforced at the HTTP handler level.

Fixes GHSA-xw77-45gv-p728

* fix(agents): add nodes to owner-only tool policy fallbacks

The nodes tool was missing from OWNER_ONLY_TOOL_NAME_FALLBACKS in
tool-policy.ts. applyOwnerOnlyToolPolicy() correctly removed gateway
and cron for non-owners but kept nodes, which internally issues
privileged gateway calls: node.pair.approve (operator.pairing) and
node.invoke (operator.write).

A non-owner sender could approve pending node pairings and invoke
arbitrary node commands, extending to system.run on paired nodes.

Add nodes to the fallback owner-only set. Non-owners no longer receive
the nodes tool after policy application; owners retain it.

Fixes GHSA-r26r-9hxr-r792

* Onboard: add Ollama auth flow and improve model defaults

Add Ollama as a auth provider in onboarding with Cloud + Local mode
selection, browser-based sign-in via /api/me, smart model suggestions
per mode, and graceful fallback when the default model is unavailable.

- Extract shared ollama-models.ts
- Auto-pull missing models during onboarding
- Non-interactive mode support for CI/automation

Closes #8239
Closes #3494

Co-Authored-By: Jeffrey Morgan <[email protected]>

* fix: tighten Ollama onboarding cloud handling (#41529) (thanks @BruceMacD)

* Fix env proxy bootstrap for model traffic (#43248)

* Fix env proxy bootstrap for model traffic

* Address proxy dispatcher review followups

* Fix proxy env precedence for empty lowercase vars

* fix(telegram): clear stale retain before transient final fallback (#41763)

Merged via squash.

Prepared head SHA: c0940838bce6c4ed052579a4773b934c08826e0a
Co-authored-by: obviyus <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus

* fix(voice-call): add speed and instructions to OpenAI TTS config schema (#39226)

Merged via squash.

Prepared head SHA: 775e3063b58d4629f59021798ab1c7222ff069d9
Co-authored-by: ademczuk <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus

* fix(signal): add missing accountUuid to Zod config schema (#35578)

Merged via squash.

Prepared head SHA: 39e8e9ad62f65fa70e1a660e65f19d9452ae0412
Co-authored-by: ingyukoh <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(config): add missing editMessage and createForumTopic to Telegram actions schema (#35498)

Merged via squash.

Prepared head SHA: 631fc14832402c5a6659fdb1a24a37ae67832ed0
Co-authored-by: ingyukoh <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(agents): check billing errors before context overflow heuristics (#40409)

Merged via squash.

Prepared head SHA: c88f89c462d87957a4c6c51a23ab997fd307059d
Co-authored-by: ademczuk <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* feat(memory): add gemini-embedding-2-preview support (#42501)

Merged via squash.

Prepared head SHA: c57b1f8ba2ca65f4946afe94a9137ee8c05c8c64
Co-authored-by: BillChirico <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix: use unknown instead of rate_limit as default cooldown reason (#42911)

Merged via squash.

Prepared head SHA: bebf6704d7b02b9a32935c0006eac2d76694fec0
Co-authored-by: VibhorGautam <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(discord): add missing autoThread to DiscordGuildChannelConfig type (#35608)

Merged via squash.

Prepared head SHA: e62b88bb01bf13ba2759c51095be07c3a47536dc
Co-authored-by: ingyukoh <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(agents): prevent false billing error replacing valid response text (#40616)

Merged via squash.

Prepared head SHA: 05179362b439ff3b0330df3eb6a28aa05396ea9d
Co-authored-by: ingyukoh <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* memory: normalize Gemini embeddings (#43409)

Merged via squash.

Prepared head SHA: 70613e022540b4d923d55c3a6ca51715cc6f46c4
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix: recognize Venice 402 billing errors for model fallback (#43205)

Merged via squash.

Prepared head SHA: 1f6b10b9d934235e71f279f888292139c4a85aa6
Co-authored-by: Squabble9 <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix: restore web tools to coding profile (#43436)

* fix: restore web tools to coding profile

* fix: tighten tool catalog regression assertion

* chore: refresh dependencies except carbon

* test(agents): cover openai responses phase replay

* fix(ollama): share model context discovery

* fix(onboard): default custom Ollama URL to native API

* docs(ollama): align onboarding guidance with code

* test: align pi-ai oauth mocks

* fix(ws): preserve payload overrides

* fix(gateway): run before_tool_call for HTTP tools

* test(gateway): widen before tool hook mock typing (#43476)

* test(gateway): widen before tool hook mock typing

* chore: update pnpm.lock

* Gateway/Dashboard: surface config validation issues (#42664)

Merged via squash.

Prepared head SHA: 43f66cdcf04a14d5381a5a2f14e291a52a8b7389
Co-authored-by: huntharo <[email protected]>
Co-authored-by: huntharo <[email protected]>
Reviewed-by: @huntharo

* Memory: add multimodal image and audio indexing (#43460)

Merged via squash.

Prepared head SHA: a994c07190a2062322f459c928b6cd74f9803d88
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(hooks): add missing trigger and channelId to agent_end, llm_input, and llm_output hook contexts (#42362)

Merged via squash.

Prepared head SHA: e6d7b7e31aa6ae12813b4609adb6e569a4084d08
Co-authored-by: zhoulf1006 <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13

* Memory: revalidate multimodal files before indexing

* preserve openai phase param

* chore: bump version to 2026.3.10

* fix(terminal): sanitize skills JSON and fallback on legacy Windows (#43520)

* Terminal: use ASCII borders on legacy Windows consoles

* Skills: sanitize JSON output for control bytes

* Changelog: credit terminal follow-up fixes

* Update CHANGELOG.md

* Update CHANGELOG.md

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Skills: strip remaining escape sequences from JSON output

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix: repair bundled plugin dirs after npm install

* fix(daemon): replace bootout with kickstart -k for launchd restarts on macOS

On macOS, launchctl bootout permanently unloads the LaunchAgent plist.
Even with KeepAlive: true, launchd cannot respawn a service whose plist
has been removed from its registry. This left users with a dead gateway
requiring manual 'openclaw gateway install' to recover.

Affected trigger paths:
- openclaw gateway restart from an agent session (#43311)
- SIGTERM on config reload (#43406)
- Gateway self-restart via SIGTERM (#43035)
- Hot reload on channel config change (#43049)

Switch restartLaunchAgent() to launchctl kickstart -k, which force-kills
and restarts the service without unloading the plist. When the restart
originates from inside the launchd-managed process tree, delegate to a
new detached handoff helper (launchd-restart-handoff.ts) to avoid the
caller being killed mid-command. Self-restart paths in process-respawn.ts
now schedule the detached start-after-exit handoff before exiting instead
of relying on exit/KeepAlive timing.

Fixes #43311, #43406, #43035, #43049

* fix(gateway): enforce browser origin check regardless of proxy headers

In trusted-proxy mode, enforceOriginCheckForAnyClient was set to false
whenever proxy headers were present. This allowed browser-originated
WebSocket connections from untrusted origins to bypass origin validation
entirely, as the check only ran for control-ui and webchat client types.

An attacker serving a page from an untrusted origin could connect through
a trusted reverse proxy, inherit proxy-injected identity, and obtain
operator.admin access via the sharedAuthOk / roleCanSkipDeviceIdentity
path without any origin restriction.

Remove the hasProxyHeaders exemption so origin validation runs for all
browser-originated connections regardless of how the request arrived.

Fixes GHSA-5wcw-8jjv-m286

* fix: harden state dir permissions during onboard

* fix(whatsapp): trim leading whitespace in direct outbound sends (#43539)

Trim leading whitespace from direct WhatsApp text and media caption sends.

Also guard empty text-only web sends after trimming.

* fix(node-host): extend script-runner set and add fail-closed guard for mutable-file approval

tsx, jiti, ts-node, ts-node-esm, vite-node, and esno were not recognized
as interpreter-style script runners in invoke-system-run-plan.ts. These
runners produced mutableFileOperand: null, causing invoke-system-run.ts
to skip revalidation entirely. A mutated script payload would execute
without the approval binding check that node ./run.js already enforced.

Two-part fix:
- Add tsx, jiti, and related TypeScript/ESM loaders to the known script
  runner set so they produce a valid mutableFileOperand from the planner
- Add a fail-closed runtime guard in invoke-system-run.ts that denies
  execution when a script run should have a mutable-file binding but the
  approval plan is missing it, preventing unknown future runners from
  silently bypassing revalidation

Fixes GHSA-qc36-x95h-7j53

* fix(daemon): address clanker review findings for kickstart restart

Bug 1 (high): replace fixed sleep 1 with caller-PID polling in both
kickstart and start-after-exit handoff modes. The helper now waits until
kill -0 $caller_pid fails before issuing launchctl kickstart -k.

Bug 2 (medium): gate enable+bootstrap fallback on isLaunchctlNotLoaded().
Only attempt re-registration when kickstart -k fails because the job is
absent; all other kickstart failures now re-throw the original error.

Follows up on 3c0fd3dffe.
Fixes #43311, #43406, #43035, #43049

* fix(cli): handle scheduled gateway restarts consistently

* test(cli): update daemon coverage restart contract

* fix: harden openai websocket replay

* fix(discord): enforce users/roles allowlist in reaction ingress

References GHSA-9vvh-2768-c8vp.

* test: fix websocket tool shape coverage

* fix: isolate plugin discovery env from global state

* fix(sandbox): anchor fs-bridge writeFile commit to canonical parent path

Refs: GHSA-xvx8-77m6-gwg6

* feat: expose runtime version in gateway status

* fix(acp): rehydrate restarted main ACP sessions (#43285)

Merged via squash.

Prepared head SHA: f06318e58fe3e3fedd70426ca7eeecf6d71bb604
Co-authored-by: frankekn <[email protected]>
Co-authored-by: frankekn <[email protected]>
Reviewed-by: @frankekn

* fix(context-engine): guard compact() throw + fire hooks for ownsCompaction engines (#41361)

Merged via squash.

Prepared head SHA: 0957b32dc63b16d710403565953b77bfbd2bd987
Co-authored-by: davidrudduck <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* docs: reorder unreleased changelog by user impact

* OpenRouter: surface free Hunter and Healer stealth models for the next week (#43642)

* Models: add temporary Hunter and Healer alpha to OpenRouter catalog

* Add temporary OpenRouter stealth catalog entries

---------

Co-authored-by: Tak Hoffman <[email protected]>

* docs: update 2026.3.11 release examples

* build: sync versions to 2026.3.11

* fix(telegram): avoid polling restart hang after stall detection

* fix: clear telegram polling cleanup timers

* build: bump openclaw to 2026.3.11-beta.1

* docs: update Raspberry Pi dashboard access instructions (#43584)

* docs(pi): update dashboard access instructions

* docs(i18n): refresh raspberry pi source hash

* docs: clarify Raspberry Pi dashboard access

* fix: clarify Raspberry Pi dashboard access (#43584) (thanks @neeravmakwana)

---------

Co-authored-by: Neerav Makwana <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>

* build: prepare 2026.3.11 release

* fix(browser): restore proxy attachment media size cap (#43684)

* browser: honor shared proxy file size cap

* test(browser): cover proxy file size cap

* docs(changelog): note browser proxy size cap fix

* Infra: block GIT_EXEC_PATH in host env sanitizer (#43685)

* Infra: block GIT_EXEC_PATH in host env sanitizer

* Changelog: note host env hardening

* Security: escape invisible exec approval format chars (#43687)

* Infra: escape invisible exec approval chars

* Gateway: sanitize exec approval display text

* Tests: cover sanitized exec approval payloads

* Tests: cover sanitized exec approval forwarding

* Changelog: note exec approval prompt hardening

* Infra: cap device tokens to approved scopes (#43686)

* Infra: cap device tokens to approved scopes

* Changelog: note device token hardening

* Update CHANGELOG.md

* Update CHANGELOG.md

* Tests: clean up temp git helper directory

* Infra: fail closed without device scope baseline

* style: format changelog

* fix(macos): add NSRemindersUsageDescription for apple-reminders skill

Fixes #5090

Without this plist key, macOS silently denies Reminders access when
running through OpenClaw.app, preventing the apple-reminders skill
from requesting permission.

(cherry picked from commit e5774471c851b773dd2bffd51dd5d28d95a8a7ca)

* Changelog: note Reminders permission fix

* fix(imessage): dedupe reflected self-chat duplicates (#38440)

* iMessage: drop reflected self-chat duplicates

* Changelog: add iMessage self-chat echo dedupe entry

* iMessage: keep self-chat dedupe scoped to final group identity

* iMessage: harden self-chat cache

* iMessage: sanitize self-chat duplicate logs

* iMessage: scope group self-chat dedupe by sender

* iMessage: move self-chat cache identity into cache

* iMessage: hash full self-chat text

* Update CHANGELOG.md

* fix(agents): enforce sandboxed session_status visibility (#43754)

* agents: guard sandboxed session_status access

* test(agents): cover sandboxed session_status scope

* docs(changelog): credit session_status hardening

* agents: preflight sandboxed session_status checks

* test(agents): cover session_status existence oracle

* agents: preserve legacy session_status tree keys

* test(agents): cover legacy session_status tree keys

* Update CHANGELOG.md

* fix: prevent duplicate assistant messages in TUI (fixes #35278) (#35364)

* fix: prevent duplicate assistant messages in TUI (fixes #35278)

When startAssistant() is called multiple times with the same runId,
it was creating duplicate AssistantMessageComponent instances instead
of reusing the existing one. This caused messages to appear twice in
the terminal UI.

The fix checks if a component already exists for the runId before
creating a new one. If it exists, we update its text instead of
appending a duplicate component.

Test coverage includes verification that:
- Only one component is created when startAssistant is called twice
- The second text replaces the first
- Component count remains 1 (prevents regression)

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <[email protected]>
Co-Authored-By: Happy <[email protected]>

* Changelog: add TUI duplicate-render fix entry

---------

Co-authored-by: 沐沐 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Happy <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* fix(cron): prevent duplicate proactive delivery on transient retry (#40646)

* fix(cron): prevent duplicate proactive delivery on transient retry

* refactor: scope skipQueue to retryTransient path only

Non-retrying direct delivery (structured content / thread) keeps the
write-ahead queue so recoverPendingDeliveries can replay after a crash.

Addresses review feedback from codex-connector.

* fix: preserve write-ahead queue on initial delivery attempt

The first call through retryTransientDirectCronDelivery now keeps the
write-ahead queue entry so recoverPendingDeliveries can replay after a
crash.  Only subsequent retry attempts set skipQueue to prevent
duplicate sends.

Addresses second codex-connector review on ea5ae5c.

* ci: retrigger checks

* Cron: bypass write-ahead queue for direct isolated delivery

* Tests: assert isolated cron skipQueue invariants

* Changelog: add cron duplicate-delivery fix entry

---------

Co-authored-by: Vincent Koc <[email protected]>

* fix(bluebubbles): dedupe reflected self-chat duplicates (#38442)

* BlueBubbles: drop reflected self-chat duplicates

* Changelog: add BlueBubbles self-chat echo dedupe entry

* BlueBubbles: gate self-chat cache and expand coverage

* BlueBubbles: require explicit sender ids for self-chat dedupe

* BlueBubbles: harden self-chat cache

* BlueBubbles: move self-chat cache identity into cache

* BlueBubbles: gate self-chat cache to confirmed outbound sends

* Update CHANGELOG.md

* BlueBubbles: bound self-chat cache input work

* Tests: cover BlueBubbles cache cap under cleanup throttle

* BlueBubbles: canonicalize self-chat DM scope

* Tests: cover BlueBubbles mixed self-chat scope aliases

* fix(mattermost): prevent duplicate messages when block streaming + threading are active (#41362)

* fix(mattermost): prevent duplicate messages when block streaming + threading are active

Remove replyToId from createBlockReplyPayloadKey so identical content is
deduplicated regardless of threading target. Add explicit threading dock
to the Mattermost plugin with resolveReplyToMode reading from config
(default "all"), and add replyToMode to the Mattermost config schema.

Fixes #41219

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(mattermost): address PR review — per-account replyToMode and test clarity

Read replyToMode from the merged per-account config via
resolveMattermostAccount so account-level overrides are honored in
multi-account setups. Add replyToMode to MattermostAccountConfig type.
Rename misleading test to clarify it exercises shouldDropFinalPayloads
short-circuit, not payload key dedup.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Replies: keep block-pipeline reply targets distinct

* Tests: cover block reply target-aware dedupe

* Update CHANGELOG.md

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* Models: enforce source-managed SecretRef markers in models.json (#43759)

Merged via squash.

Prepared head SHA: 4a065ef5d849273756ceb0dd241ca24ca9e621ca
Co-authored-by: joshavant <[email protected]>
Co-authored-by: joshavant <[email protected]>
Reviewed-by: @joshavant

* BlueBubbles: require confirmed outbound for self-chat cache

* Agents: recover malformed Anthropic-compatible tool call args (#42835)

* Agents: recover malformed anthropic tool call args

* Agents: add malformed tool call regression test

* Changelog: note Kimi tool call arg recovery

* Agents: repair toolcall end message snapshots

* Agents: narrow Kimi tool call arg repair

* Infra: tighten exec allowlist glob matching (#43798)

* Infra: tighten exec allowlist glob matching

* Changelog: note GHSA-f8r2 exec allowlist fix

* fix: scope telegram polling restart to telegram errors (#43799)

* fix: scope telegram polling restart to telegram errors

* fix: make telegram error tagging best-effort

* fix: scope telegram polling restart to telegram errors (#43799)

* feat(ui): add chat infrastructure modules (slice 1/3 of dashboard-v2) (#41497)

* feat(ui): add chat infrastructure modules (slice 1 of dashboard-v2)

New self-contained chat modules extracted from dashboard-v2-structure:

- chat/slash-commands.ts: slash command definitions and completions
- chat/slash-command-executor.ts: execute slash commands via gateway RPC
- chat/slash-command-executor.node.test.ts: test coverage
- chat/speech.ts: speech-to-text (STT) support
- chat/input-history.ts: per-session input history navigation
- chat/pinned-messages.ts: pinned message management
- chat/deleted-messages.ts: deleted message tracking
- chat/export.ts: shared exportChatMarkdown helper
- chat-export.ts: re-export shim for backwards compat

Gateway fix:
- Restore usage/cost stripping in chat.history sanitization
- Add test coverage for sanitization behavior

These modules are additive and tree-shaken — no existing code
imports them yet. They will be wired in subsequent slices.

* Update ui/src/ui/chat/export.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix(ui): address review feedback on chat infra slice

- export.ts: handle array content blocks (Claude API format) instead
  of silently exporting empty strings
- slash-command-executor.ts: restrict /kill all to current session's
  subagent subtree instead of all sessions globally
- slash-command-executor.ts: only count truly aborted runs (check
  aborted !== false) in /kill summary

* fix: scope /kill <id> to current session subtree and preserve usage.cost in chat.history

- Restrict /kill <id> matching to only subagents belonging to the current
  session's agent subtree (P1 review feedback)
- Preserve nested usage.cost in chat.history sanitization so cost badges
  remain available (P2 review feedback)

* fix(ui): tighten slash kill scoping

* fix(ui): support legacy slash kill scopes

* fix(ci): repair pr branch checks

* Gateway: harden chat abort and export

* UI: align slash commands with session tree scope

* UI: resolve session aliases for slash command lookups

* Update .gitignore

* Cron: use shared nested lane resolver

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <[email protected]>

* Agents: clear invalidated Kimi tool arg repair (#43824)

* Tests: extend exec allowlist glob coverage

* Gateway: keep spawned workspace overrides internal (#43801)

* Gateway: keep spawned workspace overrides internal

* Changelog: note GHSA-2rqg agent boundary fix

* Gateway: persist spawned workspace inheritance in sessions

* Agents: clean failed lineage spawn state

* Tests: cover lineage attachment cleanup

* Tests: cover lineage thread cleanup

* Gateway: block profile mutations via browser.request (#43800)

* Gateway: block profile mutations via browser.request

* Changelog: note GHSA-vmhq browser request fix

* Gateway: normalize browser.request profile guard paths

* feat(llm-task): add thinking override

Co-authored-by: Xaden Ryan <[email protected]>

* feat(ui): utilities, theming, and i18n updates (slice 2/3 of dashboard-v2) (#41500)

* feat(ui): add utilities, theming, and i18n updates (slice 2 of dashboard-v2)

UI utilities and theming improvements extracted from dashboard-v2-structure:

Icons & formatting:
- icons.ts: expanded icon set for new dashboard views
- format.ts: date/number formatting helpers
- tool-labels.ts: human-readable tool name mappings

Theming:
- theme.ts: enhanced theme resolution and system theme support
- theme-transition.ts: simplified transition logic
- storage.ts: theme parsing improvements for settings persistence

Navigation & types:
- navigation.ts: extended tab definitions for dashboard-v2
- app-view-state.ts: expanded view state management
- types.ts: new type definitions (HealthSummary, ModelCatalogEntry, etc.)

Components:
- components/dashboard-header.ts: reusable header component

i18n:
- Updated en, pt-BR, zh-CN, zh-TW locales with new dashboard strings

All changes are additive or backwards-compatible. Build passes.
Part of #36853.

* ui: fix theme and locale review regressions

* ui: fix review follow-ups for dashboard tabs

* ui: allowlist locale password placeholder false positives

* ui: fix theme mode and locale regressions

* Vincentkoc code/pr 41500 route fix (#43829)

* UI: keep unfinished settings routes hidden

* UI: normalize light theme data token

* UI: restore cron type compatibility

---------

Co-authored-by: Vincent Koc <[email protected]>

* Docs: clarify llm-task thinking presets

* Refactor: trim duplicate gateway/onboarding helpers and dead utils (#43871)

* Gateway: share input provenance schema

* Onboarding: dedupe top-level channel patching

* Utils: remove unused path helpers

* Protocol: refresh generated gateway models

* feat(zalouser): add markdown-to-Zalo text style parsing (#43324)

* feat(zalouser): add markdown-to-Zalo text style parsing

Parse markdown formatting (bold, italic, strikethrough, headings, lists,
code blocks, blockquotes, custom color/style tags) into Zalo native
TextStyle ranges so outbound messages render with rich formatting.

- Add text-styles.ts with parseZalouserTextStyles() converter
- Wire markdown mode into send pipeline (sendMessageZalouser)
- Export TextStyle enum and Style type from zca-client
- Add textMode/textStyles to ZaloSendOptions
- Pass textStyles through sendZaloTextMessage to zca-js API
- Enable textMode:"markdown" in outbound sendText/sendMedia and monitor
- Add comprehensive tests for parsing, send, and channel integration

* fix(zalouser): harden markdown text parsing

* fix(zalouser): mirror zca-js text style types

* fix(zalouser): support tilde fenced code blocks

* fix(zalouser): handle quoted fenced code blocks

* fix(zalouser): preserve literal quote lines in code fences

* fix(zalouser): support indented quoted fences

* fix(zalouser): preserve quoted markdown blocks

* fix(zalouser): rechunk formatted messages

* fix(zalouser): preserve markdown structure across chunks

* fix(zalouser): honor chunk limits and CRLF fences

* fix(failover): add missing network errno patterns to text-based timeout classifier (#42830)

Merged via squash.

Prepared head SHA: 91761487e8825c0fd6582a762d04bba04f726a85
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix: preserve sandbox write payload stdin (#43876)

Merged via squash.

Prepared head SHA: a10fd4b21c78ec57411e6a4f387f16b1441660c2
Co-authored-by: glitch418x <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix: stop main-session UI replies inheriting channel routes

* fix: stop main-session UI replies inheriting channel routes (#43918)

* fix: add zalouser outbound chunker

* fix(doctor): canonicalize gateway service entrypoint paths (#43882)

Merged via squash.

Prepared head SHA: 9f530d2a86b5d30822d4419db7cffae6a560ddca
Co-authored-by: ngutman <[email protected]>
Co-authored-by: ngutman <[email protected]>
Reviewed-by: @ngutman

* docs: add Kubernetes install guide, setup script, and manifests (#34492)

* add docs and manifests for k8s install

Signed-off-by: sallyom <[email protected]>

* changelog

Signed-off-by: sallyom <[email protected]>

---------

Signed-off-by: sallyom <[email protected]>

* feat(mattermost): add replyToMode support (off | first | all) (#29587)

Merged via squash.

Prepared head SHA: 4a67791f53b1109959082738429471b7a5bc93b8
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(telegram): allow fallback models in /model validation (#40105)

Merged via squash.

Prepared head SHA: de07585e03cba06897d50c1d79fbe09d326c6ac9
Co-authored-by: avirweb <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark

* fix: carry observed overflow token counts into compaction (#40357)

Merged via squash.

Prepared head SHA: b99eed4329bda45083cdedc2386c2c4041c034be
Co-authored-by: rabsef-bicrym <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(status): resolve context window by provider-qualified key, prefer max on bare-id collision, solve #35976 (#36389)

Merged via squash.

Prepared head SHA: f8cf752c59708fb388fd200276115277e8b217d6
Co-authored-by: haoruilee <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Agents: adapt pi-ai oauth and payload hooks

* build: default to Node 24 and keep Node 22 compat

* build: raise Node 22 compatibility floor to 22.16

* build: align Node 22 guidance with 22.16 minimum

* ci: harden pnpm sticky cache on PRs

* ci: restore PR pnpm cache fallback

* ci: tighten cache docs and node22 gate

* fix(mattermost): pass mediaLocalRoots through reply delivery (#44021)

Merged via squash.

Prepared head SHA: 856f11f129f7d6a4bc8f23e8d13c786ecb871f52
Co-authored-by: LyleLiu666 <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* Hardening: require LINE webhook signatures (#44090)

* LINE: require webhook signatures in express handler

* LINE: require webhook signatures in node handler

* LINE: update express signature tests

* LINE: update node signature tests

* Changelog: note LINE webhook hardening

* LINE: validate signatures before parsing webhook bodies

* LINE: reject missing signatures before body reads

* Security: preserve Feishu reaction chat type (#44088)

* Feishu: preserve looked-up chat type

* Feishu: fail closed on ambiguous reaction chats

* Feishu: cover reaction chat type fallback

* Changelog: note Feishu reaction hardening

* Feishu: fail closed without resolved chat type

* Feishu: normalize reaction chat type at runtime

* Hardening: tighten preauth WebSocket handshake limits (#44089)

* Gateway: tighten preauth handshake limits

* Changelog: note WebSocket preauth hardening

* Gateway: count preauth frame bytes accurately

* Gateway: cap WebSocket payloads before auth

* Hardening: normalize Unicode command obfuscation detection (#44091)

* Exec: cover unicode obfuscation cases

* Exec: normalize unicode obfuscation detection

* Changelog: note exec detection hardening

* Exec: strip unicode tag character obfuscation

* Exec: harden unicode suppression and length guards

* Exec: require path boundaries for safe URL suppressions

* Security: require Feishu webhook encrypt key (#44087)

* Feishu: require webhook encrypt key in schema

* Feishu: cover encrypt key webhook validation

* Feishu: enforce encrypt key at startup

* Feishu: add webhook forgery regression test

* Feishu: collect encrypt key during onboarding

* Docs: require Feishu webhook encrypt key

* Changelog: note Feishu webhook hardening

* Docs: clarify Feishu encrypt key screenshot

* Feishu: treat webhook encrypt key as secret input

* Feishu: resolve encrypt key only in webhook mode

* Subagents: stop retrying external completion timeouts (#41235) (#43847)

* Changelog: add subagent announce timeout note

* Tests: cover subagent completion timeout no-retry

* Subagents: stop retrying external completion timeouts

* Config: update subagent announce timeout default docs

* Tests: use fake timers for subagent timeout retry guard

* docs: sync Feishu secretref credential matrix

## Summary

- Problem: `src/secrets/target-registry.test.ts` fails on latest `main` because the runtime registry includes Feishu `encryptKey` paths that the docs matrix and surface reference omit.
- Why it matters: the docs/runtime sync guard currently blocks prep and merge work for unrelated PRs, including `#25558`.
- What changed: regenerated the secretref credential matrix and updated the surface reference to include both Feishu `encryptKey` paths.
- What did NOT change (scope boundary): no runtime registry behavior, config semantics, or channel handling changed.

## Change Type (select all)

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [x] Docs
- [ ] Security hardening
- [ ] Chore/infra

## Scope (select all touched areas)

- [ ] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [x] Integrations
- [ ] API / contracts
- [ ] UI / DX
- [ ] CI/CD / infra

## Linked Issue/PR

- Closes #
- Related #25558

## User-visible / Behavior Changes

None.

## Security Impact (required)

- New permissions/capabilities? `No`
- Secrets/tokens handling changed? `No`
- New/changed network calls? `No`
- Command/tool execution surface changed? `No`
- Data access scope changed? `No`
- If any `Yes`, explain risk + mitigation:

## Repro + Verification

### Environment

- OS: macOS
- Runtime/container: Node.js repo checkout
- Model/provider: N/A
- Integration/channel (if any): Feishu docs/runtime registry sync
- Relevant config (redacted): none

### Steps

1. Check out latest `main` before this change.
2. Run `./node_modules/.bin/vitest run --config vitest.unit.config.ts src/secrets/target-registry.test.ts`.
3. Apply this docs-only sync change and rerun the same command.

### Expected

- The target registry stays in sync with the generated docs matrix and the test passes.

### Actual

- Before this change, the test failed because `channels.feishu.encryptKey` and `channels.feishu.accounts.*.encryptKey` were missing from the docs artifacts.

## Evidence

Attach at least one:

- [x] Failing test/log before + passing after
- [ ] Trace/log snippets
- [ ] Screenshot/recording
- [ ] Perf numbers (if relevant)

## Human Verification (required)

What you personally verified (not just CI), and how:

- Verified scenarios: confirmed the failure on plain latest `main`, applied only these docs entries in a clean bootstrapped worktree, and reran `./node_modules/.bin/vitest run --config vitest.unit.config.ts src/secrets/target-registry.test.ts` to green.
- Edge cases checked: verified both top-level Feishu `encryptKey` and account-scoped `encryptKey` paths are present in the matrix and surface reference.
- What you did **not** verify: full repo test suite and CI beyond the targeted regression.

## Review Conversations

- [x] I replied to or resolved every bot review conversation I addressed in this PR.
- [x] I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

## Compatibility / Migration

- Backward compatible? `Yes`
- Config/env changes? `No`
- Migration needed? `No`
- If yes, exact upgrade steps:

## Failure Recovery (if this breaks)

- How to disable/revert this change quickly: revert this commit.
- Files/config to restore: `docs/reference/secretref-user-supplied-credentials-matrix.json` and `docs/reference/secretref-credential-surface.md`
- Known bad symptoms reviewers should watch for: the target-registry docs sync test failing again for missing Feishu `encryptKey` entries.

## Risks and Mitigations

- Risk: the markdown surface reference could drift from the generated matrix again in a later credential-shape change.
  - Mitigation: `src/secrets/target-registry.test.ts` continues to guard docs/runtime sync.

* Compaction Runner: emit transcript updates post-compact (#25558)

Merged via squash.

Prepared head SHA: 8a858436ed31805124a9d096bd93ab90e5423672
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Plugins: fix env-aware root resolution and caching (#44046)

Merged via squash.

Prepared head SHA: 6e8852a188b0eaa4d6cf0bb71829023e0e0ed82b
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* feat: add sessions_yield tool for cooperative turn-ending (#36537)

Merged via squash.

Prepared head SHA: 75d9204c863792226389a4d33eeb40c4e842528d
Co-authored-by: jriff <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Moonshot: respect explicit baseUrl for CN endpoint so platform.moonshot.cn keys authenticate (#33637) (#33696)

* Moonshot: respect explicit baseUrl for CN endpoint so platform.moonshot.cn keys authenticate (#33637)

* Moonshot: address review - remove dead constant, import canonical URLs (#33696)

* Plugins: require explicit trust for workspace-discovered plugins (#44174)

* Plugins: disable implicit workspace plugin auto-load

* Tests: cover workspace plugin trust gating

* Changelog: note workspace plugin trust hardening

* Plugins: keep workspace trust gate ahead of memory slot defaults

* Tests: cover workspace memory-slot trust bypass

* fix(providers): respect user-configured baseUrl for kimi-coding (#36647)

* fix(providers): respect user-configured baseUrl for kimi-coding

The kimi-coding provider was built exclusively from
`buildKimiCodingProvider()` defaults, ignoring any user-specified
`baseUrl` or other overrides in `openclaw.json` providers config.
This caused 404 errors when users configured a custom endpoint.

Now merge `explicitProviders["kimi-coding"]` on top of defaults,
matching the pattern used by ollama/vllm. User's `baseUrl`, `api`,
and `models` take precedence; env/profile API key still wins.

Fixes #36353

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Tests: use Kimi implicit provider harness

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* feat(push): add iOS APNs relay gateway (#43369)

* feat(push): add ios apns relay gateway

* fix(shared): avoid oslog string concatenation

# Conflicts:
#	apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayChannel.swift

* fix(push): harden relay validation and invalidation

* fix(push): persist app attest state before relay registration

* fix(push): harden relay invalidation and url handling

* feat(push): use scoped relay send grants

* feat(push): configure ios relay through gateway config

* feat(push): bind relay registration to gateway identity

* fix(push): tighten ios relay trust flow

* fix(push): bound APNs registration fields (#43369) (thanks @ngutman)

* fix(ios): add live activity horizontal padding

* Zalo: rate limit invalid webhook secret guesses before auth (#44173)

* Zalo: rate limit webhook guesses before auth

* Tests: cover pre-auth Zalo webhook rate limiting

* Changelog: note Zalo pre-auth rate limiting

* Zalo: preserve auth-before-content-type response ordering

* Tests: cover auth-before-content-type webhook ordering

* Zalo: split auth and unauth webhook rate-limit buckets

* Tests: cover auth bucket split for Zalo webhook rate limiting

* Zalo: use trusted proxy client IP for webhook rate limiting

* Tests: cover trusted proxy client IP rate limiting for Zalo

* docs: clarify gateway HTTP trust boundary

* Gateway: harden custom session-store discovery (#44176)

Merged via squash.

Prepared head SHA: 52ebbf5188b47386f2a78ac4715993bc082e911b
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(ci): harden docker builds and unblock config docs

* fix: make node-llama-cpp optional for npm installs

* fix: canonicalize openrouter native model keys

* runner: infer names from malformed toolCallId variants (#34485)

Merged via squash.

Prepared head SHA: 150ea1a7c90de3232f72498d851719c4dfb00b43
Co-authored-by: yuweuii <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Gateway: preserve discovered session store paths

* docs: reorder unreleased changelog

* fix(node-host): harden ambiguous approval operand binding (#44247)

* fix(node-host): harden approval operand binding

* test(node-host): cover approval parser hardening

* docs(changelog): note approval hardening GHSA cluster

* Update CHANGELOG.md

* fix(node-host): remove dead approval parser entries

* test(node-host): cover bunx approval wrapper

* fix(node-host): unwrap pnpm shim exec forms

* test(node-host): cover pnpm shim wrappers

* Kimi Coding: set default subscription user agent (#44248)

* Providers: set default Kimi coding user agent

* Tests: cover Kimi coding header overrides

* Changelog: note Kimi coding user agent

* Tests: satisfy Kimi provider fixture type

* Update CHANGELOG.md

* Providers: preserve Kimi headers through models merge

* feat(ui): dashboard-v2 views refactor (slice 3/3 of dashboard-v2) (#41503)

* feat(ui): add chat infrastructure modules (slice 1 of dashboard-v2)

New self-contained chat modules extracted from dashboard-v2-structure:

- chat/slash-commands.ts: slash command definitions and completions
- chat/slash-command-executor.ts: execute slash commands via gateway RPC
- chat/slash-command-executor.node.test.ts: test coverage
- chat/speech.ts: speech-to-text (STT) support
- chat/input-history.ts: per-session input history navigation
- chat/pinned-messages.ts: pinned message management
- chat/deleted-messages.ts: deleted message tracking
- chat/export.ts: shared exportChatMarkdown helper
- chat-export.ts: re-export shim for backwards compat

Gateway fix:
- Restore usage/cost stripping in chat.history sanitization
- Add test coverage for sanitization behavior

These modules are additive and tree-shaken — no existing code
imports them yet. They will be wired in subsequent slices.

* feat(ui): add utilities, theming, and i18n updates (slice 2 of dashboard-v2)

UI utilities and theming improvements extracted from dashboard-v2-structure:

Icons & formatting:
- icons.ts: expanded icon set for new dashboard views
- format.ts: date/number formatting helpers
- tool-labels.ts: human-readable tool name mappings

Theming:
- theme.ts: enhanced theme resolution and system theme support
- theme-transition.ts: simplified transition logic
- storage.ts: theme parsing improvements for settings persistence

Navigation & types:
- navigation.ts: extended tab definitions for dashboard-v2
- app-view-state.ts: expanded view state management
- types.ts: new type definitions (HealthSummary, ModelCatalogEntry, etc.)

Components:
- components/dashboard-header.ts: reusable header component

i18n:
- Updated en, pt-BR, zh-CN, zh-TW locales with new dashboard strings

All changes are additive or backwards-compatible. Build passes.
Part of #36853.

* feat(ui): dashboard-v2 views refactor (slice 3 of dashboard-v2)

Complete views refactor from dashboard-v2-structure, building on
slice 1 (chat infra, #41497) and slice 2 (utilities/theming, #41500).

Core app wiring:
- app.ts: updated host component with new state properties
- app-render.ts: refactored render pipeline for new dashboard layout
- app-render.helpers.ts: extracted render helpers
- app-settings.ts: theme listener lifecycle fix, cron runs on tab load
- app-gateway.ts: refactored chat event handling
- app-chat.ts: slash command integration

New views:
- views/command-palette.ts: command palette (Cmd+K)
- views/login-gate.ts: authentication gate
- views/bottom-tabs.ts: mobile tab navigation
- views/overview-*.ts: modular overview dashboard (cards, attention,
  event log, hints, log tail, quick actions)
- views/agents-panels-overview.ts: agent overview panel

Refactored views:
- views/chat.ts: major refactor with STT, slash commands, search,
  export, pinned messages, input history
- views/config.ts: restructured config management
- views/agents.ts: streamlined agent management
- views/overview.ts: modular composition from sub-views
- views/sessions.ts: enhanced session management

Controllers:
- controllers/health.ts: new health check controller
- controllers/models.ts: new model catalog controller
- controllers/agents.ts: tools catalog improvements
- controllers/config.ts: config form enhancements

Tests & infrastructure:
- Updated test helpers, browser tests, node tests
- vite.config.ts: build configuration updates
- markdown.ts: rendering improvements

Build passes ✅ | 44 files | +6,626/-1,499
Part of #36853. Depends on #41497 and #41500.

* UI: fix chat review follow-ups

* fix(ui): repair chat clear and attachment regressions

* fix(ui): address remaining chat review comments

* fix(ui): address review follow-ups

* fix(ui): replay queued local slash commands

* fix(ui): repair control-ui type drift

* fix(ui): restore control UI styling

* feat(ui): enhance layout and styling for config and topbar components

- Updated grid layout for the config layout to allow full-width usage.
- Introduced new styles for top tabs and search components to improve usability.
- Added theme mode toggle styling for better visual integration.
- Implemented tests for layout and theme mode components to ensure proper rendering and functionality.

* feat(ui): add config file opening functionality and enhance styles

- Implemented a new handler to open the configuration file using the default application based on the operating system.
- Updated various CSS styles across components for improved visual consistency and usability, including adjustments to padding, margins, and font sizes.
- Introduced new styles for the data table and sidebar components to enhance layout and interaction.
- Added tests for the collapsed navigation rail to ensure proper functionality in different states.

* refactor(ui): update CSS styles for improved layout and consistency

- Simplified font-body declaration in base.css for cleaner code.
- Adjusted transition properties in components.css for better readability.
- Added new .workspace-link class in components.css for enhanced link styling.
- Changed config layout from grid to flex in config.css for better responsiveness.
- Updated related tests to reflect layout changes in config-layout.browser.test.ts.

* feat(ui): enhance theme handling and loading states in chat interface

- Updated CSS to support new theme mode attributes for better styling consistency across light and dark themes.
- Introduced loading skeletons in the chat view to improve user experience during data fetching.
- Refactored command palette to manage focus more effectively, enhancing accessibility.
- Added tests for the appearance theme picker and loading states to ensure proper rendering and functionality.

* refactor(ui): streamline ephemeral state management in chat and config views

- Introduced interfaces for ephemeral state in chat and config views to encapsulate related variables.
- Refactored state management to utilize a single object for better organization and maintainability.
- Removed legacy state variables and updated related functions to reference the new state structure.
- Enhanced readability and consistency across the codebase by standardizing state handling.

* chore: remove test files to reduce PR scope

* fix(ui): resolve type errors in debug props and chat search

* refactor(ui): remove stream mode functionality across various components

- Eliminated stream mode related translations and CSS styles to streamline the user interface.
- Updated multiple components to remove references to stream mode, enhancing code clarity and maintainability.
- Adjusted rendering logic in views to ensure consistent behavior without stream mode.
- Improved overall readability by cleaning up unused variables and props.

* fix(ui): add msg-meta CSS and fix rebase type errors

* fix(ui): add CSS for chat footer action buttons (TTS, delete) and msg-meta

* feat(ui): add delete confirmation with remember-decision checkbox

* fix(ui): delete confirmation with remember, attention icon sizing

* fix(ui): open delete confirm popover to the left (not clipped)

* fix(ui): show all nav items in collapsed sidebar, remove gap

* fix(ui): address P1/P2 review feedback — session queue clear, kill scope, palette guard, stop button

* fix(ui): address Greptile re-review — kill scope, queue flush, idle handling, parallel fetch

- SECURITY: /kill <target> now enforces session tree scope (not just /kill all)
- /kill reports idle sessions gracefully instead of throwing
- Queue continues draining after local slash commands
- /model fetches sessions.list + models.list in parallel (perf fix)

* fix(ui): style update banner close button — SVG stroke + sizing

* fix(ui): update layout styles for sidebar and content spacing

* UI: restore colon slash command parsing

* UI: restore slash command session queries

* Refactor thinking resolution: Introduce resolveThinkingDefaultForModel function and update model-selection to utilize it. Add tests for new functionality in thinking.test.ts.

* fix(ui): constrain welcome state logo size, add missing CSS for new session view

---------

Co-authored-by: Vincent Koc <[email protected]>

* fix: restore protocol outputs and stabilize Windows path CI (#44266)

* fix(ci): restore protocol outputs and stabilize Windows path test

Regenerate the Swift protocol models so protocol:check stops failing on main.
Align the session target test helper with the sync production realpath behavior so Windows does not compare runneradmin and RUNNER~1 spellings for the same file.

Regeneration-Prompt: |
  Investigate the failing checks from merged PR #34485 and confirm whether they still affect current main before changing code. Keep the fix tight: do not alter runtime behavior beyond what is required to clear the reproduced CI regressions. Commit the generated Swift protocol outputs for the PushTestResult transport field because protocol:check was failing from stale generated files on main. Also fix the Windows-only session target test by making its helper use the same synchronous realpath behavior as production discovery, so path spelling differences like runneradmin versus RUNNER~1 do not cause a false assertion failure.

* fix(ci): align session target realpath behavior on Windows

Use native realpath for sync session target discovery so it matches the async path on Windows, and update the session target test helper to assert against the same canonical path form.

Regeneration-Prompt: |
  After opening the follow-up PR for the CI regressions from merged PR #34485, inspect the new failing Windows shard instead of assuming the first fix covered every case. Keep scope limited to the session target path mismatch exposed by CI. Fix the inconsistency at the source by making sync session target discovery use the same native realpath canonicalization as the async discovery path on Windows, then update the test helper to match that shared behavior and verify the touched file with targeted tests and file-scoped lint/format checks.

* test: make merge config fixtures satisfy provider type

After rebasing the PR onto current origin/main, the merge helper test fixtures no longer satisfied ProviderConfig because the anthropic provider examples were missing required provider and model fields. Add a shared fully-typed model fixture and explicit anthropic baseUrl values so the test keeps full type coverage under tsgo.

Regeneration-Prompt: |
  Rebase the PR branch for #44266 onto the current origin/main because the failing CI error only reproduced on the merge ref. Re-run the type-check path and inspect src/agents/models-config.merge.test.ts at the exact compiler lines instead of weakening types globally. Keep the fix test-only: make the anthropic ProviderConfig fixtures structurally valid by supplying the required baseUrl and full model definition fields, and keep the shared fixture typed so tsgo accepts it without unknown casts.

* fix: align Windows session store test expectations

* chore(changelog): update CHANGELOG.md to include new features in dashboard-v2, highlighting the refreshed gateway dashboard with modular views and enhanced chat tools (#41503)

* Ollama/Kimi: apply Moonshot payload compatibility (#44274)

* Runner: extend Moonshot payload compat to Ollama Kimi

* Changelog: note Ollama Kimi tool routing

* Tests: cover Ollama Kimi payload compat

* Runner: narrow Ollama Kimi payload compat

* onboard(minimax): flatten auth to 4 direct choices, unify CN/Global under single provider (#44284)

Replace the multi-step MiniMax onboarding wizard with 4 flat options:
- MiniMax Global — OAuth (minimax.io)
- MiniMax Global — API Key (minimax.io)
- MiniMax CN — OAuth (minimaxi.com)
- MiniMax CN — API Key (minimaxi.com)

Storage changes:
- Unify CN and Global under provider "minimax" (baseUrl distinguishes region)
- Profiles: minimax:global / minimax:cn (both regions can coexist)
- Model ref: minimax/MiniMax-M2.5 (no more minimax-cn/ prefix)
- Remove LM Studio local mode and Lightning/Highspeed choice

Backward compatibility:
- Keep minimax-cn in provider-env-vars for existing configs
- Accept minimax-cn as legacy tokenProvider in CI pipelines
- Error with migration hint for removed auth choices in non-interactive mode
- Warn when dual-profile overwrites shared provider baseUrl

Made-with: Cursor

* Gateway/ws: clear unbound scopes for shared-token auth (#44306)

* Gateway/ws: clear unbound shared-auth scopes

* Gateway/auth: cover shared-token scope stripping

* Changelog: add shared-token scope stripping entry

* Gateway/ws: preserve allowed control-ui scopes

* Gateway/auth: assert control-ui admin scopes survive allowed device-less auth

* Gateway/auth: cover shared-password scope stripping

* fix: format CSS files for oxfmt (#44313)

* Commands: require owner for /config and /debug (#44305)

* Commands: add non-owner gate helper

* Commands: enforce owner-only config and debug

* Commands/test: cover owner-only config and debug

* Changelog: add owner-only config debug entry

* Commands/test: split config owner gating section

* Commands: redact sender ids in verbose command logs

* Commands: preserve internal read-only config access

* Commands/test: keep operator.write config show coverage non-owner

* fix(runtime): duplicate messages, share singleton state across bundled chunks (#43683)

* Tests: add fresh module import helper

* Process: share command queue runtime state

* Agents: share embedded run runtime state

* Reply: share followup queue runtime state

* Reply: share followup drain callback state

* Reply: share queued message dedupe state

* Reply: share inbound dedupe state

* Tests: cover shared command queue runtime state

* Tests: cover shared embedded run runtime state

* Tests: cover shared followup queue runtime state

* Tests: cover shared inbound dedupe state

* Tests: cover shared Slack thread participation state

* Slack: share sent thread participation state

* Tests: document fresh import helper

* Telegram: share draft stream runtime state

* Tests: cover shared Telegram draft stream state

* Telegram: share sent message cache state

* Tests: cover shared Telegram sent message cache

* Telegram: share thread binding runtime state

* Tests: cover shared Telegram thread binding state

* Tests: avoid duplicate shared queue reset

* refactor(runtime): centralize global singleton access

* refactor(runtime): preserve undefined global singleton values

* test(runtime): cover undefined global singleton values

---------

Co-authored-by: Nimrod Gutman <[email protected]>

* fix(sandbox): restore spawned workspace handoff (#44307)

* feat(context-engine): plumb sessionKey into all ContextEngine methods (#44157)

Merged via squash.

Prepared head SHA: 0b341f6f4ce487055d8bc0c0d335c42577941592
Co-authored-by: jalehman <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* docs: codify American English spelling convention (#44159)

* fix(failover): classify z.ai network_error stop reason as retryable timeout (#43884)

Merged via squash.

Prepared head SHA: 9660f6cd5bcb8d073fc5575bbba2bf3792b29de3
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(failover): classify ZenMux quota-refresh 402 as rate_limit (#43917)

Merged via squash.

Prepared head SHA: 1d58a36a774d06b1493971e8f14f9abc806be6b0
Co-authored-by: bwjoke <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* Compaction Runner: wire post-compaction memory sync (#25561)

Merged via squash.

Prepared head SHA: 6d2bc02cc16429a19b041acd353c08dd2404335f
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(gateway): honor trusted proxy hook auth rate limits

* fix(security): audit unrestricted hook agent routing

* refactor(gateway): move request client ip resolution to net

* refactor(gateway): cache hook proxy config in runtime state

* refactor(security): reuse hook agent routing normalization

* refactor(test): share hook request handler fixtures

* fix(failover): classify HTTP 422 as format and OpenRouter credits as billing (#43823)

Merged via squash.

Prepared head SHA: 4f48e977fe06c5662753d3900fe94f1835cc2dce
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix: skip cache-ttl append after compaction to prevent double compaction (#28548)

Merged via squash.

Prepared head SHA: a4114a52bcff6ed4057cc54d3c629bd723f3d420
Co-authored-by: MoerAI <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: switch pairing setup codes to bootstrap tokens

* feat: modularize provider plugin architecture

* docs: explain plugin architecture

* fix(ci): restore generated protocol swift outputs (#44411)

Regenerate the Swift protocol models so PushTestResult keeps the transport field required by the current gateway schema, and update protocol:check to diff both generated Swift destinations because the generator writes both files.

Regeneration-Prompt: |
  Investigate the protocol CI failure on current origin/main rather than assuming the earlier fix still held. Confirm whether the generated Swift outputs drifted from the TypeScript gateway schema, identify whether the regression was reintroduced by a later commit, and keep the patch minimal: restore the generated Swift outputs from the existing schema and tighten the protocol check so it verifies every Swift file the generator writes.

* fix(security): harden nodes owner-only tool gating

* refactor: share openai-compatible local discovery

* refactor: remove legacy provider apply shims

* refactor: split non-interactive auth choice providers

* refactor: split simple api-key auth providers

* test: cover provider plugin boundaries

* refactor: unify gateway connect auth selection

* refactor: trim bootstrap token metadata

* refactor: extract websocket handshake auth helpers

* refactor: clarify pairing setup auth labels

* deps: bump openclaw to 2026.3.11

Raise internal OpenClaw constraints to 2026.3.11 and regenerate pnpm lockfile to remove the vulnerable 2026.3.8 resolution.

* fix: harden windows npm runtime path

* feat: add --no-test flag to prepare-gates

Allows skipping the full test suite during prepare phase.
Testing is deferred to the dedicated Test phase in the pipeline.

* fix(node-host): fail closed on ruby approval preload flags

* feat: add fast mode toggle for OpenAI models

* Revert "feat: add --no-test flag to prepare-gates"

This reverts commit ee6bdb3bab26f2796943c6cac03d8f62a5664937.

* feat: add Anthropic fast mode support

* fix: harden windows native updates

* feat: add windows update package spec override

* fix(hooks): dedupe repeated agent deliveries by idempotency key (#44438)

* Hooks: add hook idempotency key resolution

* Hooks: dedupe repeated agent deliveries by idempotency key

* Tests: cover hook idempotency dedupe

* Changelog: note hook idempotency dedupe

* Hooks: cap hook idempotency key length

* Gateway: hash hook replay cache keys

* Tests: cover hook replay key hardening

* fix(hooks): fail closed on unreadable loader paths (#44437)

* Hooks: fail closed on unreadable loader paths

* Changelog: note hooks loader hardening

* Tests: cover sanitized hook loader logs

* Hooks: use realpath containment for legacy loaders

* Hooks: sanitize unreadable workspace log path

* fix(models): keep codex spark codex-only

* test(live): add codex instructions to spark probe

* fix(security): strip Mongolian selectors in exec obfuscation detector

* Gateway: preserve trusted-proxy browser scopes

* build: update deps and fix vitest 4 regressions

* build: sync bundled plugin versions

* refactor: add non-interactive provider plugin setup

* refactor: validate provider plugin metadata

* fix(zalouser): require ids for group allowlist auth

* fix: avoid ineffective dynamic imports

* fix(mac): adopt canonical session key and add reset triggers (#10898)

Add shared native chat handling for /new, /reset, and /clear.

This also aligns main session key handling in the shared chat UI and includes follow-up test and CI fixes needed to keep the branch mergeable.

Co-authored-by: Nachx639 <[email protected]>
Co-authored-by: Luke <[email protected]>

* test: resolve rebase conflicts in gateway coverage

* chore: prepare 2026.3.12 release

* refactor(zalouser): reuse shared name matching helper

* feat(zalouser): audit mutable group allowlists

* fix(routing): require ids for slack and msteams allowlists

* fix: quiet Telegram command overflow retry logs

* fix(memory): fail closed for Windows qmd wrappers

* docs(ollama): update onboarding flow

Co-Authored-By: Jeffrey Morgan <[email protected]>
(cherry picked from commit e8ca2ff4e522f2d971801a537b3c4fdfecde0711)

* fix: align Ollama onboarding docs before landing (#43473) (thanks @BruceMacD)

(cherry picked from commit 19fa274343a102ca85c7679ec28c5a3503a99f55)

* docs: reorder latest release changelog

* test: stabilize hooks loader log assertion on Windows
…
0x666c6f added a commit to 0x666c6f/openclaw that referenced this pull request Mar 26, 2026
…claw#57)

* fix(gateway): run before_tool_call for HTTP tools

* test(gateway): widen before tool hook mock typing (#43476)

* test(gateway): widen before tool hook mock typing

* chore: update pnpm.lock

* Gateway/Dashboard: surface config validation issues (#42664)

Merged via squash.

Prepared head SHA: 43f66cdcf04a14d5381a5a2f14e291a52a8b7389
Co-authored-by: huntharo <[email protected]>
Co-authored-by: huntharo <[email protected]>
Reviewed-by: @huntharo

* Memory: add multimodal image and audio indexing (#43460)

Merged via squash.

Prepared head SHA: a994c07190a2062322f459c928b6cd74f9803d88
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(hooks): add missing trigger and channelId to agent_end, llm_input, and llm_output hook contexts (#42362)

Merged via squash.

Prepared head SHA: e6d7b7e31aa6ae12813b4609adb6e569a4084d08
Co-authored-by: zhoulf1006 <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13

* Memory: revalidate multimodal files before indexing

* preserve openai phase param

* chore: bump version to 2026.3.10

* fix(terminal): sanitize skills JSON and fallback on legacy Windows (#43520)

* Terminal: use ASCII borders on legacy Windows consoles

* Skills: sanitize JSON output for control bytes

* Changelog: credit terminal follow-up fixes

* Update CHANGELOG.md

* Update CHANGELOG.md

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Skills: strip remaining escape sequences from JSON output

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix: repair bundled plugin dirs after npm install

* fix(daemon): replace bootout with kickstart -k for launchd restarts on macOS

On macOS, launchctl bootout permanently unloads the LaunchAgent plist.
Even with KeepAlive: true, launchd cannot respawn a service whose plist
has been removed from its registry. This left users with a dead gateway
requiring manual 'openclaw gateway install' to recover.

Affected trigger paths:
- openclaw gateway restart from an agent session (#43311)
- SIGTERM on config reload (#43406)
- Gateway self-restart via SIGTERM (#43035)
- Hot reload on channel config change (#43049)

Switch restartLaunchAgent() to launchctl kickstart -k, which force-kills
and restarts the service without unloading the plist. When the restart
originates from inside the launchd-managed process tree, delegate to a
new detached handoff helper (launchd-restart-handoff.ts) to avoid the
caller being killed mid-command. Self-restart paths in process-respawn.ts
now schedule the detached start-after-exit handoff before exiting instead
of relying on exit/KeepAlive timing.

Fixes #43311, #43406, #43035, #43049

* fix(gateway): enforce browser origin check regardless of proxy headers

In trusted-proxy mode, enforceOriginCheckForAnyClient was set to false
whenever proxy headers were present. This allowed browser-originated
WebSocket connections from untrusted origins to bypass origin validation
entirely, as the check only ran for control-ui and webchat client types.

An attacker serving a page from an untrusted origin could connect through
a trusted reverse proxy, inherit proxy-injected identity, and obtain
operator.admin access via the sharedAuthOk / roleCanSkipDeviceIdentity
path without any origin restriction.

Remove the hasProxyHeaders exemption so origin validation runs for all
browser-originated connections regardless of how the request arrived.

Fixes GHSA-5wcw-8jjv-m286

* fix: harden state dir permissions during onboard

* fix(whatsapp): trim leading whitespace in direct outbound sends (#43539)

Trim leading whitespace from direct WhatsApp text and media caption sends.

Also guard empty text-only web sends after trimming.

* fix(node-host): extend script-runner set and add fail-closed guard for mutable-file approval

tsx, jiti, ts-node, ts-node-esm, vite-node, and esno were not recognized
as interpreter-style script runners in invoke-system-run-plan.ts. These
runners produced mutableFileOperand: null, causing invoke-system-run.ts
to skip revalidation entirely. A mutated script payload would execute
without the approval binding check that node ./run.js already enforced.

Two-part fix:
- Add tsx, jiti, and related TypeScript/ESM loaders to the known script
  runner set so they produce a valid mutableFileOperand from the planner
- Add a fail-closed runtime guard in invoke-system-run.ts that denies
  execution when a script run should have a mutable-file binding but the
  approval plan is missing it, preventing unknown future runners from
  silently bypassing revalidation

Fixes GHSA-qc36-x95h-7j53

* fix(daemon): address clanker review findings for kickstart restart

Bug 1 (high): replace fixed sleep 1 with caller-PID polling in both
kickstart and start-after-exit handoff modes. The helper now waits until
kill -0 $caller_pid fails before issuing launchctl kickstart -k.

Bug 2 (medium): gate enable+bootstrap fallback on isLaunchctlNotLoaded().
Only attempt re-registration when kickstart -k fails because the job is
absent; all other kickstart failures now re-throw the original error.

Follows up on 3c0fd3dffe.
Fixes #43311, #43406, #43035, #43049

* fix(cli): handle scheduled gateway restarts consistently

* test(cli): update daemon coverage restart contract

* fix: harden openai websocket replay

* fix(discord): enforce users/roles allowlist in reaction ingress

References GHSA-9vvh-2768-c8vp.

* test: fix websocket tool shape coverage

* fix: isolate plugin discovery env from global state

* fix(sandbox): anchor fs-bridge writeFile commit to canonical parent path

Refs: GHSA-xvx8-77m6-gwg6

* feat: expose runtime version in gateway status

* fix(acp): rehydrate restarted main ACP sessions (#43285)

Merged via squash.

Prepared head SHA: f06318e58fe3e3fedd70426ca7eeecf6d71bb604
Co-authored-by: frankekn <[email protected]>
Co-authored-by: frankekn <[email protected]>
Reviewed-by: @frankekn

* fix(context-engine): guard compact() throw + fire hooks for ownsCompaction engines (#41361)

Merged via squash.

Prepared head SHA: 0957b32dc63b16d710403565953b77bfbd2bd987
Co-authored-by: davidrudduck <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* docs: reorder unreleased changelog by user impact

* OpenRouter: surface free Hunter and Healer stealth models for the next week (#43642)

* Models: add temporary Hunter and Healer alpha to OpenRouter catalog

* Add temporary OpenRouter stealth catalog entries

---------

Co-authored-by: Tak Hoffman <[email protected]>

* docs: update 2026.3.11 release examples

* build: sync versions to 2026.3.11

* fix(telegram): avoid polling restart hang after stall detection

* fix: clear telegram polling cleanup timers

* build: bump openclaw to 2026.3.11-beta.1

* docs: update Raspberry Pi dashboard access instructions (#43584)

* docs(pi): update dashboard access instructions

* docs(i18n): refresh raspberry pi source hash

* docs: clarify Raspberry Pi dashboard access

* fix: clarify Raspberry Pi dashboard access (#43584) (thanks @neeravmakwana)

---------

Co-authored-by: Neerav Makwana <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>

* build: prepare 2026.3.11 release

* fix(browser): restore proxy attachment media size cap (#43684)

* browser: honor shared proxy file size cap

* test(browser): cover proxy file size cap

* docs(changelog): note browser proxy size cap fix

* Infra: block GIT_EXEC_PATH in host env sanitizer (#43685)

* Infra: block GIT_EXEC_PATH in host env sanitizer

* Changelog: note host env hardening

* Security: escape invisible exec approval format chars (#43687)

* Infra: escape invisible exec approval chars

* Gateway: sanitize exec approval display text

* Tests: cover sanitized exec approval payloads

* Tests: cover sanitized exec approval forwarding

* Changelog: note exec approval prompt hardening

* Infra: cap device tokens to approved scopes (#43686)

* Infra: cap device tokens to approved scopes

* Changelog: note device token hardening

* Update CHANGELOG.md

* Update CHANGELOG.md

* Tests: clean up temp git helper directory

* Infra: fail closed without device scope baseline

* style: format changelog

* fix(macos): add NSRemindersUsageDescription for apple-reminders skill

Fixes #5090

Without this plist key, macOS silently denies Reminders access when
running through OpenClaw.app, preventing the apple-reminders skill
from requesting permission.

(cherry picked from commit e5774471c851b773dd2bffd51dd5d28d95a8a7ca)

* Changelog: note Reminders permission fix

* fix(imessage): dedupe reflected self-chat duplicates (#38440)

* iMessage: drop reflected self-chat duplicates

* Changelog: add iMessage self-chat echo dedupe entry

* iMessage: keep self-chat dedupe scoped to final group identity

* iMessage: harden self-chat cache

* iMessage: sanitize self-chat duplicate logs

* iMessage: scope group self-chat dedupe by sender

* iMessage: move self-chat cache identity into cache

* iMessage: hash full self-chat text

* Update CHANGELOG.md

* fix(agents): enforce sandboxed session_status visibility (#43754)

* agents: guard sandboxed session_status access

* test(agents): cover sandboxed session_status scope

* docs(changelog): credit session_status hardening

* agents: preflight sandboxed session_status checks

* test(agents): cover session_status existence oracle

* agents: preserve legacy session_status tree keys

* test(agents): cover legacy session_status tree keys

* Update CHANGELOG.md

* fix: prevent duplicate assistant messages in TUI (fixes #35278) (#35364)

* fix: prevent duplicate assistant messages in TUI (fixes #35278)

When startAssistant() is called multiple times with the same runId,
it was creating duplicate AssistantMessageComponent instances instead
of reusing the existing one. This caused messages to appear twice in
the terminal UI.

The fix checks if a component already exists for the runId before
creating a new one. If it exists, we update its text instead of
appending a duplicate component.

Test coverage includes verification that:
- Only one component is created when startAssistant is called twice
- The second text replaces the first
- Component count remains 1 (prevents regression)

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <[email protected]>
Co-Authored-By: Happy <[email protected]>

* Changelog: add TUI duplicate-render fix entry

---------

Co-authored-by: 沐沐 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Happy <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* fix(cron): prevent duplicate proactive delivery on transient retry (#40646)

* fix(cron): prevent duplicate proactive delivery on transient retry

* refactor: scope skipQueue to retryTransient path only

Non-retrying direct delivery (structured content / thread) keeps the
write-ahead queue so recoverPendingDeliveries can replay after a crash.

Addresses review feedback from codex-connector.

* fix: preserve write-ahead queue on initial delivery attempt

The first call through retryTransientDirectCronDelivery now keeps the
write-ahead queue entry so recoverPendingDeliveries can replay after a
crash.  Only subsequent retry attempts set skipQueue to prevent
duplicate sends.

Addresses second codex-connector review on ea5ae5c.

* ci: retrigger checks

* Cron: bypass write-ahead queue for direct isolated delivery

* Tests: assert isolated cron skipQueue invariants

* Changelog: add cron duplicate-delivery fix entry

---------

Co-authored-by: Vincent Koc <[email protected]>

* fix(bluebubbles): dedupe reflected self-chat duplicates (#38442)

* BlueBubbles: drop reflected self-chat duplicates

* Changelog: add BlueBubbles self-chat echo dedupe entry

* BlueBubbles: gate self-chat cache and expand coverage

* BlueBubbles: require explicit sender ids for self-chat dedupe

* BlueBubbles: harden self-chat cache

* BlueBubbles: move self-chat cache identity into cache

* BlueBubbles: gate self-chat cache to confirmed outbound sends

* Update CHANGELOG.md

* BlueBubbles: bound self-chat cache input work

* Tests: cover BlueBubbles cache cap under cleanup throttle

* BlueBubbles: canonicalize self-chat DM scope

* Tests: cover BlueBubbles mixed self-chat scope aliases

* fix(mattermost): prevent duplicate messages when block streaming + threading are active (#41362)

* fix(mattermost): prevent duplicate messages when block streaming + threading are active

Remove replyToId from createBlockReplyPayloadKey so identical content is
deduplicated regardless of threading target. Add explicit threading dock
to the Mattermost plugin with resolveReplyToMode reading from config
(default "all"), and add replyToMode to the Mattermost config schema.

Fixes #41219

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(mattermost): address PR review — per-account replyToMode and test clarity

Read replyToMode from the merged per-account config via
resolveMattermostAccount so account-level overrides are honored in
multi-account setups. Add replyToMode to MattermostAccountConfig type.
Rename misleading test to clarify it exercises shouldDropFinalPayloads
short-circuit, not payload key dedup.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Replies: keep block-pipeline reply targets distinct

* Tests: cover block reply target-aware dedupe

* Update CHANGELOG.md

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* Models: enforce source-managed SecretRef markers in models.json (#43759)

Merged via squash.

Prepared head SHA: 4a065ef5d849273756ceb0dd241ca24ca9e621ca
Co-authored-by: joshavant <[email protected]>
Co-authored-by: joshavant <[email protected]>
Reviewed-by: @joshavant

* BlueBubbles: require confirmed outbound for self-chat cache

* Agents: recover malformed Anthropic-compatible tool call args (#42835)

* Agents: recover malformed anthropic tool call args

* Agents: add malformed tool call regression test

* Changelog: note Kimi tool call arg recovery

* Agents: repair toolcall end message snapshots

* Agents: narrow Kimi tool call arg repair

* Infra: tighten exec allowlist glob matching (#43798)

* Infra: tighten exec allowlist glob matching

* Changelog: note GHSA-f8r2 exec allowlist fix

* fix: scope telegram polling restart to telegram errors (#43799)

* fix: scope telegram polling restart to telegram errors

* fix: make telegram error tagging best-effort

* fix: scope telegram polling restart to telegram errors (#43799)

* feat(ui): add chat infrastructure modules (slice 1/3 of dashboard-v2) (#41497)

* feat(ui): add chat infrastructure modules (slice 1 of dashboard-v2)

New self-contained chat modules extracted from dashboard-v2-structure:

- chat/slash-commands.ts: slash command definitions and completions
- chat/slash-command-executor.ts: execute slash commands via gateway RPC
- chat/slash-command-executor.node.test.ts: test coverage
- chat/speech.ts: speech-to-text (STT) support
- chat/input-history.ts: per-session input history navigation
- chat/pinned-messages.ts: pinned message management
- chat/deleted-messages.ts: deleted message tracking
- chat/export.ts: shared exportChatMarkdown helper
- chat-export.ts: re-export shim for backwards compat

Gateway fix:
- Restore usage/cost stripping in chat.history sanitization
- Add test coverage for sanitization behavior

These modules are additive and tree-shaken — no existing code
imports them yet. They will be wired in subsequent slices.

* Update ui/src/ui/chat/export.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix(ui): address review feedback on chat infra slice

- export.ts: handle array content blocks (Claude API format) instead
  of silently exporting empty strings
- slash-command-executor.ts: restrict /kill all to current session's
  subagent subtree instead of all sessions globally
- slash-command-executor.ts: only count truly aborted runs (check
  aborted !== false) in /kill summary

* fix: scope /kill <id> to current session subtree and preserve usage.cost in chat.history

- Restrict /kill <id> matching to only subagents belonging to the current
  session's agent subtree (P1 review feedback)
- Preserve nested usage.cost in chat.history sanitization so cost badges
  remain available (P2 review feedback)

* fix(ui): tighten slash kill scoping

* fix(ui): support legacy slash kill scopes

* fix(ci): repair pr branch checks

* Gateway: harden chat abort and export

* UI: align slash commands with session tree scope

* UI: resolve session aliases for slash command lookups

* Update .gitignore

* Cron: use shared nested lane resolver

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <[email protected]>

* Agents: clear invalidated Kimi tool arg repair (#43824)

* Tests: extend exec allowlist glob coverage

* Gateway: keep spawned workspace overrides internal (#43801)

* Gateway: keep spawned workspace overrides internal

* Changelog: note GHSA-2rqg agent boundary fix

* Gateway: persist spawned workspace inheritance in sessions

* Agents: clean failed lineage spawn state

* Tests: cover lineage attachment cleanup

* Tests: cover lineage thread cleanup

* Gateway: block profile mutations via browser.request (#43800)

* Gateway: block profile mutations via browser.request

* Changelog: note GHSA-vmhq browser request fix

* Gateway: normalize browser.request profile guard paths

* feat(llm-task): add thinking override

Co-authored-by: Xaden Ryan <[email protected]>

* feat(ui): utilities, theming, and i18n updates (slice 2/3 of dashboard-v2) (#41500)

* feat(ui): add utilities, theming, and i18n updates (slice 2 of dashboard-v2)

UI utilities and theming improvements extracted from dashboard-v2-structure:

Icons & formatting:
- icons.ts: expanded icon set for new dashboard views
- format.ts: date/number formatting helpers
- tool-labels.ts: human-readable tool name mappings

Theming:
- theme.ts: enhanced theme resolution and system theme support
- theme-transition.ts: simplified transition logic
- storage.ts: theme parsing improvements for settings persistence

Navigation & types:
- navigation.ts: extended tab definitions for dashboard-v2
- app-view-state.ts: expanded view state management
- types.ts: new type definitions (HealthSummary, ModelCatalogEntry, etc.)

Components:
- components/dashboard-header.ts: reusable header component

i18n:
- Updated en, pt-BR, zh-CN, zh-TW locales with new dashboard strings

All changes are additive or backwards-compatible. Build passes.
Part of #36853.

* ui: fix theme and locale review regressions

* ui: fix review follow-ups for dashboard tabs

* ui: allowlist locale password placeholder false positives

* ui: fix theme mode and locale regressions

* Vincentkoc code/pr 41500 route fix (#43829)

* UI: keep unfinished settings routes hidden

* UI: normalize light theme data token

* UI: restore cron type compatibility

---------

Co-authored-by: Vincent Koc <[email protected]>

* Docs: clarify llm-task thinking presets

* Refactor: trim duplicate gateway/onboarding helpers and dead utils (#43871)

* Gateway: share input provenance schema

* Onboarding: dedupe top-level channel patching

* Utils: remove unused path helpers

* Protocol: refresh generated gateway models

* feat(zalouser): add markdown-to-Zalo text style parsing (#43324)

* feat(zalouser): add markdown-to-Zalo text style parsing

Parse markdown formatting (bold, italic, strikethrough, headings, lists,
code blocks, blockquotes, custom color/style tags) into Zalo native
TextStyle ranges so outbound messages render with rich formatting.

- Add text-styles.ts with parseZalouserTextStyles() converter
- Wire markdown mode into send pipeline (sendMessageZalouser)
- Export TextStyle enum and Style type from zca-client
- Add textMode/textStyles to ZaloSendOptions
- Pass textStyles through sendZaloTextMessage to zca-js API
- Enable textMode:"markdown" in outbound sendText/sendMedia and monitor
- Add comprehensive tests for parsing, send, and channel integration

* fix(zalouser): harden markdown text parsing

* fix(zalouser): mirror zca-js text style types

* fix(zalouser): support tilde fenced code blocks

* fix(zalouser): handle quoted fenced code blocks

* fix(zalouser): preserve literal quote lines in code fences

* fix(zalouser): support indented quoted fences

* fix(zalouser): preserve quoted markdown blocks

* fix(zalouser): rechunk formatted messages

* fix(zalouser): preserve markdown structure across chunks

* fix(zalouser): honor chunk limits and CRLF fences

* fix(failover): add missing network errno patterns to text-based timeout classifier (#42830)

Merged via squash.

Prepared head SHA: 91761487e8825c0fd6582a762d04bba04f726a85
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix: preserve sandbox write payload stdin (#43876)

Merged via squash.

Prepared head SHA: a10fd4b21c78ec57411e6a4f387f16b1441660c2
Co-authored-by: glitch418x <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix: stop main-session UI replies inheriting channel routes

* fix: stop main-session UI replies inheriting channel routes (#43918)

* fix: add zalouser outbound chunker

* fix(doctor): canonicalize gateway service entrypoint paths (#43882)

Merged via squash.

Prepared head SHA: 9f530d2a86b5d30822d4419db7cffae6a560ddca
Co-authored-by: ngutman <[email protected]>
Co-authored-by: ngutman <[email protected]>
Reviewed-by: @ngutman

* docs: add Kubernetes install guide, setup script, and manifests (#34492)

* add docs and manifests for k8s install

Signed-off-by: sallyom <[email protected]>

* changelog

Signed-off-by: sallyom <[email protected]>

---------

Signed-off-by: sallyom <[email protected]>

* feat(mattermost): add replyToMode support (off | first | all) (#29587)

Merged via squash.

Prepared head SHA: 4a67791f53b1109959082738429471b7a5bc93b8
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(telegram): allow fallback models in /model validation (#40105)

Merged via squash.

Prepared head SHA: de07585e03cba06897d50c1d79fbe09d326c6ac9
Co-authored-by: avirweb <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark

* fix: carry observed overflow token counts into compaction (#40357)

Merged via squash.

Prepared head SHA: b99eed4329bda45083cdedc2386c2c4041c034be
Co-authored-by: rabsef-bicrym <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(status): resolve context window by provider-qualified key, prefer max on bare-id collision, solve #35976 (#36389)

Merged via squash.

Prepared head SHA: f8cf752c59708fb388fd200276115277e8b217d6
Co-authored-by: haoruilee <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Agents: adapt pi-ai oauth and payload hooks

* build: default to Node 24 and keep Node 22 compat

* build: raise Node 22 compatibility floor to 22.16

* build: align Node 22 guidance with 22.16 minimum

* ci: harden pnpm sticky cache on PRs

* ci: restore PR pnpm cache fallback

* ci: tighten cache docs and node22 gate

* fix(mattermost): pass mediaLocalRoots through reply delivery (#44021)

Merged via squash.

Prepared head SHA: 856f11f129f7d6a4bc8f23e8d13c786ecb871f52
Co-authored-by: LyleLiu666 <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* Hardening: require LINE webhook signatures (#44090)

* LINE: require webhook signatures in express handler

* LINE: require webhook signatures in node handler

* LINE: update express signature tests

* LINE: update node signature tests

* Changelog: note LINE webhook hardening

* LINE: validate signatures before parsing webhook bodies

* LINE: reject missing signatures before body reads

* Security: preserve Feishu reaction chat type (#44088)

* Feishu: preserve looked-up chat type

* Feishu: fail closed on ambiguous reaction chats

* Feishu: cover reaction chat type fallback

* Changelog: note Feishu reaction hardening

* Feishu: fail closed without resolved chat type

* Feishu: normalize reaction chat type at runtime

* Hardening: tighten preauth WebSocket handshake limits (#44089)

* Gateway: tighten preauth handshake limits

* Changelog: note WebSocket preauth hardening

* Gateway: count preauth frame bytes accurately

* Gateway: cap WebSocket payloads before auth

* Hardening: normalize Unicode command obfuscation detection (#44091)

* Exec: cover unicode obfuscation cases

* Exec: normalize unicode obfuscation detection

* Changelog: note exec detection hardening

* Exec: strip unicode tag character obfuscation

* Exec: harden unicode suppression and length guards

* Exec: require path boundaries for safe URL suppressions

* Security: require Feishu webhook encrypt key (#44087)

* Feishu: require webhook encrypt key in schema

* Feishu: cover encrypt key webhook validation

* Feishu: enforce encrypt key at startup

* Feishu: add webhook forgery regression test

* Feishu: collect encrypt key during onboarding

* Docs: require Feishu webhook encrypt key

* Changelog: note Feishu webhook hardening

* Docs: clarify Feishu encrypt key screenshot

* Feishu: treat webhook encrypt key as secret input

* Feishu: resolve encrypt key only in webhook mode

* Subagents: stop retrying external completion timeouts (#41235) (#43847)

* Changelog: add subagent announce timeout note

* Tests: cover subagent completion timeout no-retry

* Subagents: stop retrying external completion timeouts

* Config: update subagent announce timeout default docs

* Tests: use fake timers for subagent timeout retry guard

* docs: sync Feishu secretref credential matrix

## Summary

- Problem: `src/secrets/target-registry.test.ts` fails on latest `main` because the runtime registry includes Feishu `encryptKey` paths that the docs matrix and surface reference omit.
- Why it matters: the docs/runtime sync guard currently blocks prep and merge work for unrelated PRs, including `#25558`.
- What changed: regenerated the secretref credential matrix and updated the surface reference to include both Feishu `encryptKey` paths.
- What did NOT change (scope boundary): no runtime registry behavior, config semantics, or channel handling changed.

## Change Type (select all)

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [x] Docs
- [ ] Security hardening
- [ ] Chore/infra

## Scope (select all touched areas)

- [ ] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [x] Integrations
- [ ] API / contracts
- [ ] UI / DX
- [ ] CI/CD / infra

## Linked Issue/PR

- Closes #
- Related #25558

## User-visible / Behavior Changes

None.

## Security Impact (required)

- New permissions/capabilities? `No`
- Secrets/tokens handling changed? `No`
- New/changed network calls? `No`
- Command/tool execution surface changed? `No`
- Data access scope changed? `No`
- If any `Yes`, explain risk + mitigation:

## Repro + Verification

### Environment

- OS: macOS
- Runtime/container: Node.js repo checkout
- Model/provider: N/A
- Integration/channel (if any): Feishu docs/runtime registry sync
- Relevant config (redacted): none

### Steps

1. Check out latest `main` before this change.
2. Run `./node_modules/.bin/vitest run --config vitest.unit.config.ts src/secrets/target-registry.test.ts`.
3. Apply this docs-only sync change and rerun the same command.

### Expected

- The target registry stays in sync with the generated docs matrix and the test passes.

### Actual

- Before this change, the test failed because `channels.feishu.encryptKey` and `channels.feishu.accounts.*.encryptKey` were missing from the docs artifacts.

## Evidence

Attach at least one:

- [x] Failing test/log before + passing after
- [ ] Trace/log snippets
- [ ] Screenshot/recording
- [ ] Perf numbers (if relevant)

## Human Verification (required)

What you personally verified (not just CI), and how:

- Verified scenarios: confirmed the failure on plain latest `main`, applied only these docs entries in a clean bootstrapped worktree, and reran `./node_modules/.bin/vitest run --config vitest.unit.config.ts src/secrets/target-registry.test.ts` to green.
- Edge cases checked: verified both top-level Feishu `encryptKey` and account-scoped `encryptKey` paths are present in the matrix and surface reference.
- What you did **not** verify: full repo test suite and CI beyond the targeted regression.

## Review Conversations

- [x] I replied to or resolved every bot review conversation I addressed in this PR.
- [x] I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

## Compatibility / Migration

- Backward compatible? `Yes`
- Config/env changes? `No`
- Migration needed? `No`
- If yes, exact upgrade steps:

## Failure Recovery (if this breaks)

- How to disable/revert this change quickly: revert this commit.
- Files/config to restore: `docs/reference/secretref-user-supplied-credentials-matrix.json` and `docs/reference/secretref-credential-surface.md`
- Known bad symptoms reviewers should watch for: the target-registry docs sync test failing again for missing Feishu `encryptKey` entries.

## Risks and Mitigations

- Risk: the markdown surface reference could drift from the generated matrix again in a later credential-shape change.
  - Mitigation: `src/secrets/target-registry.test.ts` continues to guard docs/runtime sync.

* Compaction Runner: emit transcript updates post-compact (#25558)

Merged via squash.

Prepared head SHA: 8a858436ed31805124a9d096bd93ab90e5423672
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Plugins: fix env-aware root resolution and caching (#44046)

Merged via squash.

Prepared head SHA: 6e8852a188b0eaa4d6cf0bb71829023e0e0ed82b
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* feat: add sessions_yield tool for cooperative turn-ending (#36537)

Merged via squash.

Prepared head SHA: 75d9204c863792226389a4d33eeb40c4e842528d
Co-authored-by: jriff <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Moonshot: respect explicit baseUrl for CN endpoint so platform.moonshot.cn keys authenticate (#33637) (#33696)

* Moonshot: respect explicit baseUrl for CN endpoint so platform.moonshot.cn keys authenticate (#33637)

* Moonshot: address review - remove dead constant, import canonical URLs (#33696)

* Plugins: require explicit trust for workspace-discovered plugins (#44174)

* Plugins: disable implicit workspace plugin auto-load

* Tests: cover workspace plugin trust gating

* Changelog: note workspace plugin trust hardening

* Plugins: keep workspace trust gate ahead of memory slot defaults

* Tests: cover workspace memory-slot trust bypass

* fix(providers): respect user-configured baseUrl for kimi-coding (#36647)

* fix(providers): respect user-configured baseUrl for kimi-coding

The kimi-coding provider was built exclusively from
`buildKimiCodingProvider()` defaults, ignoring any user-specified
`baseUrl` or other overrides in `openclaw.json` providers config.
This caused 404 errors when users configured a custom endpoint.

Now merge `explicitProviders["kimi-coding"]` on top of defaults,
matching the pattern used by ollama/vllm. User's `baseUrl`, `api`,
and `models` take precedence; env/profile API key still wins.

Fixes #36353

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Tests: use Kimi implicit provider harness

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* feat(push): add iOS APNs relay gateway (#43369)

* feat(push): add ios apns relay gateway

* fix(shared): avoid oslog string concatenation

# Conflicts:
#	apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayChannel.swift

* fix(push): harden relay validation and invalidation

* fix(push): persist app attest state before relay registration

* fix(push): harden relay invalidation and url handling

* feat(push): use scoped relay send grants

* feat(push): configure ios relay through gateway config

* feat(push): bind relay registration to gateway identity

* fix(push): tighten ios relay trust flow

* fix(push): bound APNs registration fields (#43369) (thanks @ngutman)

* fix(ios): add live activity horizontal padding

* Zalo: rate limit invalid webhook secret guesses before auth (#44173)

* Zalo: rate limit webhook guesses before auth

* Tests: cover pre-auth Zalo webhook rate limiting

* Changelog: note Zalo pre-auth rate limiting

* Zalo: preserve auth-before-content-type response ordering

* Tests: cover auth-before-content-type webhook ordering

* Zalo: split auth and unauth webhook rate-limit buckets

* Tests: cover auth bucket split for Zalo webhook rate limiting

* Zalo: use trusted proxy client IP for webhook rate limiting

* Tests: cover trusted proxy client IP rate limiting for Zalo

* docs: clarify gateway HTTP trust boundary

* Gateway: harden custom session-store discovery (#44176)

Merged via squash.

Prepared head SHA: 52ebbf5188b47386f2a78ac4715993bc082e911b
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(ci): harden docker builds and unblock config docs

* fix: make node-llama-cpp optional for npm installs

* fix: canonicalize openrouter native model keys

* runner: infer names from malformed toolCallId variants (#34485)

Merged via squash.

Prepared head SHA: 150ea1a7c90de3232f72498d851719c4dfb00b43
Co-authored-by: yuweuii <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Gateway: preserve discovered session store paths

* docs: reorder unreleased changelog

* fix(node-host): harden ambiguous approval operand binding (#44247)

* fix(node-host): harden approval operand binding

* test(node-host): cover approval parser hardening

* docs(changelog): note approval hardening GHSA cluster

* Update CHANGELOG.md

* fix(node-host): remove dead approval parser entries

* test(node-host): cover bunx approval wrapper

* fix(node-host): unwrap pnpm shim exec forms

* test(node-host): cover pnpm shim wrappers

* Kimi Coding: set default subscription user agent (#44248)

* Providers: set default Kimi coding user agent

* Tests: cover Kimi coding header overrides

* Changelog: note Kimi coding user agent

* Tests: satisfy Kimi provider fixture type

* Update CHANGELOG.md

* Providers: preserve Kimi headers through models merge

* feat(ui): dashboard-v2 views refactor (slice 3/3 of dashboard-v2) (#41503)

* feat(ui): add chat infrastructure modules (slice 1 of dashboard-v2)

New self-contained chat modules extracted from dashboard-v2-structure:

- chat/slash-commands.ts: slash command definitions and completions
- chat/slash-command-executor.ts: execute slash commands via gateway RPC
- chat/slash-command-executor.node.test.ts: test coverage
- chat/speech.ts: speech-to-text (STT) support
- chat/input-history.ts: per-session input history navigation
- chat/pinned-messages.ts: pinned message management
- chat/deleted-messages.ts: deleted message tracking
- chat/export.ts: shared exportChatMarkdown helper
- chat-export.ts: re-export shim for backwards compat

Gateway fix:
- Restore usage/cost stripping in chat.history sanitization
- Add test coverage for sanitization behavior

These modules are additive and tree-shaken — no existing code
imports them yet. They will be wired in subsequent slices.

* feat(ui): add utilities, theming, and i18n updates (slice 2 of dashboard-v2)

UI utilities and theming improvements extracted from dashboard-v2-structure:

Icons & formatting:
- icons.ts: expanded icon set for new dashboard views
- format.ts: date/number formatting helpers
- tool-labels.ts: human-readable tool name mappings

Theming:
- theme.ts: enhanced theme resolution and system theme support
- theme-transition.ts: simplified transition logic
- storage.ts: theme parsing improvements for settings persistence

Navigation & types:
- navigation.ts: extended tab definitions for dashboard-v2
- app-view-state.ts: expanded view state management
- types.ts: new type definitions (HealthSummary, ModelCatalogEntry, etc.)

Components:
- components/dashboard-header.ts: reusable header component

i18n:
- Updated en, pt-BR, zh-CN, zh-TW locales with new dashboard strings

All changes are additive or backwards-compatible. Build passes.
Part of #36853.

* feat(ui): dashboard-v2 views refactor (slice 3 of dashboard-v2)

Complete views refactor from dashboard-v2-structure, building on
slice 1 (chat infra, #41497) and slice 2 (utilities/theming, #41500).

Core app wiring:
- app.ts: updated host component with new state properties
- app-render.ts: refactored render pipeline for new dashboard layout
- app-render.helpers.ts: extracted render helpers
- app-settings.ts: theme listener lifecycle fix, cron runs on tab load
- app-gateway.ts: refactored chat event handling
- app-chat.ts: slash command integration

New views:
- views/command-palette.ts: command palette (Cmd+K)
- views/login-gate.ts: authentication gate
- views/bottom-tabs.ts: mobile tab navigation
- views/overview-*.ts: modular overview dashboard (cards, attention,
  event log, hints, log tail, quick actions)
- views/agents-panels-overview.ts: agent overview panel

Refactored views:
- views/chat.ts: major refactor with STT, slash commands, search,
  export, pinned messages, input history
- views/config.ts: restructured config management
- views/agents.ts: streamlined agent management
- views/overview.ts: modular composition from sub-views
- views/sessions.ts: enhanced session management

Controllers:
- controllers/health.ts: new health check controller
- controllers/models.ts: new model catalog controller
- controllers/agents.ts: tools catalog improvements
- controllers/config.ts: config form enhancements

Tests & infrastructure:
- Updated test helpers, browser tests, node tests
- vite.config.ts: build configuration updates
- markdown.ts: rendering improvements

Build passes ✅ | 44 files | +6,626/-1,499
Part of #36853. Depends on #41497 and #41500.

* UI: fix chat review follow-ups

* fix(ui): repair chat clear and attachment regressions

* fix(ui): address remaining chat review comments

* fix(ui): address review follow-ups

* fix(ui): replay queued local slash commands

* fix(ui): repair control-ui type drift

* fix(ui): restore control UI styling

* feat(ui): enhance layout and styling for config and topbar components

- Updated grid layout for the config layout to allow full-width usage.
- Introduced new styles for top tabs and search components to improve usability.
- Added theme mode toggle styling for better visual integration.
- Implemented tests for layout and theme mode components to ensure proper rendering and functionality.

* feat(ui): add config file opening functionality and enhance styles

- Implemented a new handler to open the configuration file using the default application based on the operating system.
- Updated various CSS styles across components for improved visual consistency and usability, including adjustments to padding, margins, and font sizes.
- Introduced new styles for the data table and sidebar components to enhance layout and interaction.
- Added tests for the collapsed navigation rail to ensure proper functionality in different states.

* refactor(ui): update CSS styles for improved layout and consistency

- Simplified font-body declaration in base.css for cleaner code.
- Adjusted transition properties in components.css for better readability.
- Added new .workspace-link class in components.css for enhanced link styling.
- Changed config layout from grid to flex in config.css for better responsiveness.
- Updated related tests to reflect layout changes in config-layout.browser.test.ts.

* feat(ui): enhance theme handling and loading states in chat interface

- Updated CSS to support new theme mode attributes for better styling consistency across light and dark themes.
- Introduced loading skeletons in the chat view to improve user experience during data fetching.
- Refactored command palette to manage focus more effectively, enhancing accessibility.
- Added tests for the appearance theme picker and loading states to ensure proper rendering and functionality.

* refactor(ui): streamline ephemeral state management in chat and config views

- Introduced interfaces for ephemeral state in chat and config views to encapsulate related variables.
- Refactored state management to utilize a single object for better organization and maintainability.
- Removed legacy state variables and updated related functions to reference the new state structure.
- Enhanced readability and consistency across the codebase by standardizing state handling.

* chore: remove test files to reduce PR scope

* fix(ui): resolve type errors in debug props and chat search

* refactor(ui): remove stream mode functionality across various components

- Eliminated stream mode related translations and CSS styles to streamline the user interface.
- Updated multiple components to remove references to stream mode, enhancing code clarity and maintainability.
- Adjusted rendering logic in views to ensure consistent behavior without stream mode.
- Improved overall readability by cleaning up unused variables and props.

* fix(ui): add msg-meta CSS and fix rebase type errors

* fix(ui): add CSS for chat footer action buttons (TTS, delete) and msg-meta

* feat(ui): add delete confirmation with remember-decision checkbox

* fix(ui): delete confirmation with remember, attention icon sizing

* fix(ui): open delete confirm popover to the left (not clipped)

* fix(ui): show all nav items in collapsed sidebar, remove gap

* fix(ui): address P1/P2 review feedback — session queue clear, kill scope, palette guard, stop button

* fix(ui): address Greptile re-review — kill scope, queue flush, idle handling, parallel fetch

- SECURITY: /kill <target> now enforces session tree scope (not just /kill all)
- /kill reports idle sessions gracefully instead of throwing
- Queue continues draining after local slash commands
- /model fetches sessions.list + models.list in parallel (perf fix)

* fix(ui): style update banner close button — SVG stroke + sizing

* fix(ui): update layout styles for sidebar and content spacing

* UI: restore colon slash command parsing

* UI: restore slash command session queries

* Refactor thinking resolution: Introduce resolveThinkingDefaultForModel function and update model-selection to utilize it. Add tests for new functionality in thinking.test.ts.

* fix(ui): constrain welcome state logo size, add missing CSS for new session view

---------

Co-authored-by: Vincent Koc <[email protected]>

* fix: restore protocol outputs and stabilize Windows path CI (#44266)

* fix(ci): restore protocol outputs and stabilize Windows path test

Regenerate the Swift protocol models so protocol:check stops failing on main.
Align the session target test helper with the sync production realpath behavior so Windows does not compare runneradmin and RUNNER~1 spellings for the same file.

Regeneration-Prompt: |
  Investigate the failing checks from merged PR #34485 and confirm whether they still affect current main before changing code. Keep the fix tight: do not alter runtime behavior beyond what is required to clear the reproduced CI regressions. Commit the generated Swift protocol outputs for the PushTestResult transport field because protocol:check was failing from stale generated files on main. Also fix the Windows-only session target test by making its helper use the same synchronous realpath behavior as production discovery, so path spelling differences like runneradmin versus RUNNER~1 do not cause a false assertion failure.

* fix(ci): align session target realpath behavior on Windows

Use native realpath for sync session target discovery so it matches the async path on Windows, and update the session target test helper to assert against the same canonical path form.

Regeneration-Prompt: |
  After opening the follow-up PR for the CI regressions from merged PR #34485, inspect the new failing Windows shard instead of assuming the first fix covered every case. Keep scope limited to the session target path mismatch exposed by CI. Fix the inconsistency at the source by making sync session target discovery use the same native realpath canonicalization as the async discovery path on Windows, then update the test helper to match that shared behavior and verify the touched file with targeted tests and file-scoped lint/format checks.

* test: make merge config fixtures satisfy provider type

After rebasing the PR onto current origin/main, the merge helper test fixtures no longer satisfied ProviderConfig because the anthropic provider examples were missing required provider and model fields. Add a shared fully-typed model fixture and explicit anthropic baseUrl values so the test keeps full type coverage under tsgo.

Regeneration-Prompt: |
  Rebase the PR branch for #44266 onto the current origin/main because the failing CI error only reproduced on the merge ref. Re-run the type-check path and inspect src/agents/models-config.merge.test.ts at the exact compiler lines instead of weakening types globally. Keep the fix test-only: make the anthropic ProviderConfig fixtures structurally valid by supplying the required baseUrl and full model definition fields, and keep the shared fixture typed so tsgo accepts it without unknown casts.

* fix: align Windows session store test expectations

* chore(changelog): update CHANGELOG.md to include new features in dashboard-v2, highlighting the refreshed gateway dashboard with modular views and enhanced chat tools (#41503)

* Ollama/Kimi: apply Moonshot payload compatibility (#44274)

* Runner: extend Moonshot payload compat to Ollama Kimi

* Changelog: note Ollama Kimi tool routing

* Tests: cover Ollama Kimi payload compat

* Runner: narrow Ollama Kimi payload compat

* onboard(minimax): flatten auth to 4 direct choices, unify CN/Global under single provider (#44284)

Replace the multi-step MiniMax onboarding wizard with 4 flat options:
- MiniMax Global — OAuth (minimax.io)
- MiniMax Global — API Key (minimax.io)
- MiniMax CN — OAuth (minimaxi.com)
- MiniMax CN — API Key (minimaxi.com)

Storage changes:
- Unify CN and Global under provider "minimax" (baseUrl distinguishes region)
- Profiles: minimax:global / minimax:cn (both regions can coexist)
- Model ref: minimax/MiniMax-M2.5 (no more minimax-cn/ prefix)
- Remove LM Studio local mode and Lightning/Highspeed choice

Backward compatibility:
- Keep minimax-cn in provider-env-vars for existing configs
- Accept minimax-cn as legacy tokenProvider in CI pipelines
- Error with migration hint for removed auth choices in non-interactive mode
- Warn when dual-profile overwrites shared provider baseUrl

Made-with: Cursor

* Gateway/ws: clear unbound scopes for shared-token auth (#44306)

* Gateway/ws: clear unbound shared-auth scopes

* Gateway/auth: cover shared-token scope stripping

* Changelog: add shared-token scope stripping entry

* Gateway/ws: preserve allowed control-ui scopes

* Gateway/auth: assert control-ui admin scopes survive allowed device-less auth

* Gateway/auth: cover shared-password scope stripping

* fix: format CSS files for oxfmt (#44313)

* Commands: require owner for /config and /debug (#44305)

* Commands: add non-owner gate helper

* Commands: enforce owner-only config and debug

* Commands/test: cover owner-only config and debug

* Changelog: add owner-only config debug entry

* Commands/test: split config owner gating section

* Commands: redact sender ids in verbose command logs

* Commands: preserve internal read-only config access

* Commands/test: keep operator.write config show coverage non-owner

* fix(runtime): duplicate messages, share singleton state across bundled chunks (#43683)

* Tests: add fresh module import helper

* Process: share command queue runtime state

* Agents: share embedded run runtime state

* Reply: share followup queue runtime state

* Reply: share followup drain callback state

* Reply: share queued message dedupe state

* Reply: share inbound dedupe state

* Tests: cover shared command queue runtime state

* Tests: cover shared embedded run runtime state

* Tests: cover shared followup queue runtime state

* Tests: cover shared inbound dedupe state

* Tests: cover shared Slack thread participation state

* Slack: share sent thread participation state

* Tests: document fresh import helper

* Telegram: share draft stream runtime state

* Tests: cover shared Telegram draft stream state

* Telegram: share sent message cache state

* Tests: cover shared Telegram sent message cache

* Telegram: share thread binding runtime state

* Tests: cover shared Telegram thread binding state

* Tests: avoid duplicate shared queue reset

* refactor(runtime): centralize global singleton access

* refactor(runtime): preserve undefined global singleton values

* test(runtime): cover undefined global singleton values

---------

Co-authored-by: Nimrod Gutman <[email protected]>

* fix(sandbox): restore spawned workspace handoff (#44307)

* feat(context-engine): plumb sessionKey into all ContextEngine methods (#44157)

Merged via squash.

Prepared head SHA: 0b341f6f4ce487055d8bc0c0d335c42577941592
Co-authored-by: jalehman <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* docs: codify American English spelling convention (#44159)

* fix(failover): classify z.ai network_error stop reason as retryable timeout (#43884)

Merged via squash.

Prepared head SHA: 9660f6cd5bcb8d073fc5575bbba2bf3792b29de3
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(failover): classify ZenMux quota-refresh 402 as rate_limit (#43917)

Merged via squash.

Prepared head SHA: 1d58a36a774d06b1493971e8f14f9abc806be6b0
Co-authored-by: bwjoke <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* Compaction Runner: wire post-compaction memory sync (#25561)

Merged via squash.

Prepared head SHA: 6d2bc02cc16429a19b041acd353c08dd2404335f
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(gateway): honor trusted proxy hook auth rate limits

* fix(security): audit unrestricted hook agent routing

* refactor(gateway): move request client ip resolution to net

* refactor(gateway): cache hook proxy config in runtime state

* refactor(security): reuse hook agent routing normalization

* refactor(test): share hook request handler fixtures

* fix(failover): classify HTTP 422 as format and OpenRouter credits as billing (#43823)

Merged via squash.

Prepared head SHA: 4f48e977fe06c5662753d3900fe94f1835cc2dce
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix: skip cache-ttl append after compaction to prevent double compaction (#28548)

Merged via squash.

Prepared head SHA: a4114a52bcff6ed4057cc54d3c629bd723f3d420
Co-authored-by: MoerAI <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: switch pairing setup codes to bootstrap tokens

* feat: modularize provider plugin architecture

* docs: explain plugin architecture

* fix(ci): restore generated protocol swift outputs (#44411)

Regenerate the Swift protocol models so PushTestResult keeps the transport field required by the current gateway schema, and update protocol:check to diff both generated Swift destinations because the generator writes both files.

Regeneration-Prompt: |
  Investigate the protocol CI failure on current origin/main rather than assuming the earlier fix still held. Confirm whether the generated Swift outputs drifted from the TypeScript gateway schema, identify whether the regression was reintroduced by a later commit, and keep the patch minimal: restore the generated Swift outputs from the existing schema and tighten the protocol check so it verifies every Swift file the generator writes.

* fix(security): harden nodes owner-only tool gating

* refactor: share openai-compatible local discovery

* refactor: remove legacy provider apply shims

* refactor: split non-interactive auth choice providers

* refactor: split simple api-key auth providers

* test: cover provider plugin boundaries

* refactor: unify gateway connect auth selection

* refactor: trim bootstrap token metadata

* refactor: extract websocket handshake auth helpers

* refactor: clarify pairing setup auth labels

* deps: bump openclaw to 2026.3.11

Raise internal OpenClaw constraints to 2026.3.11 and regenerate pnpm lockfile to remove the vulnerable 2026.3.8 resolution.

* fix: harden windows npm runtime path

* feat: add --no-test flag to prepare-gates

Allows skipping the full test suite during prepare phase.
Testing is deferred to the dedicated Test phase in the pipeline.

* fix(node-host): fail closed on ruby approval preload flags

* feat: add fast mode toggle for OpenAI models

* Revert "feat: add --no-test flag to prepare-gates"

This reverts commit ee6bdb3bab26f2796943c6cac03d8f62a5664937.

* feat: add Anthropic fast mode support

* fix: harden windows native updates

* feat: add windows update package spec override

* fix(hooks): dedupe repeated agent deliveries by idempotency key (#44438)

* Hooks: add hook idempotency key resolution

* Hooks: dedupe repeated agent deliveries by idempotency key

* Tests: cover hook idempotency dedupe

* Changelog: note hook idempotency dedupe

* Hooks: cap hook idempotency key length

* Gateway: hash hook replay cache keys

* Tests: cover hook replay key hardening

* fix(hooks): fail closed on unreadable loader paths (#44437)

* Hooks: fail closed on unreadable loader paths

* Changelog: note hooks loader hardening

* Tests: cover sanitized hook loader logs

* Hooks: use realpath containment for legacy loaders

* Hooks: sanitize unreadable workspace log path

* fix(models): keep codex spark codex-only

* test(live): add codex instructions to spark probe

* fix(security): strip Mongolian selectors in exec obfuscation detector

* Gateway: preserve trusted-proxy browser scopes

* build: update deps and fix vitest 4 regressions

* build: sync bundled plugin versions

* refactor: add non-interactive provider plugin setup

* refactor: validate provider plugin metadata

* fix(zalouser): require ids for group allowlist auth

* fix: avoid ineffective dynamic imports

* fix(mac): adopt canonical session key and add reset triggers (#10898)

Add shared native chat handling for /new, /reset, and /clear.

This also aligns main session key handling in the shared chat UI and includes follow-up test and CI fixes needed to keep the branch mergeable.

Co-authored-by: Nachx639 <[email protected]>
Co-authored-by: Luke <[email protected]>

* test: resolve rebase conflicts in gateway coverage

* chore: prepare 2026.3.12 release

* refactor(zalouser): reuse shared name matching helper

* feat(zalouser): audit mutable group allowlists

* fix(routing): require ids for slack and msteams allowlists

* fix: quiet Telegram command overflow retry logs

* fix(memory): fail closed for Windows qmd wrappers

* docs(ollama): update onboarding flow

Co-Authored-By: Jeffrey Morgan <[email protected]>
(cherry picked from commit e8ca2ff4e522f2d971801a537b3c4fdfecde0711)

* fix: align Ollama onboarding docs before landing (#43473) (thanks @BruceMacD)

(cherry picked from commit 19fa274343a102ca85c7679ec28c5a3503a99f55)

* docs: reorder latest release changelog

* test: stabilize hooks loader log assertion on Windows

* fix: import oauth types from the oauth entrypoint

* refactor(agents): replace console.warn with SubsystemLogger in compaction-safeguard.ts (#9974)

Merged via squash.

Prepared head SHA: 35dcc5ba354ad7f058d796846bda9d1f8a416e04
Co-authored-by: dinakars777 <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: clarify windows onboarding gateway health

* fix(gateway): strip unbound scopes for shared-auth connects

* test(commands): align slash-command config persistence coverage

* fix: use build-stage image for docker live tests

* test: harden plugin env-scoped fixtures

* fix(cron): avoid false legacy payload kind migrations

* fix(cron): compare raw value not trimmed in normalizePayloadKind

* fix: stop false cron payload-kind warnings in doctor (#44012) (thanks @shuicici)

* fix(memory): stop forcing Windows qmd cmd shims

* test: harden plugin fixture permissions on macos

* fix(feishu): fail closed on webhook signature checks

* test(qmd): make windows cli fixtures explicit

* test(gateway): avoid hoisted reply mock tdz

* fix: fall back to a startup entry for windows gateway install

* Slack: support Block Kit payloads in agent replies (#44592)

* Slack: route reply blocks through outbound adapter

* Slack: cover Block Kit outbound payloads

* Changelog: add Slack Block Kit agent reply entry

* fix: enable fast mode for isolated cron runs

* fix(acp): preserve final assistant message snapshot before end_turn (#44597)

Process messageData via handleDeltaEvent for both delta and final states
before resolving the turn, so ACP clients no longer drop the last visible
assistant text when the gateway sends the final message body on the
terminal chat event.

Closes #15377
Based on #17615

Co-authored-by: PJ Eby <[email protected]>

* fix: narrow Slack outbound blocks opt type

* changelog: move ACP final-snapshot entry to active 2026.3.12 section

* fix(ci): restore full gate

* UI: fix control chat logo fallback

* test(qmd): make windows cli fixtures explicit

* UI: fix mounted avatar meta fallback

* fix(ui): resolve control chat avatar fallback

* fix(ui): harden avatar fallback regressions

* test(ui): add jsdom runtime for vitest dom suites

* fix(ui): restore native web /status

* feat: show status reaction during context compaction (#35474)

Merged via squash.

Prepared head SHA: 145a7b7c4e1939718c41a300899ae813bd9c511b
Co-authored-by: Cypherm <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(plugins): normalize bundled provider ids

* test(proxy): make env proxy tests windows-safe

* chore: update appcast for 2026.3.12 release

* fix(compaction): use full-session token count for post-compaction sanity check (#28347)

Merged via squash.

Prepared head SHA: cf4eab1c51e6b8890e23c2d7172313c40cd2fe04
Co-authored-by: efe-arv <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* chore: bump version to 2026.3.13

* test(utils): await temp dir cleanup in async tests

* fix(telegram): thread media transport policy into SSRF (#44639)

* fix(telegram): preserve media download transport policy

* refactor(telegram): thread media transport policy

* fix(telegram): sync fallback media policy

* fix: note telegram media transport fix (#44639)

* fix: handle Discord gateway metadata fetch failures (#44397)

Merged via squash.

Prepared head SHA: edd17c0effe4f90887ac94ce549f44a69fe19eb2
Co-authored-by: jalehman <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: harden windows gateway fallback launch

* test: fix windows startup fallback mock typing

* docs: move post-release changelog entries to Unreleased (#44691)

4 entries were added to the 2026.3.12 section after the v2026.3.12
tag was cut. Move them to ## Unreleased where they belong.

Verified: 2026.3.12 section now matches the 74 entries present at
the v2026.3.12 release tag (28d64c48e).

* fix(android): clip CommandBlock accent bar to rounded container bounds

* fix: recover outbound plugins from the active registry

* test: stabilize sanitize session history smoke checks

* feat(android): redesign onboarding flow UI

- Welcome: replace bullet list with icon+subtitle feature cards
- Gateway: simplify to single instruction line, collapse advanced by default, remove verbose developer text
- Permissions: group into System/Media/Personal Data sections, rewrite subtitles to plain English, style "Not granted" with warning color
- Review: replace plain text fields with icon cards matching Welcome style, add colored status cards for connect/pairing states
- Remove redundant "FIRST RUN" label, "Step X of 4" text, and StepRailWrap dividers

* fix(session): preserve `lastAccountId` and `lastThreadId` on session reset

* fix: add gateway session reset routing coverage (#44773) (thanks @Lanfei)

* Updated default model from openai-codex/gpt-5.3-codex to openai-codex/gpt-5.4 in tests. (#44367)

Merged via squash.

Prepared head SHA: c372ba691b9964dc986c3a4880a7413ab8fb23f7
Co-authored-by: jrrcdev <[email protected]>
Co-authored-by: dvrshil <[email protected]>
Reviewed-by: @dvrshil

* fix: address delivery dedupe review follow-ups (#44666)

Merged via squash.

Prepared head SHA: 8e6d254cc4781df66ee02b683c4ad72b5a633502
Co-authored-by: frankekn <[email protected]>
Co-authored-by: frankekn <[email protected]>
Reviewed-by: @frankekn

* CLI: align xhigh thinking help text (#44819)

Merged via squash.

Prepared head SHA: ff1f12717692d7745b34c5aef7c1dde3c6a4500d
Co-authored-by: frankekn <[email protected]>
Co-authored-by: frankekn <[email protected]>
Reviewed-by: @frankekn

* docs: fix changelog credit for xhigh help (#44874)

* fix(sre:PLA-815): drop accidental node_modules from sync branch

* fix(agents): drop Anthropic thinking blocks on replay (#44843)

* agents: drop Anthropic thinking blocks on replay

* fix: extend anthropic replay sanitization openclaw#44429 thanks @jmcte

* fix: extend anthropic replay sanitization openclaw#44843 thanks @jmcte

* test: add bedrock replay sanitization coverage openclaw#44843

* test: cover anthropic provider drop-thinking hints openclaw#44843

---------

Co-authored-by: johnmteneyckjr <[email protected]>

* docs: fix session key :dm: → :direct (#26506)

* ci(sre:PLA-815): remove secrets job from ci workflow

* feat(android): redesign Connect tab with unified status cards

Merge endpoint and status into a single grouped card with icons.
Split connect/disconnect into context-aware buttons.

* feat(android): add speaker label and status pill to Voice tab

Add text label under speaker toggle, balance layout with matching
spacer column, and wrap status text in a colored pill.

* feat(android): compact chat composer layout

Remove MESSAGE label and divider, let text field auto-size instead
of fixed 92dp, and merge Detail/Attach into the bottom action row.

* feat(android): soften chat role labels and deduplicate session header

Rename role labels to You/OpenClaw/System, update streaming label to
OpenClaw · Live, and remove the redundant SESSION row + Connected pill
since the top bar and chip row already convey both.

* feat(android): consolidate Settings…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to documentation maintainer Maintainer-authored PR scripts Repository scripts size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant