Compare commits

..

89 Commits

Author SHA1 Message Date
quotentiroler
b4aefa3937 feat(ci): add staged release pipeline workflows (dormant)
Add all new CI/CD workflow files for the staged branch promotion pipeline
(develop  alpha  beta  main). Push triggers are intentionally disabled
workflows use workflow_dispatch or workflow_call only.

No changes to existing ci.yml. All workflows are inert until activated in
a follow-up PR.

New workflows:
- feature-pr.yml: auto-create PRs to develop (disabled)
- hotfix-pr.yml: emergency hotfix PRs to main (disabled)
- promote-branch.yml: staged promotion (disabled)
- release-orchestrator.yml: release pipeline (disabled)
- deployment-strategy.yml: npm + Docker deploy (workflow_call)
- testing-strategy.yml: progressive test gates (workflow_call)
- generate-changelog.yml: changelog generation (workflow_call)
- version-operations.yml: version bumping (workflow_call)
- release.yml: manual release trigger (workflow_dispatch)
- rollback.yml: emergency rollback (workflow_dispatch)
- discord-notify action: reusable notification

Also adds pipeline docs and updates CONTRIBUTING.md with future branch
strategy (clearly marked as not yet active).

Split from #10755 for safe, additive merge.
2026-02-07 09:50:02 -08:00
大猫子
a4d5c7f673 docs: add missing HEARTBEAT.md and MEMORY.md to bootstrap files list (#8105)
* docs: add missing HEARTBEAT.md and MEMORY.md to bootstrap files list

Fixes #7928

The documentation for skipBootstrap and workspace setup was missing
HEARTBEAT.md and MEMORY.md from the bootstrap files list.

Changes:
- docs/gateway/configuration.md: Add HEARTBEAT.md and MEMORY.md
- docs/zh-CN/gateway/configuration.md: Same for Chinese version
- docs/start/openclaw.md: Add HEARTBEAT.md, clarify MEMORY.md is optional
- docs/zh-CN/start/openclaw.md: Same for Chinese version

* fix: reference PR number instead of issue in CHANGELOG

* docs(workspace): align bootstrap file docs with runtime (#8105)

---------

Co-authored-by: damaozi <1811866786@qq.com>
Co-authored-by: Sebastian <19554889+sebslight@users.noreply.github.com>
2026-02-07 10:51:44 -05:00
Seb Slight
9a3f62cb86 docs: add symptom-first troubleshooting hub and deep runbooks (#11196)
* docs(troubleshooting): add symptom-first troubleshooting runbooks

* docs(troubleshooting): fix approvals command examples

* docs(troubleshooting): wrap symptom cases in accordions

* docs(automation): clarify userTimezone missing-key behavior

* docs(troubleshooting): fix first-60-seconds ladder order
2026-02-07 10:28:19 -05:00
Tyler Yust
1007d71f0c fix: comprehensive BlueBubbles and channel cleanup (#11093)
* feat(bluebubbles): auto-strip markdown from outbound messages (#7402)

* fix(security): add timeout to webhook body reading (#6762)

Adds 30-second timeout to readBody() in voice-call, bluebubbles, and nostr
webhook handlers. Prevents Slow-Loris DoS (CWE-400, CVSS 7.5).
Merged with existing maxBytes protection in voice-call.

* fix(security): unify Error objects and lint fixes in webhook timeouts (#6762)

* fix: prevent plugins from auto-enabling without user consent (#3961)

Changes default plugin enabled state from true to false in enablePluginEntry().
Preserves existing enabled:true values. Fixes #3932.

* fix: apply hierarchical mediaMaxMb config to all channels (#8749)

Generalizes resolveAttachmentMaxBytes() to use account → channel → global
config resolution for all channels, not just BlueBubbles. Fixes #7847.

* fix(bluebubbles): sanitize attachment filenames against header injection (#10333)

Strip ", \r, \n, and \\ from filenames after path.basename() to prevent
multipart Content-Disposition header injection (CWE-93, CVSS 5.4).
Also adds sanitization to setGroupIconBlueBubbles which had zero filename
sanitization.

* fix(lint): exclude extensions/ from Oxlint preflight check (#9313)

Extensions use PluginRuntime|null patterns that trigger
no-redundant-type-constituents because PluginRuntime resolves to any.
Excluding extensions/ from Oxlint unblocks user upgrades.
Re-applies the approach from closed PR #10087.

* fix(bluebubbles): add tempGuid to createNewChatWithMessage payload (#7745)

Non-Private-API mode (AppleScript) requires tempGuid in send payloads.
The main sendMessageBlueBubbles already had it, but createNewChatWithMessage
was missing it, causing 400 errors for new chat creation without Private API.

* fix: send stop-typing signal when run ends with NO_REPLY (#8785)

Adds onCleanup callback to the typing controller that fires when the
controller is cleaned up while typing was active (e.g., after NO_REPLY).
Channels using createTypingCallbacks automatically get stop-typing on
cleanup. This prevents the typing indicator from lingering in group chats
when the agent decides not to reply.

* fix(telegram): deduplicate skill commands in multi-agent setup (#5717)

Two fixes:
1. Skip duplicate workspace dirs when listing skill commands across agents.
   Multiple agents sharing the same workspace would produce duplicate commands
   with _2, _3 suffixes.
2. Clear stale commands via deleteMyCommands before registering new ones.
   Commands from deleted skills now get cleaned up on restart.

* fix: add size limits to unbounded in-memory caches (#4948)

Adds max-size caps with oldest-entry eviction to prevent OOM in
long-running deployments:
- BlueBubbles serverInfoCache: 64 entries (already has TTL)
- Google Chat authCache: 32 entries
- Matrix directRoomCache: 1024 entries
- Discord presenceCache: 5000 entries per account

* fix: address review concerns (#11093)

- Chain deleteMyCommands → setMyCommands to prevent race condition (#5717)
- Rename enablePluginEntry to registerPluginEntry (now sets enabled: false)
- Add Slow-Loris timeout test for readJsonBody (#6023)
2026-02-07 05:00:55 -08:00
Peter Steinberger
9f703a44dc chore(release): 2026.2.6-3 2026-02-07 00:44:32 -08:00
Peter Steinberger
85ed6c7fa4 chore(onboard): reorder xAI + Qianfan providers 2026-02-07 00:43:13 -08:00
Peter Steinberger
ad4dd0422e chore(release): 2026.2.6-2 2026-02-07 00:30:43 -08:00
Peter Steinberger
4ba9809f18 test(hooks): stabilize session-memory hook tests 2026-02-07 00:22:34 -08:00
Peter Steinberger
80d42eb0ba fix(docker): support .mjs entrypoints in images and e2e 2026-02-07 00:22:34 -08:00
Peter Steinberger
2b6cf03b47 fix(build): support daemon-cli .mjs bundles in compat shim 2026-02-07 00:22:34 -08:00
Peter Steinberger
88ffad1c4f Merge PR #8868: add Baidu Qianfan support (thanks @ide-rea) 2026-02-07 00:19:04 -08:00
Peter Steinberger
875324e7c7 docs(changelog): note CI pipeline optimization (#10784) (thanks @mcaxtr) 2026-02-06 23:31:48 -08:00
Marcus Castro
2d7428a7f2 ci: re-enable parallel vitest on Windows CI 2026-02-06 23:31:48 -08:00
Marcus Castro
47596257ea ci: add concurrency controls, consolidate macOS jobs, optimize Windows CI 2026-02-06 23:31:48 -08:00
Peter Steinberger
ab3045cb48 chore(onboard): move xAI below Google 2026-02-06 23:06:55 -08:00
Peter Steinberger
aaddbdae52 chore(release): 2026.2.6-1 2026-02-06 22:48:19 -08:00
Peter Steinberger
8d0e7997c8 chore(onboard): move xAI up in auth list 2026-02-06 22:41:19 -08:00
Peter Steinberger
31a7e4f937 chore(skills): remove bird skill 2026-02-06 22:28:44 -08:00
Peter Steinberger
c5194d8148 fix(dashboard): restore tokenized control ui links 2026-02-06 22:17:09 -08:00
ide-rea
43c0a7fe1c Merge branch 'openclaw:main' into qianfan 2026-02-07 14:07:52 +08:00
Jake
e78ae48e69 fix(memory): add input_type to Voyage AI embeddings for improved retrieval (#10818)
* fix(memory): add input_type to Voyage AI embeddings for improved retrieval

Voyage AI recommends passing input_type='document' when indexing and
input_type='query' when searching. This improves retrieval quality by
optimising the embedding space for each direction.

Changes:
- embedQuery now passes input_type: 'query'
- embedBatch now passes input_type: 'document'
- Batch API request_params includes input_type: 'document'
- Tests updated to verify input_type is passed correctly

* Changelog: note Voyage embeddings input_type fix (#10818) (thanks @mcinteerj)

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-06 21:55:09 -06:00
Markus Buhatem Koch
4c1da23a71 Revert previous change from 'Clawdbot' to 'OpenClaw' in lore (#9119) 2026-02-06 21:53:02 -05:00
Val Alexander
3d2fe9284e Fix repository links in formal-verification.md (#10200)
Updated repository links for formal verification models.
2026-02-06 21:47:55 -05:00
Peter Steinberger
a3b5f1b15c fix(build): unblock pnpm build dts 2026-02-06 18:43:11 -08:00
DEOKLYONG MOON
d1dc60774b Docs: fix broken /plugins links (#9308)
* Docs: fix broken /plugins links to /plugin

The documentation linked to /plugins which doesn't exist.
The correct path is /plugin (singular) which contains the
plugins overview documentation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: drop manual zh-CN doc edits from plugins link fix

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Sebastian <19554889+sebslight@users.noreply.github.com>
2026-02-06 21:08:26 -05:00
Tyler Yust
d90cac990c fix: cron scheduler reliability, store hardening, and UX improvements (#10776)
* refactor: update cron job wake mode and run mode handling

- Changed default wake mode from 'next-heartbeat' to 'now' in CronJobEditor and related CLI commands.
- Updated cron-tool tests to reflect changes in run mode, introducing 'due' and 'force' options.
- Enhanced cron-tool logic to handle new run modes and ensure compatibility with existing job structures.
- Added new tests for delivery plan consistency and job execution behavior under various conditions.
- Improved normalization functions to handle wake mode and session target casing.

This refactor aims to streamline cron job configurations and enhance the overall user experience with clearer defaults and improved functionality.

* test: enhance cron job functionality and UI

- Added tests to ensure the isolated agent correctly announces the final payload text when delivering messages via Telegram.
- Implemented a new function to pick the last deliverable payload from a list of delivery payloads.
- Enhanced the cron service to maintain legacy "every" jobs while minute cron jobs recompute schedules.
- Updated the cron store migration tests to verify the addition of anchorMs to legacy every schedules.
- Improved the UI for displaying cron job details, including job state and delivery information, with new styles and layout adjustments.

These changes aim to improve the reliability and user experience of the cron job system.

* test: enhance sessions thinking level handling

- Added tests to verify that the correct thinking levels are applied during session spawning.
- Updated the sessions-spawn-tool to include a new parameter for overriding thinking levels.
- Enhanced the UI to support additional thinking levels, including "xhigh" and "full", and improved the handling of current options in dropdowns.

These changes aim to improve the flexibility and accuracy of thinking level configurations in session management.

* feat: enhance session management and cron job functionality

- Introduced passthrough arguments in the test-parallel script to allow for flexible command-line options.
- Updated session handling to hide cron run alias session keys from the sessions list, improving clarity.
- Enhanced the cron service to accurately record job start times and durations, ensuring better tracking of job execution.
- Added tests to verify the correct behavior of the cron service under various conditions, including zero-delay timers.

These changes aim to improve the usability and reliability of session and cron job management.

* feat: implement job running state checks in cron service

- Added functionality to prevent manual job runs if a job is already in progress, enhancing job management.
- Updated the `isJobDue` function to include checks for running jobs, ensuring accurate scheduling.
- Enhanced the `run` function to return a specific reason when a job is already running.
- Introduced a new test case to verify the behavior of forced manual runs during active job execution.

These changes aim to improve the reliability and clarity of cron job execution and management.

* feat: add session ID and key to CronRunLogEntry model

- Introduced `sessionid` and `sessionkey` properties to the `CronRunLogEntry` struct for enhanced tracking of session-related information.
- Updated the initializer and Codable conformance to accommodate the new properties, ensuring proper serialization and deserialization.

These changes aim to improve the granularity of logging and session management within the cron job system.

* fix: improve session display name resolution

- Updated the `resolveSessionDisplayName` function to ensure that both label and displayName are trimmed and default to an empty string if not present.
- Enhanced the logic to prevent returning the key if it matches the label or displayName, improving clarity in session naming.

These changes aim to enhance the accuracy and usability of session display names in the UI.

* perf: skip cron store persist when idle timer tick produces no changes

recomputeNextRuns now returns a boolean indicating whether any job
state was mutated. The idle path in onTimer only persists when the
return value is true, eliminating unnecessary file writes every 60s
for far-future or idle schedules.

* fix: prep for merge - explicit delivery mode migration, docs + changelog (#10776) (thanks @tyler6204)
2026-02-06 18:03:03 -08:00
Peter Steinberger
0dd7033521 chore(lockfile): fix pnpm-lock 2026-02-06 17:56:22 -08:00
Raymond Berger
c80a09fc2f Fix QMD CLI installation link in memory.md (#8647)
Correct the installation link for the QMD CLI in the documentation.
2026-02-06 20:53:47 -05:00
Peter Steinberger
f831c48e56 docs(changelog): highlight Opus 4.6 + Codex 5.3 first 2026-02-06 17:28:46 -08:00
Peter Steinberger
c237a82b42 docs(changelog): curate 2026.2.6 2026-02-06 16:56:29 -08:00
Peter Steinberger
94b2fc14f2 chore(deps): bump carbon beta 2026-02-06 16:56:25 -08:00
Peter Steinberger
0daf416908 fix(agents): add Opus 4.6 forward-compat fallback 2026-02-06 16:56:21 -08:00
Peter Steinberger
dca8cf958b chore(deps): update deps 2026-02-06 16:37:56 -08:00
Seb Slight
93bf75279f docs(imessage): improve macOS TCC troubleshooting guidance (#10781) 2026-02-06 19:21:52 -05:00
gitpds
fe308a3aa1 docs(imessage): add macOS TCC troubleshooting 2026-02-06 19:10:01 -05:00
Peter Steinberger
7be921c434 docs(changelog): refresh 2026.2.6 since v2026.2.3 2026-02-06 15:47:10 -08:00
Peter Steinberger
5163833be5 docs: fix markdownlint fragments + headings 2026-02-06 15:45:39 -08:00
Peter Steinberger
d898ad6807 fix(telegram): cast fetch for grammY ApiClientOptions 2026-02-06 15:45:34 -08:00
Peter Steinberger
677450cd9b chore(release): bump version to 2026.2.6 2026-02-06 15:37:31 -08:00
Peter Steinberger
ac5944cde7 docs(changelog): include merged PRs since v2026.2.3 2026-02-06 15:36:13 -08:00
Peter Steinberger
3b768a2851 docs(changelog): prepare 2026.2.6 2026-02-06 15:30:17 -08:00
Shadril Hassan Shifat
2c8af78d20 fix(hooks): replace debug console.log with proper subsystem logging in session-memory (#10730)
* fix: replace debug console.log with proper subsystem logging in session-memory

* fix(hooks): normalize session-memory subsystem logging

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-06 17:22:38 -06:00
calvin-hpnet
48b0fd8d88 feat(antigravity): update default model to Claude Opus 4.6 (#10720)
* feat(antigravity): update default model to Claude Opus 4.6

Claude Opus 4.5 has been replaced by Claude Opus 4.6 on the
Antigravity (Google Cloud Code Assist) platform.

- Update DEFAULT_MODEL in google-antigravity-auth extension
- Update testing docs to reference the new model

* fix: update remaining antigravity opus 4.5 refs in zh-CN docs and tests

Address review comments from Greptile:
- Update zh-CN/testing.md antigravity model references
- Update pi-tools-agent-config.test.ts model IDs

* Antigravity: default OAuth model to Opus 4.6 (#10720) (thanks @calvin-hpnet)

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-06 16:42:57 -06:00
Tak Hoffman
40425db0f1 feat(memory): document Voyage embeddings + VOYAGE_API_KEY (#7078) (thanks @mcinteerj) (#10699) 2026-02-06 15:51:47 -06:00
Jake
6965a2cc9d feat(memory): native Voyage AI support (#7078)
* feat(memory): add native Voyage AI embedding support with batching

Cherry-picked from PR #2519, resolved conflict in memory-search.ts
(hasRemote -> hasRemoteConfig rename + added voyage provider)

* fix(memory): optimize voyage batch memory usage with streaming and deduplicate code

Cherry-picked from PR #2519. Fixed lint error: changed this.runWithConcurrency
to use imported runWithConcurrency function after extraction to internal.ts
2026-02-06 15:09:32 -06:00
Tak Hoffman
e3d3893d5d Docs: revise PR and issue submission guides (#10617)
* Docs: revise PR submission guide

* Docs: revise issue submission guide
2026-02-06 13:29:11 -06:00
Yida-Dev
4216449405 fix: guard resolveUserPath against undefined input (#10176)
* fix: guard resolveUserPath against undefined input

When subagent spawner omits workspaceDir, resolveUserPath receives
undefined and crashes on .trim().  Add a falsy guard that falls back
to process.cwd(), matching the behavior callers already expect.

Closes #10089

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: harden runner workspace fallback (#10176) (thanks @Yida-Dev)

* fix: harden workspace fallback scoping (#10176) (thanks @Yida-Dev)

* refactor: centralize workspace fallback classification and redaction (#10176) (thanks @Yida-Dev)

* test: remove explicit any from utils mock (#10176) (thanks @Yida-Dev)

* security: reject malformed agent session keys for workspace resolution (#10176) (thanks @Yida-Dev)

---------

Co-authored-by: Yida-Dev <reyifeijun@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com>
2026-02-06 13:16:58 -05:00
Tak Hoffman
5842bcaaf7 Docs: add PR sign-off template (#10561) 2026-02-06 11:58:39 -06:00
Seb Slight
991cf4d7fe Docs: revamp installer internals for readability and accuracy (#10499)
* docs(install): revamp installer internals for readability and accuracy

Restructure the installer internals page with better flow and Mintlify
components (CardGroup, Steps, Tabs, AccordionGroup). All flags, env vars,
and behavioral descriptions cross-checked against install.sh,
install-cli.sh, and install.ps1 source code.

- Add CardGroup chooser and Quick Commands section at top
- Organize each script into consistent Flow → Examples → Reference pattern
- Move flags/env var tables into collapsible Accordions
- Consolidate troubleshooting into AccordionGroup at bottom
- Add missing flags (--version, --beta, --verbose, --help, etc.)
- Add missing env vars (OPENCLAW_VERSION, OPENCLAW_BETA, etc.)
- Document install-cli.sh fully (was one paragraph)
- Fix non-interactive checkout detection behavior (defaults to npm)
- Use --proto/--tlsv1.2 in curl examples to match script usage
- No content deleted; all original info preserved or relocated

* fix(docs): correct in-page anchor hrefs for installer cards

* docs(install): replace CardGroup with table for installer overview
2026-02-06 10:49:38 -05:00
Seb Slight
578a6e27aa Docs: enable markdownlint autofixables except list numbering (#10476)
* docs(markdownlint): enable autofixable rules except list numbering

* docs(zalo): fix malformed bot platform link
2026-02-06 10:08:59 -05:00
Sebastian
0a1f4f666a revert(docs): undo markdownlint autofix churn 2026-02-06 10:00:08 -05:00
Sebastian
c7aec0660e docs(markdownlint): enable autofixable rules and normalize links 2026-02-06 09:55:12 -05:00
Sebastian
1bf9f237f7 docs: linting 2026-02-06 09:35:57 -05:00
Sebastian
134c03a903 feat: add markdownlint configuration for documentation formatting and linting 2026-02-06 09:14:36 -05:00
Seb Slight
18b480dd3e Docs: sharpen Install tab to stop duplicating Getting Started (#10416)
* docs(install): reframe install overview to stop duplicating getting started

* docs(install): link default installer row to getting started, not internals

* docs(install): use Mintlify components for install overview

* docs(install): fix card grid layout with CardGroup

* docs(install): platform tabs for global install, npm/pnpm as accordion

* docs(install): add PowerShell no-onboard alternative

* docs(install): add repo link to from-source clone step

* docs(install): capitalize OpenClaw in repo link

* docs(install): add pnpm link --global to from-source steps

* docs(install): rewrite install overview for clarity and flow

* docs(install): use tooltip for Windows WSL2 recommendation

* docs(install): use Note box for Windows WSL2 recommendation

* docs(install): group install methods under single heading

* docs(install): standardize tab labels across installer sections

* docs(install): rewrite Node.js page with install instructions and better structure

* docs(install): clarify Node.js page intro

* docs(install): scope auto-install note to installer script, link Node page

* docs(install): fix installer script link to internals page

* docs: rename Install methods nav group to Other install methods

* docs(install): link to on-page anchor, use Tip box for recommended

* docs(install): wrap install methods in AccordionGroup with Tip box

* docs: move Node.js page from Install to Help > Environment and debugging

* docs(install): add complete flags and env vars reference to installer internals

* docs(install): use stable troubleshooting anchor for Node.js link

* docs(install): fix Node page installer anchor

* docs(install): fix broken installer script anchor in requirements note
2026-02-06 08:55:05 -05:00
ideoutrea
0b51f0d762 Fix conflicts 2026-02-06 18:16:20 +08:00
ideoutrea
7a9deb2400 Resolve conflicts 2026-02-06 18:13:42 +08:00
ide-rea
3997316fb0 Merge branch 'main' into qianfan 2026-02-06 17:58:28 +08:00
ideoutrea
360851366f Support ERNIE-5.0-Thinking-Preview 2026-02-06 17:49:54 +08:00
Gustavo Madeira Santana
c75275f109 Update: harden control UI asset handling in update flow (#10146)
* Update: harden control UI asset handling in update flow

* fix: harden update doctor entrypoint guard (#10146) (thanks @gumadeiras)
2026-02-06 01:14:00 -05:00
Tak Hoffman
50e687d17d Docs: add PR and issue submission guides (#10150)
* Docs: add PR and issue submission guides

* Docs: fix LLM-assisted wording
2026-02-05 23:59:47 -06:00
Gustavo Madeira Santana
4a59b7786b fix: CLI harden update restart imports and fix nested bundle version resolution 2026-02-06 00:09:48 -05:00
Tak Hoffman
8a352c8f9d Web UI: add token usage dashboard (#10072)
* feat(ui): Token Usage dashboard with session analytics

Adds a comprehensive Token Usage view to the dashboard:

Backend:
- Extended session-cost-usage.ts with per-session daily breakdown
- Added date range filtering (startMs/endMs) to API endpoints
- New sessions.usage, sessions.usage.timeseries, sessions.usage.logs endpoints
- Cost breakdown by token type (input/output/cache read/write)

Frontend:
- Two-column layout: Daily chart + breakdown | Sessions list
- Interactive daily bar chart with click-to-filter and shift-click range select
- Session detail panel with usage timeline, conversation logs, context weight
- Filter chips for active day/session selections
- Toggle between tokens/cost view modes (default: cost)
- Responsive design for smaller screens

UX improvements:
- 21-day default date range
- Debounced date input (400ms)
- Session list shows filtered totals when days selected
- Context weight breakdown shows skills, tools, files contribution

* fix(ui): restore gatewayUrl validation and syncUrlWithSessionKey signature

- Restore normalizeGatewayUrl() to validate ws:/wss: protocol
- Restore isTopLevelWindow() guard for iframe security
- Revert syncUrlWithSessionKey signature (host param was unused)

* feat(ui): Token Usage dashboard with session analytics

Adds a comprehensive Token Usage view to the dashboard:

Backend:
- Extended session-cost-usage.ts with per-session daily breakdown
- Added date range filtering (startMs/endMs) to API endpoints
- New sessions.usage, sessions.usage.timeseries, sessions.usage.logs endpoints
- Cost breakdown by token type (input/output/cache read/write)

Frontend:
- Two-column layout: Daily chart + breakdown | Sessions list
- Interactive daily bar chart with click-to-filter and shift-click range select
- Session detail panel with usage timeline, conversation logs, context weight
- Filter chips for active day/session selections
- Toggle between tokens/cost view modes (default: cost)
- Responsive design for smaller screens

UX improvements:
- 21-day default date range
- Debounced date input (400ms)
- Session list shows filtered totals when days selected
- Context weight breakdown shows skills, tools, files contribution

* fix: usage dashboard data + cost handling (#8462) (thanks @mcinteerj)

* Usage: enrich metrics dashboard

* Usage: add latency + model trends

* Gateway: improve usage log parsing

* UI: add usage query helpers

* UI: client-side usage filter + debounce

* Build: harden write-cli-compat timing

* UI: add conversation log filters

* UI: fix usage dashboard lint + state

* Web UI: default usage dates to local day

* Protocol: sync session usage params (#8462) (thanks @mcinteerj, @TakHoffman)

---------

Co-authored-by: Jake McInteer <mcinteerj@gmail.com>
2026-02-05 22:35:46 -06:00
Gustavo Madeira Santana
b40da2cb7a fix: remove dead restore control-ui step from update runner 2026-02-05 22:10:55 -05:00
Gustavo Madeira Santana
72245855e5 fix: add fallback for Control UI asset resolution in global installs 2026-02-05 22:03:43 -05:00
Gustavo Madeira Santana
7b2a221212 chore: run lint step after build during preflight check 2026-02-05 21:22:27 -05:00
Sebastian
ac0c2f260f docs: update clawtributors (add @unisone) 2026-02-05 21:19:42 -05:00
Alex Zaytsev
d2aee7da68 docs: add activeHours to heartbeat field notes and examples (#9366)
Co-authored-by: unisone <unisone@users.noreply.github.com>
2026-02-05 21:18:57 -05:00
Coy Geek
717129f7f9 fix: silence unused hook token url param (#9436)
* fix: Gateway authentication token exposed in URL query parameters

* fix: silence unused hook token url param

* fix: remove gateway auth tokens from URLs (#9436) (thanks @coygeek)

* test: fix Windows path separators in audit test (#9436)

---------

Co-authored-by: George Pickett <gpickett00@gmail.com>
2026-02-05 18:08:29 -08:00
Matt Ezell
b1430aaaca Chore: Update memory.md with current default workspace path (#9559)
Removed 'clawd' workspace reference - updated with current default workspace path of '~/.openclaw/workspace'
2026-02-05 21:06:14 -05:00
Shailesh
bccdc95a9b Cap sessions_history payloads to prevent context overflow (#10000)
* Cap sessions_history payloads to prevent context overflow

* fix: harden sessions_history payload caps

* fix: cap sessions_history payloads to prevent context overflow (#10000) (thanks @gut-puncture)

---------

Co-authored-by: Shailesh Rana <shaileshrana@ShaileshMM.local>
Co-authored-by: George Pickett <gpickett00@gmail.com>
2026-02-05 17:50:57 -08:00
cpojer
328b69be17 chore: Fix audit test on Windows. 2026-02-06 10:22:48 +09:00
cpojer
f16e32b73d fix: Do not process.exit(0) in the middle of a test. 2026-02-06 09:57:51 +09:00
cpojer
8abce8a84d fix: onToolResult fallback is not expected. 2026-02-06 09:55:56 +09:00
therealZpoint-bot
c448e5da6f fix(docs): correct OpenCode Zen description in code comment (#9998)
* fix(docs): correct OpenCode Zen description in code comment

OpenCode Zen is a pay-as-you-go token-based API, not a $200/month
subscription. The subscription tiers ($20/$100/$200) are OpenCode Black,
a separate product.

This fixes the misleading comment that conflated Zen with Black.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: align OpenCode Zen billing copy (#9998) (thanks @therealZpoint-bot)

---------

Co-authored-by: Claude <claude@archibald.local>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com>
2026-02-05 19:55:02 -05:00
ideoutrea
7af00f040a Optimize import 2026-02-05 14:53:38 +08:00
ideoutrea
4d30f97407 Fix key resolve 2026-02-05 14:40:56 +08:00
ideoutrea
ff948a6dd7 Optimize doc 2026-02-05 14:04:23 +08:00
ideoutrea
ad759c9446 Optimize format 2026-02-05 13:50:09 +08:00
ide-rea
9ccbd57016 Merge branch 'openclaw:main' into qianfan 2026-02-05 13:36:44 +08:00
ideoutrea
52c9d3480f Add auth choice 2026-02-05 13:35:35 +08:00
ide-rea
517a8eafe5 Merge branch 'openclaw:main' into qianfan 2026-02-05 12:43:21 +08:00
ideoutrea
c8e67ad5d5 Fix import error 2026-02-05 12:39:38 +08:00
ideoutrea
fb5280e1b5 optimize doc 2026-02-04 22:57:34 +08:00
ide-rea
009abd306a Merge branch 'main' into qianfan 2026-02-04 22:39:13 +08:00
ideoutrea
8c53dfb74f Optimize doc 2026-02-04 22:30:42 +08:00
ideoutrea
7bf4080608 Fix format 2026-02-04 22:27:51 +08:00
ideoutrea
1de05ad068 Add baidu qianfan model provider 2026-02-04 22:27:49 +08:00
ideoutrea
30ac80b96b Add baidu qianfan model provider 2026-02-04 16:36:37 +08:00
361 changed files with 20315 additions and 3100 deletions

View File

@@ -0,0 +1,69 @@
name: Discord Notify
description: Send notifications to Discord webhook
inputs:
webhook_url:
description: Discord webhook URL
required: true
title:
description: Notification title
required: true
description:
description: Notification description
required: true
color:
description: Embed color (decimal)
required: false
default: "3447003"
username:
description: Bot username
required: false
default: "OpenClaw CI"
avatar_url:
description: Bot avatar URL
required: false
default: "https://avatars.githubusercontent.com/u/182880377"
timestamp:
description: Include timestamp
required: false
default: "true"
fields:
description: JSON array of embed fields
required: false
default: "[]"
runs:
using: composite
steps:
- name: Send Discord notification
shell: bash
run: |
TIMESTAMP=""
if [ "${{ inputs.timestamp }}" = "true" ]; then
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
fi
# Build JSON payload with jq to handle escaping properly
PAYLOAD=$(jq -n \
--arg username "${{ inputs.username }}" \
--arg avatar_url "${{ inputs.avatar_url }}" \
--arg title "${{ inputs.title }}" \
--arg description "${{ inputs.description }}" \
--argjson color "${{ inputs.color }}" \
--argjson fields '${{ inputs.fields }}' \
--arg timestamp "$TIMESTAMP" \
--argjson add_timestamp "${{ inputs.timestamp == 'true' }}" \
'{
username: $username,
avatar_url: $avatar_url,
embeds: [{
title: $title,
description: $description,
color: $color,
fields: $fields
} + (if $add_timestamp then {timestamp: $timestamp} else {} end)]
}')
curl -sS -H "Content-Type: application/json" \
-d "$PAYLOAD" \
"${{ inputs.webhook_url }}"

View File

@@ -2,8 +2,13 @@ name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
jobs:
install-check:
runs-on: blacksmith-4vcpu-ubuntu-2404
@@ -185,7 +190,9 @@ jobs:
runs-on: blacksmith-4vcpu-windows-2025
env:
NODE_OPTIONS: --max-old-space-size=4096
CLAWDBOT_TEST_WORKERS: 1
# Keep total concurrency predictable on the 4 vCPU runner:
# `scripts/test-parallel.mjs` runs some vitest suites in parallel processes.
OPENCLAW_TEST_WORKERS: 2
defaults:
run:
shell: bash
@@ -208,6 +215,25 @@ jobs:
with:
submodules: false
- name: Try to exclude workspace from Windows Defender (best-effort)
shell: pwsh
run: |
$cmd = Get-Command Add-MpPreference -ErrorAction SilentlyContinue
if (-not $cmd) {
Write-Host "Add-MpPreference not available, skipping Defender exclusions."
exit 0
}
try {
# Defender sometimes intercepts process spawning (vitest workers). If this fails
# (eg hardened images), keep going and rely on worker limiting above.
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE" -ErrorAction Stop
Add-MpPreference -ExclusionProcess "node.exe" -ErrorAction Stop
Write-Host "Defender exclusions applied."
} catch {
Write-Warning "Failed to apply Defender exclusions, continuing. $($_.Exception.Message)"
}
- name: Checkout submodules (retry)
run: |
set -euo pipefail
@@ -269,15 +295,13 @@ jobs:
- name: Run ${{ matrix.task }} (${{ matrix.runtime }})
run: ${{ matrix.command }}
checks-macos:
# Consolidated macOS job: runs TS tests + Swift lint/build/test sequentially
# on a single runner. GitHub limits macOS concurrent jobs to 5 per org;
# running 4 separate jobs per PR (as before) starved the queue. One job
# per PR allows 5 PRs to run macOS checks simultaneously.
macos:
if: github.event_name == 'pull_request'
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
include:
- task: test
command: pnpm test
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -297,6 +321,7 @@ jobs:
done
exit 1
# --- Node/pnpm setup (for TS tests) ---
- name: Setup Node.js
uses: actions/setup-node@v4
with:
@@ -336,71 +361,20 @@ jobs:
pnpm -v
pnpm install --frozen-lockfile --ignore-scripts=false --config.engine-strict=false --config.enable-pre-post-scripts=true || pnpm install --frozen-lockfile --ignore-scripts=false --config.engine-strict=false --config.enable-pre-post-scripts=true
- name: Run ${{ matrix.task }}
# --- Run all checks sequentially (fast gates first) ---
- name: TS tests (macOS)
env:
NODE_OPTIONS: --max-old-space-size=4096
run: ${{ matrix.command }}
macos-app:
if: github.event_name == 'pull_request'
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
include:
- task: lint
command: |
swiftlint --config .swiftlint.yml
swiftformat --lint apps/macos/Sources --config .swiftformat
- task: build
command: |
set -euo pipefail
for attempt in 1 2 3; do
if swift build --package-path apps/macos --configuration release; then
exit 0
fi
echo "swift build failed (attempt $attempt/3). Retrying…"
sleep $((attempt * 20))
done
exit 1
- task: test
command: |
set -euo pipefail
for attempt in 1 2 3; do
if swift test --package-path apps/macos --parallel --enable-code-coverage --show-codecov-path; then
exit 0
fi
echo "swift test failed (attempt $attempt/3). Retrying…"
sleep $((attempt * 20))
done
exit 1
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: false
- name: Checkout submodules (retry)
run: |
set -euo pipefail
git submodule sync --recursive
for attempt in 1 2 3 4 5; do
if git -c protocol.version=2 submodule update --init --force --depth=1 --recursive; then
exit 0
fi
echo "Submodule update failed (attempt $attempt/5). Retrying…"
sleep $((attempt * 10))
done
exit 1
run: pnpm test
# --- Xcode/Swift setup ---
- name: Select Xcode 26.1
run: |
sudo xcode-select -s /Applications/Xcode_26.1.app
xcodebuild -version
- name: Install XcodeGen / SwiftLint / SwiftFormat
run: |
brew install xcodegen swiftlint swiftformat
run: brew install xcodegen swiftlint swiftformat
- name: Show toolchain
run: |
@@ -408,8 +382,35 @@ jobs:
xcodebuild -version
swift --version
- name: Run ${{ matrix.task }}
run: ${{ matrix.command }}
- name: Swift lint
run: |
swiftlint --config .swiftlint.yml
swiftformat --lint apps/macos/Sources --config .swiftformat
- name: Swift build (release)
run: |
set -euo pipefail
for attempt in 1 2 3; do
if swift build --package-path apps/macos --configuration release; then
exit 0
fi
echo "swift build failed (attempt $attempt/3). Retrying…"
sleep $((attempt * 20))
done
exit 1
- name: Swift test
run: |
set -euo pipefail
for attempt in 1 2 3; do
if swift test --package-path apps/macos --parallel --enable-code-coverage --show-codecov-path; then
exit 0
fi
echo "swift test failed (attempt $attempt/3). Retrying…"
sleep $((attempt * 20))
done
exit 1
ios:
if: false # ignore iOS in CI for now
runs-on: macos-latest

View File

@@ -0,0 +1,349 @@
name: Deployment Strategy
# Reusable deployment workflow for staged releases
#
# Deployment targets by stage:
# - alpha: npm @alpha tag only
# - beta: npm @beta tag + Docker (ghcr.io) beta tag
# - stable: npm @latest + Docker latest + multi-arch manifest
on:
workflow_call:
inputs:
deployment_stage:
description: "Deployment stage: alpha, beta, or stable"
required: true
type: string
app_version:
description: "Version of the application to deploy"
required: true
type: string
source_branch:
description: "Source branch for deployment"
required: true
type: string
outputs:
deployment_status:
description: "Status of the deployment"
value: ${{ jobs.deploy-summary.outputs.status }}
npm_url:
description: "npm package URL"
value: ${{ jobs.deploy-summary.outputs.npm_url }}
docker_url:
description: "Docker image URL"
value: ${{ jobs.deploy-summary.outputs.docker_url }}
secrets:
NPM_TOKEN:
required: false
DISCORD_WEBHOOK_URL:
required: false
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# npm publish (all stages)
npm-publish:
name: npm Publish (${{ inputs.deployment_stage }})
runs-on: blacksmith-4vcpu-ubuntu-2404
outputs:
status: ${{ steps.publish.outputs.status }}
npm_url: ${{ steps.publish.outputs.npm_url }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.source_branch }}
submodules: false
- name: Checkout submodules (retry)
run: |
set -euo pipefail
git submodule sync --recursive
for attempt in 1 2 3 4 5; do
if git -c protocol.version=2 submodule update --init --force --depth=1 --recursive; then
exit 0
fi
echo "Submodule update failed (attempt $attempt/5). Retrying…"
sleep $((attempt * 10))
done
exit 1
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22.x
registry-url: "https://registry.npmjs.org"
- name: Setup pnpm (corepack retry)
run: |
set -euo pipefail
corepack enable
for attempt in 1 2 3; do
if corepack prepare pnpm@10.23.0 --activate; then
pnpm -v
exit 0
fi
echo "corepack prepare failed (attempt $attempt/3). Retrying..."
sleep $((attempt * 10))
done
exit 1
- name: Install dependencies
run: pnpm install --frozen-lockfile --ignore-scripts=false --config.engine-strict=false --config.enable-pre-post-scripts=true
- name: Build
run: pnpm build
- name: Determine npm tag
id: npm-tag
run: |
case "${{ inputs.deployment_stage }}" in
alpha)
echo "tag=alpha" >> $GITHUB_OUTPUT
;;
beta)
echo "tag=beta" >> $GITHUB_OUTPUT
;;
stable)
echo "tag=latest" >> $GITHUB_OUTPUT
;;
esac
- name: Publish to npm
id: publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
if [ -z "$NODE_AUTH_TOKEN" ]; then
echo "NPM_TOKEN not set, skipping publish"
echo "status=skipped" >> $GITHUB_OUTPUT
echo "npm_url=" >> $GITHUB_OUTPUT
exit 0
fi
NPM_TAG="${{ steps.npm-tag.outputs.tag }}"
if npm publish --tag "$NPM_TAG" --access public; then
echo "status=success" >> $GITHUB_OUTPUT
echo "npm_url=https://www.npmjs.com/package/openclaw/v/${{ inputs.app_version }}" >> $GITHUB_OUTPUT
else
echo "status=failed" >> $GITHUB_OUTPUT
echo "npm_url=" >> $GITHUB_OUTPUT
exit 1
fi
# Docker build - amd64 (beta+ only)
docker-amd64:
name: Docker amd64 (${{ inputs.deployment_stage }})
if: inputs.deployment_stage != 'alpha'
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.source_branch }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ inputs.app_version }}-amd64
type=raw,value=${{ inputs.deployment_stage }}-amd64
- name: Build and push amd64
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: false
push: true
# Docker build - arm64 (beta+ only)
docker-arm64:
name: Docker arm64 (${{ inputs.deployment_stage }})
if: inputs.deployment_stage != 'alpha'
runs-on: ubuntu-24.04-arm
permissions:
packages: write
contents: read
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.source_branch }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ inputs.app_version }}-arm64
type=raw,value=${{ inputs.deployment_stage }}-arm64
- name: Build and push arm64
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/arm64
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: false
push: true
# Create multi-arch manifest (beta+ only)
docker-manifest:
name: Docker Manifest (${{ inputs.deployment_stage }})
if: inputs.deployment_stage != 'alpha'
runs-on: ubuntu-latest
needs: [docker-amd64, docker-arm64]
permissions:
packages: write
contents: read
outputs:
docker_url: ${{ steps.manifest.outputs.docker_url }}
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push manifest
id: manifest
run: |
STAGE="${{ inputs.deployment_stage }}"
VERSION="${{ inputs.app_version }}"
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
# Create version manifest
docker buildx imagetools create \
-t "${IMAGE}:${VERSION}" \
"${IMAGE}:${VERSION}-amd64" \
"${IMAGE}:${VERSION}-arm64"
# Create stage manifest (beta or latest)
if [ "$STAGE" = "stable" ]; then
docker buildx imagetools create \
-t "${IMAGE}:latest" \
"${IMAGE}:${VERSION}-amd64" \
"${IMAGE}:${VERSION}-arm64"
echo "docker_url=${IMAGE}:latest" >> $GITHUB_OUTPUT
else
docker buildx imagetools create \
-t "${IMAGE}:${STAGE}" \
"${IMAGE}:${VERSION}-amd64" \
"${IMAGE}:${VERSION}-arm64"
echo "docker_url=${IMAGE}:${STAGE}" >> $GITHUB_OUTPUT
fi
# Deployment summary
deploy-summary:
name: Deployment Summary
runs-on: ubuntu-latest
needs: [npm-publish, docker-manifest]
if: "!cancelled()"
outputs:
status: ${{ steps.summary.outputs.status }}
npm_url: ${{ steps.summary.outputs.npm_url }}
docker_url: ${{ steps.summary.outputs.docker_url }}
steps:
- name: Summarize deployment
id: summary
run: |
NPM_STATUS="${{ needs.npm-publish.outputs.status || 'skipped' }}"
NPM_URL="${{ needs.npm-publish.outputs.npm_url }}"
DOCKER_URL="${{ needs.docker-manifest.outputs.docker_url || '' }}"
echo "npm_url=$NPM_URL" >> $GITHUB_OUTPUT
echo "docker_url=$DOCKER_URL" >> $GITHUB_OUTPUT
if [ "$NPM_STATUS" = "success" ] || [ "$NPM_STATUS" = "skipped" ]; then
echo "status=success" >> $GITHUB_OUTPUT
else
echo "status=failed" >> $GITHUB_OUTPUT
fi
# Generate summary
echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Stage | ${{ inputs.deployment_stage }} |" >> $GITHUB_STEP_SUMMARY
echo "| Version | ${{ inputs.app_version }} |" >> $GITHUB_STEP_SUMMARY
echo "| npm | $NPM_STATUS |" >> $GITHUB_STEP_SUMMARY
echo "| Docker | ${{ needs.docker-manifest.result || 'skipped' }} |" >> $GITHUB_STEP_SUMMARY
# Discord notification
notify:
name: Discord Notification
needs: deploy-summary
if: "!cancelled()"
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discord success notification
if: ${{ env.DISCORD_WEBHOOK_URL != '' && needs.deploy-summary.outputs.status == 'success' }}
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: "🚀 Deployed: ${{ inputs.deployment_stage }} v${{ inputs.app_version }}"
description: |
**npm**: ${{ needs.deploy-summary.outputs.npm_url || 'skipped' }}
**Docker**: ${{ needs.deploy-summary.outputs.docker_url || 'skipped' }}
color: "3066993"
- name: Discord failure notification
if: ${{ env.DISCORD_WEBHOOK_URL != '' && needs.deploy-summary.outputs.status != 'success' }}
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: "❌ Deployment Failed: ${{ inputs.deployment_stage }}"
description: |
**Version**: ${{ inputs.app_version }}
[View Logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
color: "15158332"

97
.github/workflows/feature-pr.yml vendored Normal file
View File

@@ -0,0 +1,97 @@
name: Feature PR
# Auto-create PR from dev/* branches to develop
# This is the entry point for new features into the staging pipeline
# NOTE: push triggers disabled until staging pipeline is activated.
# To enable: uncomment the push block and remove workflow_dispatch.
# push:
# branches:
# - "dev/**"
# - "feature/**"
# - "fix/**"
on:
workflow_dispatch:
concurrency:
group: feature-pr-${{ github.ref_name }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
jobs:
create-pr:
name: Create PR to develop
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Ensure develop branch exists
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if git ls-remote --heads origin develop | grep -q develop; then
echo "develop branch already exists"
else
echo "develop branch does not exist — creating from main"
git push origin origin/main:refs/heads/develop
fi
- name: Check for existing PR
id: check-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH="${{ github.ref_name }}"
TARGET="develop"
# Check if PR already exists
EXISTING=$(gh pr list --head "$BRANCH" --base "$TARGET" --json number --jq '.[0].number // empty')
if [ -n "$EXISTING" ]; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "pr_number=$EXISTING" >> $GITHUB_OUTPUT
echo "PR #$EXISTING already exists for $BRANCH → $TARGET"
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Create PR
if: steps.check-pr.outputs.exists != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH="${{ github.ref_name }}"
TARGET="develop"
# Extract title from branch name (dev/foo-bar → foo bar)
TITLE=$(echo "$BRANCH" | sed 's|^dev/||; s|^feature/||; s|^fix/||; s|-| |g; s|_| |g')
# Capitalize first letter
TITLE="$(echo "${TITLE:0:1}" | tr '[:lower:]' '[:upper:]')${TITLE:1}"
# Create PR body
BODY=$(cat << 'PRBODY'
Auto-created PR from feature branch.
## Changes
<!-- Describe your changes here -->
---
*This PR was auto-created by the feature-pr workflow.*
PRBODY
)
gh pr create \
--base "$TARGET" \
--head "$BRANCH" \
--title "$TITLE" \
--body "$BODY"
echo "Created PR: $BRANCH → $TARGET"

View File

@@ -3,6 +3,10 @@ name: Formal models (informational conformance)
on:
pull_request:
concurrency:
group: formal-conformance-${{ github.event.pull_request.number || github.ref_name }}
cancel-in-progress: true
jobs:
formal_conformance:
runs-on: ubuntu-latest

129
.github/workflows/generate-changelog.yml vendored Normal file
View File

@@ -0,0 +1,129 @@
name: Generate Changelog
on:
workflow_call:
inputs:
version:
description: "Version for the changelog"
required: true
type: string
release_type:
description: "Release type: alpha, beta, or stable"
required: true
type: string
outputs:
changelog:
description: "Generated changelog content"
value: ${{ jobs.generate.outputs.changelog }}
changelog_file:
description: "Path to changelog file"
value: ${{ jobs.generate.outputs.changelog_file }}
jobs:
generate:
name: Generate Changelog
runs-on: ubuntu-latest
outputs:
changelog: ${{ steps.generate.outputs.changelog }}
changelog_file: ${{ steps.generate.outputs.changelog_file }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate changelog
id: generate
run: |
VERSION="${{ inputs.version }}"
RELEASE_TYPE="${{ inputs.release_type }}"
DATE=$(date +%Y-%m-%d)
# Start building changelog
CHANGELOG="## v${VERSION} (${DATE})\n\n"
# Initialize sections
FEATURES=""
FIXES=""
DOCS=""
CHORES=""
OTHER=""
# Get commits since last tag
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -n "$LATEST_TAG" ]; then
COMMITS=$(git log ${LATEST_TAG}..HEAD --oneline --format="%s")
else
COMMITS=$(git log --oneline --format="%s" | head -50)
fi
# Categorize commits by conventional commit type
while IFS= read -r commit; do
if [ -z "$commit" ]; then
continue
fi
# Extract type from conventional commit
if [[ "$commit" =~ ^feat(\(.+\))?:\ (.+)$ ]]; then
FEATURES="${FEATURES}- ${BASH_REMATCH[2]}\n"
elif [[ "$commit" =~ ^fix(\(.+\))?:\ (.+)$ ]]; then
FIXES="${FIXES}- ${BASH_REMATCH[2]}\n"
elif [[ "$commit" =~ ^docs(\(.+\))?:\ (.+)$ ]]; then
DOCS="${DOCS}- ${BASH_REMATCH[2]}\n"
elif [[ "$commit" =~ ^chore(\(.+\))?:\ (.+)$ ]]; then
CHORES="${CHORES}- ${BASH_REMATCH[2]}\n"
elif [[ "$commit" =~ ^refactor(\(.+\))?:\ (.+)$ ]]; then
CHORES="${CHORES}- ${BASH_REMATCH[2]}\n"
elif [[ "$commit" =~ ^test(\(.+\))?:\ (.+)$ ]]; then
CHORES="${CHORES}- ${BASH_REMATCH[2]}\n"
elif [[ "$commit" =~ ^ci(\(.+\))?:\ (.+)$ ]]; then
CHORES="${CHORES}- ${BASH_REMATCH[2]}\n"
else
# Non-conventional commit, add to other
OTHER="${OTHER}- ${commit}\n"
fi
done <<< "$COMMITS"
# Build final changelog
if [ -n "$FEATURES" ]; then
CHANGELOG="${CHANGELOG}### ✨ Features\n\n${FEATURES}\n"
fi
if [ -n "$FIXES" ]; then
CHANGELOG="${CHANGELOG}### 🐛 Bug Fixes\n\n${FIXES}\n"
fi
if [ -n "$DOCS" ]; then
CHANGELOG="${CHANGELOG}### 📚 Documentation\n\n${DOCS}\n"
fi
if [ -n "$CHORES" ]; then
CHANGELOG="${CHANGELOG}### 🔧 Maintenance\n\n${CHORES}\n"
fi
if [ -n "$OTHER" ]; then
CHANGELOG="${CHANGELOG}### Other Changes\n\n${OTHER}\n"
fi
# If no categorized commits, add a simple message
if [ -z "$FEATURES" ] && [ -z "$FIXES" ] && [ -z "$DOCS" ] && [ -z "$CHORES" ] && [ -z "$OTHER" ]; then
CHANGELOG="${CHANGELOG}No notable changes in this release.\n"
fi
# Add release metadata
CHANGELOG="${CHANGELOG}\n---\n\n"
CHANGELOG="${CHANGELOG}**Release Type**: ${RELEASE_TYPE}\n"
CHANGELOG="${CHANGELOG}**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LATEST_TAG:-initial}...v${VERSION}\n"
# Escape for multiline output (random delimiter prevents collision with commit messages)
DELIMITER="CHANGELOG_$(openssl rand -hex 16)"
echo "changelog<<${DELIMITER}" >> $GITHUB_OUTPUT
echo -e "$CHANGELOG" >> $GITHUB_OUTPUT
echo "${DELIMITER}" >> $GITHUB_OUTPUT
echo "changelog_file=CHANGELOG.md" >> $GITHUB_OUTPUT
# Also write to step summary
echo "## Generated Changelog" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo -e "$CHANGELOG" >> $GITHUB_STEP_SUMMARY

96
.github/workflows/hotfix-pr.yml vendored Normal file
View File

@@ -0,0 +1,96 @@
name: Hotfix PR
# Emergency hotfix workflow - bypasses staging pipeline
# Use for critical security fixes or production-breaking bugs only
#
# Flow: hotfix/* → main (directly, with expedited review)
# NOTE: push triggers disabled until staging pipeline is activated.
# To enable: uncomment the push block and remove workflow_dispatch.
# push:
# branches:
# - "hotfix/**"
on:
workflow_dispatch:
concurrency:
group: hotfix-${{ github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
jobs:
create-pr:
name: Create Hotfix PR
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for existing PR
id: check-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH="${{ github.ref_name }}"
EXISTING=$(gh pr list --head "$BRANCH" --base main --json number --jq '.[0].number // empty')
if [ -n "$EXISTING" ]; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "pr_number=$EXISTING" >> $GITHUB_OUTPUT
echo "Hotfix PR #$EXISTING already exists"
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Create Hotfix PR
if: steps.check-pr.outputs.exists != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH="${{ github.ref_name }}"
# Extract title from branch name
TITLE=$(echo "$BRANCH" | sed 's|^hotfix/||; s|-| |g; s|_| |g')
TITLE="🚨 HOTFIX: $(echo "${TITLE:0:1}" | tr '[:lower:]' '[:upper:]')${TITLE:1}"
# Create PR body
BODY=$(cat << 'PRBODY'
## 🚨 Emergency Hotfix
**This PR bypasses the normal staging pipeline.**
### What's broken?
<!-- Describe the production issue -->
### Root cause
<!-- Brief explanation of what went wrong -->
### Fix
<!-- What this hotfix does -->
### Verification
- [ ] Tested locally
- [ ] Reviewed by at least one other maintainer
- [ ] Post-merge monitoring plan in place
---
⚠️ **After merging:** Cherry-pick this fix to `develop`, `alpha`, and `beta` branches to keep them in sync.
*This PR was auto-created by the hotfix-pr workflow.*
PRBODY
)
gh pr create \
--base main \
--head "$BRANCH" \
--title "$TITLE" \
--label "hotfix,priority:critical" \
--body "$BODY"
echo "Created hotfix PR: $BRANCH → main"

View File

@@ -6,6 +6,10 @@ on:
pull_request:
workflow_dispatch:
concurrency:
group: install-smoke-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
jobs:
install-smoke:
runs-on: ubuntu-latest

321
.github/workflows/promote-branch.yml vendored Normal file
View File

@@ -0,0 +1,321 @@
name: Promote Branch
# Staged branch promotion for openclaw:
#
# develop → alpha → beta → main
#
# - External contributors: target `develop`
# - develop → alpha: auto-creates PR after core checks pass
# - alpha → beta: auto-creates PR after alpha tests pass (+ secrets scan)
# - beta → main: auto-creates PR after full tests pass (+ Windows)
#
# Merging to main triggers a release (handled separately by release workflow)
# NOTE: push triggers disabled until staging pipeline is activated.
# To enable: uncomment the push block below.
# push:
# branches:
# - develop
# - alpha
# - beta
# paths-ignore:
# - "docs/**"
# - "*.md"
on:
workflow_dispatch:
inputs:
source_branch:
description: "Source branch to promote from"
required: true
type: choice
options:
- develop
- alpha
- beta
skip_tests:
description: "Skip tests (use with caution)"
required: false
type: boolean
default: false
concurrency:
group: promote-${{ github.ref_name }}
cancel-in-progress: false
permissions:
contents: write
pull-requests: write
jobs:
# Determine promotion target
determine-target:
name: Determine Target Branch
runs-on: ubuntu-latest
outputs:
source: ${{ steps.determine.outputs.source }}
target: ${{ steps.determine.outputs.target }}
test_stage: ${{ steps.determine.outputs.test_stage }}
should_promote: ${{ steps.determine.outputs.should_promote }}
steps:
- name: Determine promotion target
id: determine
run: |
# Get source branch
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
SOURCE="${{ inputs.source_branch }}"
else
SOURCE="${{ github.ref_name }}"
fi
echo "source=$SOURCE" >> $GITHUB_OUTPUT
case "$SOURCE" in
develop)
echo "target=alpha" >> $GITHUB_OUTPUT
echo "test_stage=develop" >> $GITHUB_OUTPUT
echo "should_promote=true" >> $GITHUB_OUTPUT
;;
alpha)
echo "target=beta" >> $GITHUB_OUTPUT
echo "test_stage=alpha" >> $GITHUB_OUTPUT
echo "should_promote=true" >> $GITHUB_OUTPUT
;;
beta)
echo "target=main" >> $GITHUB_OUTPUT
echo "test_stage=beta" >> $GITHUB_OUTPUT
echo "should_promote=true" >> $GITHUB_OUTPUT
;;
*)
echo "target=" >> $GITHUB_OUTPUT
echo "test_stage=" >> $GITHUB_OUTPUT
echo "should_promote=false" >> $GITHUB_OUTPUT
;;
esac
# Ensure target branch exists (create from main if not)
ensure-target-branch:
name: Ensure Target Branch
needs: determine-target
if: needs.determine-target.outputs.should_promote == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create target branch if missing
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TARGET="${{ needs.determine-target.outputs.target }}"
if git ls-remote --exit-code origin "refs/heads/$TARGET" >/dev/null 2>&1; then
echo "Branch '$TARGET' already exists"
else
echo "Branch '$TARGET' does not exist — creating from main"
git push origin "origin/main:refs/heads/$TARGET"
fi
# Run stage-appropriate tests
run-tests:
name: Run Tests
needs: [determine-target, ensure-target-branch]
if: ${{ needs.determine-target.outputs.should_promote == 'true' && (github.event_name != 'workflow_dispatch' || !inputs.skip_tests) }}
uses: ./.github/workflows/testing-strategy.yml
with:
test_stage: ${{ needs.determine-target.outputs.test_stage }}
app_version: ${{ github.sha }}
secrets: inherit
# Create promotion PR
create-promotion-pr:
name: Create Promotion PR
needs: [determine-target, ensure-target-branch, run-tests]
if: |
!cancelled() &&
needs.determine-target.outputs.should_promote == 'true' &&
(needs.run-tests.outputs.test_status == 'passed' || (github.event_name == 'workflow_dispatch' && inputs.skip_tests))
runs-on: ubuntu-latest
outputs:
pr_number: ${{ steps.output-pr.outputs.pull-request-number }}
pr_url: ${{ steps.output-pr.outputs.pull-request-url }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ needs.determine-target.outputs.source }}
fetch-depth: 0
- name: Get commit info
id: commits
run: |
TARGET="${{ needs.determine-target.outputs.target }}"
# Fetch target branch
git fetch origin $TARGET 2>/dev/null || true
# Get commits not in target
if git rev-parse origin/$TARGET >/dev/null 2>&1; then
COMMIT_COUNT=$(git rev-list --count origin/$TARGET..HEAD 2>/dev/null || echo "0")
COMMIT_SUMMARY=$(git log origin/$TARGET..HEAD --oneline --format="- %s (%h)" 2>/dev/null | head -20 || echo "Initial promotion")
else
COMMIT_COUNT=$(git rev-list --count HEAD 2>/dev/null || echo "0")
COMMIT_SUMMARY=$(git log --oneline --format="- %s (%h)" 2>/dev/null | head -20 || echo "Initial promotion")
fi
echo "count=$COMMIT_COUNT" >> $GITHUB_OUTPUT
DELIM="COMMITS_$(openssl rand -hex 16)"
echo "summary<<${DELIM}" >> $GITHUB_OUTPUT
echo "$COMMIT_SUMMARY" >> $GITHUB_OUTPUT
echo "${DELIM}" >> $GITHUB_OUTPUT
- name: Check for existing PR
id: check-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
SOURCE="${{ needs.determine-target.outputs.source }}"
TARGET="${{ needs.determine-target.outputs.target }}"
EXISTING=$(gh pr list --head "$SOURCE" --base "$TARGET" --json number --jq '.[0].number // empty')
if [ -n "$EXISTING" ]; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "pr_number=$EXISTING" >> $GITHUB_OUTPUT
echo "pr_url=https://github.com/${{ github.repository }}/pull/$EXISTING" >> $GITHUB_OUTPUT
echo "Promotion PR #$EXISTING already exists for $SOURCE → $TARGET"
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Create Pull Request
id: create-pr
if: steps.check-pr.outputs.exists != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
SOURCE="${{ needs.determine-target.outputs.source }}"
TARGET="${{ needs.determine-target.outputs.target }}"
TEST_STAGE="${{ needs.determine-target.outputs.test_stage }}"
COMMIT_COUNT="${{ steps.commits.outputs.count }}"
# Write PR body to a temp file to avoid shell quoting issues
BODY_FILE=$(mktemp)
cat > "$BODY_FILE" <<__PRBODY__
## Staged Promotion
| Property | Value |
|----------|-------|
| Source | \`${SOURCE}\` |
| Target | \`${TARGET}\` |
| Test Stage | \`${TEST_STAGE}\` |
### Changes (${COMMIT_COUNT} commits)
${{ steps.commits.outputs.summary }}
### Checklist
- [ ] Changes reviewed
- [ ] CI passing
- [ ] Ready to promote
---
*Auto-generated by the branch promotion workflow.*
__PRBODY__
PR_URL=$(gh pr create \
--base "$TARGET" \
--head "$SOURCE" \
--title "🚀 Promote: $SOURCE → $TARGET" \
--body-file "$BODY_FILE" \
--label "promotion")
rm -f "$BODY_FILE"
PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$')
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
echo "Created promotion PR: $SOURCE → $TARGET"
- name: Output existing PR
id: output-pr
run: |
if [ "${{ steps.check-pr.outputs.exists }}" = "true" ]; then
echo "pull-request-number=${{ steps.check-pr.outputs.pr_number }}" >> $GITHUB_OUTPUT
echo "pull-request-url=${{ steps.check-pr.outputs.pr_url }}" >> $GITHUB_OUTPUT
else
echo "pull-request-number=${{ steps.create-pr.outputs.pr_number }}" >> $GITHUB_OUTPUT
echo "pull-request-url=${{ steps.create-pr.outputs.pr_url }}" >> $GITHUB_OUTPUT
fi
# Auto-merge for develop → alpha (fast-track, new PRs only)
auto-merge:
name: Auto-merge (develop → alpha)
needs: [determine-target, create-promotion-pr]
if: |
needs.determine-target.outputs.source == 'develop' &&
needs.create-promotion-pr.outputs.pr_number != '' &&
needs.create-promotion-pr.result == 'success'
runs-on: ubuntu-latest
steps:
- name: Enable auto-merge
run: |
gh pr merge ${{ needs.create-promotion-pr.outputs.pr_number }} \
--auto \
--squash \
--repo ${{ github.repository }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Notify about promotion
notify-promotion:
name: Notify Promotion
needs: [determine-target, create-promotion-pr]
if: "!cancelled() && needs.create-promotion-pr.outputs.pr_url != ''"
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discord notification
if: env.DISCORD_WEBHOOK_URL != ''
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: "🔄 Promotion PR: ${{ needs.determine-target.outputs.source }} → ${{ needs.determine-target.outputs.target }}"
description: |
**PR**: ${{ needs.create-promotion-pr.outputs.pr_url }}
**Stage**: ${{ needs.determine-target.outputs.test_stage }}
color: "3447003"
# Handle failed tests
notify-failure:
name: Notify Test Failure
needs: [determine-target, run-tests]
if: |
!cancelled() &&
needs.run-tests.outputs.test_status != 'passed' &&
!inputs.skip_tests
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discord notification
if: env.DISCORD_WEBHOOK_URL != ''
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: "❌ Promotion Blocked: ${{ needs.determine-target.outputs.source }}"
description: |
**Target**: ${{ needs.determine-target.outputs.target }}
**Reason**: Tests failed
[View Logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
color: "15158332"

View File

@@ -0,0 +1,265 @@
name: Release Orchestrator
# Orchestrates staged releases for openclaw
#
# This workflow is called when code is promoted to main (stable release)
# or can be triggered manually for alpha/beta releases from their branches.
#
# Flow: version → changelog → test → deploy → release
# NOTE: push-to-main trigger disabled until staging pipeline is activated.
# To enable: uncomment the push block below.
# push:
# branches:
# - main
# paths-ignore:
# - "docs/**"
# - "*.md"
# - ".github/workflows/docs-*.yml"
on:
workflow_call:
inputs:
release_type:
description: "Release type: alpha, beta, or stable"
required: true
type: string
source_branch:
description: "Source branch for the release"
required: true
type: string
dry_run:
description: "Perform a dry run without publishing"
required: false
type: boolean
default: false
outputs:
version:
description: "The released version"
value: ${{ jobs.version.outputs.new_version }}
release_url:
description: "URL to the GitHub release"
value: ${{ jobs.release.outputs.release_url }}
status:
description: "Release status"
value: ${{ jobs.release.outputs.status }}
secrets:
NPM_TOKEN:
required: false
DISCORD_WEBHOOK_URL:
required: false
concurrency:
group: release-${{ github.ref_name }}
cancel-in-progress: false
permissions:
contents: write
packages: write
jobs:
# Determine release parameters (push vs workflow_call)
determine-params:
name: Determine Parameters
runs-on: ubuntu-latest
outputs:
release_type: ${{ steps.params.outputs.release_type }}
source_branch: ${{ steps.params.outputs.source_branch }}
dry_run: ${{ steps.params.outputs.dry_run }}
steps:
- name: Set parameters
id: params
run: |
# When triggered by push to main, use stable defaults
if [ "${{ github.event_name }}" = "push" ]; then
echo "release_type=stable" >> $GITHUB_OUTPUT
echo "source_branch=main" >> $GITHUB_OUTPUT
echo "dry_run=false" >> $GITHUB_OUTPUT
else
# workflow_call - use provided inputs
echo "release_type=${{ inputs.release_type }}" >> $GITHUB_OUTPUT
echo "source_branch=${{ inputs.source_branch }}" >> $GITHUB_OUTPUT
echo "dry_run=${{ inputs.dry_run }}" >> $GITHUB_OUTPUT
fi
# Get commits since last release
get-commits:
name: Get Commits
needs: determine-params
runs-on: ubuntu-latest
outputs:
commits: ${{ steps.commits.outputs.commits }}
has_changes: ${{ steps.commits.outputs.has_changes }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.determine-params.outputs.source_branch }}
- name: Get commits since last tag
id: commits
run: |
# Get latest tag for this release type
case "${{ needs.determine-params.outputs.release_type }}" in
alpha)
PATTERN="v*-alpha.*"
;;
beta)
PATTERN="v*-beta.*"
;;
stable)
PATTERN="v[0-9]*.[0-9]*.[0-9]*"
;;
esac
# Filter out prerelease tags for stable (glob * matches -alpha/-beta suffixes)
if [ "${{ needs.determine-params.outputs.release_type }}" = "stable" ]; then
LATEST_TAG=$(git tag -l "$PATTERN" --sort=-v:refname | grep -v -E '-(alpha|beta)\.' | head -1)
else
LATEST_TAG=$(git tag -l "$PATTERN" --sort=-v:refname | head -1)
fi
if [ -z "$LATEST_TAG" ]; then
# No previous tag, use all commits
LATEST_TAG=$(git rev-list --max-parents=0 HEAD)
echo "No previous ${{ needs.determine-params.outputs.release_type }} tag found, using initial commit"
else
echo "Latest ${{ needs.determine-params.outputs.release_type }} tag: $LATEST_TAG"
fi
COMMITS=$(git log ${LATEST_TAG}..HEAD --oneline --format="- %s (%h)")
if [ -z "$COMMITS" ]; then
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "commits=" >> $GITHUB_OUTPUT
else
echo "has_changes=true" >> $GITHUB_OUTPUT
DELIM="COMMITS_$(openssl rand -hex 16)"
echo "commits<<${DELIM}" >> $GITHUB_OUTPUT
echo "$COMMITS" >> $GITHUB_OUTPUT
echo "${DELIM}" >> $GITHUB_OUTPUT
fi
# Version operations
version:
name: Version
needs: [determine-params, get-commits]
if: needs.get-commits.outputs.has_changes == 'true'
uses: ./.github/workflows/version-operations.yml
with:
release_type: ${{ needs.determine-params.outputs.release_type }}
source_branch: ${{ needs.determine-params.outputs.source_branch }}
should_bump: true
dry_run: ${{ needs.determine-params.outputs.dry_run }}
# Generate changelog
changelog:
name: Changelog
needs: [determine-params, get-commits, version]
if: needs.get-commits.outputs.has_changes == 'true'
uses: ./.github/workflows/generate-changelog.yml
with:
version: ${{ needs.version.outputs.new_version }}
release_type: ${{ needs.determine-params.outputs.release_type }}
# Run full test suite for the release type
test:
name: Test
needs: [determine-params, get-commits, version]
if: needs.get-commits.outputs.has_changes == 'true'
uses: ./.github/workflows/testing-strategy.yml
with:
test_stage: ${{ needs.determine-params.outputs.release_type }}
app_version: ${{ needs.version.outputs.new_version }}
secrets: inherit
# Deploy (npm + Docker)
deploy:
name: Deploy
needs: [determine-params, version, test]
if: ${{ needs.determine-params.outputs.dry_run != 'true' && needs.test.outputs.test_status == 'passed' }}
uses: ./.github/workflows/deployment-strategy.yml
with:
deployment_stage: ${{ needs.determine-params.outputs.release_type }}
app_version: ${{ needs.version.outputs.new_version }}
source_branch: ${{ needs.determine-params.outputs.source_branch }}
secrets: inherit
# Create GitHub release
release:
name: GitHub Release
needs: [determine-params, version, changelog, deploy]
if: ${{ needs.determine-params.outputs.dry_run != 'true' }}
runs-on: ubuntu-latest
outputs:
release_url: ${{ steps.create-release.outputs.html_url }}
status: ${{ steps.status.outputs.status }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ needs.determine-params.outputs.source_branch }}
- name: Create GitHub Release
id: create-release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.version.outputs.new_version }}
name: openclaw ${{ needs.version.outputs.new_version }}
body: ${{ needs.changelog.outputs.changelog }}
prerelease: ${{ needs.determine-params.outputs.release_type != 'stable' }}
draft: false
- name: Set status
id: status
run: echo "status=success" >> $GITHUB_OUTPUT
# Notify on success
notify-success:
name: Notify Success
needs: [determine-params, version, release]
if: ${{ !cancelled() && needs.release.result == 'success' }}
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discord notification
if: env.DISCORD_WEBHOOK_URL != ''
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: "🎉 Released: openclaw v${{ needs.version.outputs.new_version }}"
description: |
**Type**: ${{ needs.determine-params.outputs.release_type }}
**Release**: ${{ needs.release.outputs.release_url }}
color: "3066993"
# Notify on failure
notify-failure:
name: Notify Failure
needs: [determine-params, version, test, deploy, release]
if: |
!cancelled() &&
needs.version.result != 'skipped' &&
(needs.test.result == 'failure' || needs.deploy.result == 'failure' || needs.release.result == 'failure')
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discord notification
if: env.DISCORD_WEBHOOK_URL != ''
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: "❌ Release Failed: ${{ needs.determine-params.outputs.release_type }}"
description: |
**Branch**: ${{ needs.determine-params.outputs.source_branch }}
**Tests**: ${{ needs.test.outputs.test_status }}
[View Logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
color: "15158332"

51
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: Release
# Manual release workflow - triggers the release orchestrator
#
# Branch → Release Type mapping:
# alpha → releases from 'alpha' branch with -alpha.N suffix
# beta → releases from 'beta' branch with -beta.N suffix
# stable → releases from 'main' branch with YYYY.M.D version
on:
workflow_dispatch:
inputs:
release_type:
description: "Release type"
required: true
type: choice
options:
- alpha
- beta
- stable
default: "alpha"
dry_run:
description: "Dry run (no publish)"
required: false
type: boolean
default: false
jobs:
determine-branch:
runs-on: ubuntu-latest
outputs:
branch: ${{ steps.branch.outputs.name }}
steps:
- name: Determine source branch
id: branch
run: |
case "${{ inputs.release_type }}" in
alpha) echo "name=alpha" >> $GITHUB_OUTPUT ;;
beta) echo "name=beta" >> $GITHUB_OUTPUT ;;
stable) echo "name=main" >> $GITHUB_OUTPUT ;;
esac
release:
name: Release
needs: determine-branch
uses: ./.github/workflows/release-orchestrator.yml
with:
release_type: ${{ inputs.release_type }}
source_branch: ${{ needs.determine-branch.outputs.branch }}
dry_run: ${{ inputs.dry_run }}
secrets: inherit

256
.github/workflows/rollback.yml vendored Normal file
View File

@@ -0,0 +1,256 @@
name: Rollback
# Emergency rollback workflow
#
# Reverts npm + Docker to a previous known-good version.
# Does NOT revert git — the bad commits stay in history.
# Create a hotfix branch to fix forward after rolling back.
#
# What it does:
# 1. Re-tags the previous version as @latest / :latest on npm + Docker
# 2. Creates a GitHub release noting the rollback
# 3. Notifies Discord
#
# What it does NOT do:
# - Revert git commits (fix forward instead)
# - Remove the bad version from npm (use `npm unpublish` manually if needed)
on:
workflow_dispatch:
inputs:
rollback_to:
description: "Version to roll back to (e.g. 2026.2.5)"
required: true
type: string
reason:
description: "Reason for rollback"
required: true
type: string
rollback_npm:
description: "Roll back npm dist-tag"
required: false
type: boolean
default: true
rollback_docker:
description: "Roll back Docker :latest tag"
required: false
type: boolean
default: true
concurrency:
group: rollback
cancel-in-progress: false
permissions:
contents: write
packages: write
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Validate the target version exists
validate:
name: Validate Target Version
runs-on: ubuntu-latest
outputs:
tag_exists: ${{ steps.check.outputs.tag_exists }}
npm_exists: ${{ steps.check.outputs.npm_exists }}
docker_exists: ${{ steps.check.outputs.docker_exists }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate version
id: check
run: |
VERSION="${{ inputs.rollback_to }}"
# Check git tag
if git tag -l "v${VERSION}" | grep -q .; then
echo "tag_exists=true" >> $GITHUB_OUTPUT
echo "✅ Git tag v${VERSION} exists"
else
echo "tag_exists=false" >> $GITHUB_OUTPUT
echo "❌ Git tag v${VERSION} not found"
fi
# Check npm
if npm view "openclaw@${VERSION}" version 2>/dev/null | grep -q "${VERSION}"; then
echo "npm_exists=true" >> $GITHUB_OUTPUT
echo "✅ npm version ${VERSION} exists"
else
echo "npm_exists=false" >> $GITHUB_OUTPUT
echo "⚠️ npm version ${VERSION} not found (npm rollback will be skipped)"
fi
# Check Docker
if docker manifest inspect "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION}" >/dev/null 2>&1; then
echo "docker_exists=true" >> $GITHUB_OUTPUT
echo "✅ Docker image ${VERSION} exists"
else
echo "docker_exists=false" >> $GITHUB_OUTPUT
echo "⚠️ Docker image ${VERSION} not found (Docker rollback will be skipped)"
fi
- name: Fail if tag doesn't exist
if: steps.check.outputs.tag_exists != 'true'
run: |
echo "::error::Version v${{ inputs.rollback_to }} does not exist as a git tag"
exit 1
# Roll back npm dist-tag
rollback-npm:
name: Rollback npm
needs: validate
if: ${{ inputs.rollback_npm && needs.validate.outputs.npm_exists == 'true' }}
runs-on: ubuntu-latest
outputs:
status: ${{ steps.rollback.outputs.status }}
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22.x
registry-url: "https://registry.npmjs.org"
- name: Roll back npm @latest tag
id: rollback
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
VERSION="${{ inputs.rollback_to }}"
if [ -z "$NODE_AUTH_TOKEN" ]; then
echo "::warning::NPM_TOKEN not set, skipping npm rollback"
echo "status=skipped" >> $GITHUB_OUTPUT
exit 0
fi
# Move the @latest dist-tag to the rollback version
if npm dist-tag add "openclaw@${VERSION}" latest; then
echo "status=success" >> $GITHUB_OUTPUT
echo "✅ npm @latest now points to ${VERSION}"
# Show current dist-tags for verification
npm dist-tag ls openclaw
else
echo "status=failed" >> $GITHUB_OUTPUT
echo "::error::Failed to update npm dist-tag"
exit 1
fi
# Roll back Docker :latest tag
rollback-docker:
name: Rollback Docker
needs: validate
if: ${{ inputs.rollback_docker && needs.validate.outputs.docker_exists == 'true' }}
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
outputs:
status: ${{ steps.rollback.outputs.status }}
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Roll back Docker :latest tag
id: rollback
run: |
VERSION="${{ inputs.rollback_to }}"
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
# Re-tag the rollback version as :latest
if docker buildx imagetools create -t "${IMAGE}:latest" "${IMAGE}:${VERSION}"; then
echo "status=success" >> $GITHUB_OUTPUT
echo "✅ Docker :latest now points to ${VERSION}"
else
echo "status=failed" >> $GITHUB_OUTPUT
echo "::error::Failed to retag Docker image"
exit 1
fi
# Create rollback release note
create-rollback-release:
name: Create Rollback Release
needs: [validate, rollback-npm, rollback-docker]
if: "!cancelled() && needs.validate.result == 'success'"
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get current version
id: current
run: |
CURRENT=$(node -p "require('./package.json').version")
echo "version=$CURRENT" >> $GITHUB_OUTPUT
- name: Create rollback release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ inputs.rollback_to }}
name: "⚠️ Rollback to openclaw ${{ inputs.rollback_to }}"
body: |
## ⚠️ Rollback
| Property | Value |
|----------|-------|
| Rolled back from | `${{ steps.current.outputs.version }}` |
| Rolled back to | `${{ inputs.rollback_to }}` |
| Initiated by | @${{ github.actor }} |
### Reason
${{ inputs.reason }}
### Rollback Status
| Target | Status |
|--------|--------|
| npm @latest | ${{ needs.rollback-npm.outputs.status || 'skipped' }} |
| Docker :latest | ${{ needs.rollback-docker.outputs.status || 'skipped' }} |
### Next Steps
1. Investigate the issue in the rolled-back version
2. Create a `hotfix/*` branch with the fix
3. Merge via the hotfix workflow to restore forward progress
---
*This release was created by the rollback workflow.*
make_latest: false
prerelease: false
# Notify
notify:
name: Discord Notification
needs: [validate, rollback-npm, rollback-docker, create-rollback-release]
if: "!cancelled() && needs.validate.result == 'success'"
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discord notification
if: env.DISCORD_WEBHOOK_URL != ''
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: "⚠️ ROLLBACK: openclaw → v${{ inputs.rollback_to }}"
description: |
**Reason**: ${{ inputs.reason }}
**Initiated by**: @${{ github.actor }}
**npm**: ${{ needs.rollback-npm.outputs.status || 'skipped' }}
**Docker**: ${{ needs.rollback-docker.outputs.status || 'skipped' }}
color: "15105570"

153
.github/workflows/testing-strategy.yml vendored Normal file
View File

@@ -0,0 +1,153 @@
name: Testing Strategy
# Reusable testing workflow for staged releases
# Passes test_stage to ci.yml to control which platform tests run
#
# Progressive test coverage by stage:
# - develop/alpha: core checks + secrets + android
# - beta: + Windows tests
# - stable: + macOS tests, macOS app, install smoke
on:
workflow_call:
inputs:
test_stage:
description: "Testing stage: develop, alpha, beta, or stable"
required: true
type: string
app_version:
description: "Version of the application being tested"
required: false
type: string
default: "dev"
outputs:
test_status:
description: "Overall test status"
value: ${{ jobs.test-summary.outputs.overall_status }}
secrets:
DISCORD_WEBHOOK_URL:
required: false
jobs:
# Run CI with stage-appropriate platform gates
ci:
name: Core CI
uses: ./.github/workflows/ci.yml
with:
test_stage: ${{ inputs.test_stage }}
secrets: inherit
# Install smoke test (stable only)
install-smoke:
name: Install Smoke Test
if: inputs.test_stage == 'stable'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm (corepack retry)
run: |
set -euo pipefail
corepack enable
for attempt in 1 2 3; do
if corepack prepare pnpm@10.23.0 --activate; then
pnpm -v
exit 0
fi
echo "corepack prepare failed (attempt $attempt/3). Retrying..."
sleep $((attempt * 10))
done
exit 1
- name: Install pnpm deps (minimal)
run: pnpm install --ignore-scripts --frozen-lockfile
- name: Run installer smoke tests
env:
CLAWDBOT_INSTALL_URL: https://openclaw.ai/install.sh
CLAWDBOT_INSTALL_CLI_URL: https://openclaw.ai/install-cli.sh
CLAWDBOT_NO_ONBOARD: "1"
CLAWDBOT_INSTALL_SMOKE_SKIP_CLI: "1"
CLAWDBOT_INSTALL_SMOKE_SKIP_NONROOT: "1"
CLAWDBOT_INSTALL_SMOKE_SKIP_PREVIOUS: "1"
run: pnpm test:install:smoke
# Test summary
test-summary:
name: Test Summary (${{ inputs.test_stage }})
runs-on: ubuntu-latest
needs: [ci, install-smoke]
if: "!cancelled()"
outputs:
overall_status: ${{ steps.summary.outputs.overall_status }}
steps:
- name: Generate summary
id: summary
run: |
echo "## 🧪 Test Results - ${{ inputs.test_stage }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Test Suite | Result |" >> $GITHUB_STEP_SUMMARY
echo "|------------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| CI (checks + secrets) | ${{ needs.ci.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Install Smoke | ${{ needs.install-smoke.result || 'skipped' }} |" >> $GITHUB_STEP_SUMMARY
# CI must pass (includes platform-specific jobs based on test_stage)
if [ "${{ needs.ci.result }}" != "success" ]; then
echo "overall_status=failed" >> $GITHUB_OUTPUT
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ CI failed" >> $GITHUB_STEP_SUMMARY
exit 0
fi
# Stage-specific checks
STAGE="${{ inputs.test_stage }}"
FAILED=false
if [ "$STAGE" = "stable" ]; then
if [ "${{ needs.install-smoke.result }}" = "failure" ]; then
FAILED=true
fi
fi
if [ "$FAILED" = "true" ]; then
echo "overall_status=failed" >> $GITHUB_OUTPUT
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Some stage-specific tests failed" >> $GITHUB_STEP_SUMMARY
else
echo "overall_status=passed" >> $GITHUB_OUTPUT
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ✅ All required tests passed!" >> $GITHUB_STEP_SUMMARY
fi
# Discord notifications
notify:
name: Discord Notification
needs: test-summary
if: "!cancelled()"
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discord success notification
if: ${{ env.DISCORD_WEBHOOK_URL != '' && needs.test-summary.outputs.overall_status == 'passed' }}
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: "✅ Tests Passed: ${{ inputs.test_stage }} v${{ inputs.app_version }}"
description: "All tests passed for ${{ inputs.test_stage }} stage!"
color: "3066993"
- name: Discord failure notification
if: ${{ env.DISCORD_WEBHOOK_URL != '' && needs.test-summary.outputs.overall_status != 'passed' }}
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: "❌ Tests Failed: ${{ inputs.test_stage }} v${{ inputs.app_version }}"
description: |
Some tests failed for ${{ inputs.test_stage }} stage.
[View Logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
color: "15158332"

188
.github/workflows/version-operations.yml vendored Normal file
View File

@@ -0,0 +1,188 @@
name: Version Operations
# Version bump workflow for openclaw
#
# Version format: YYYY.M.D (stable) or YYYY.M.D-{alpha,beta}.N (prerelease)
# Examples: 2026.2.6, 2026.2.6-alpha.1, 2026.2.6-beta.3
on:
workflow_call:
inputs:
release_type:
description: "Release type: alpha, beta, or stable"
required: true
type: string
source_branch:
description: "Source branch"
required: true
type: string
should_bump:
description: "Whether to bump the version"
required: false
type: boolean
default: true
dry_run:
description: "Perform a dry run without committing"
required: false
type: boolean
default: false
outputs:
current_version:
description: "Current version before bump"
value: ${{ jobs.version.outputs.current_version }}
new_version:
description: "New version after bump"
value: ${{ jobs.version.outputs.new_version }}
version_tag:
description: "Version tag (with v prefix)"
value: ${{ jobs.version.outputs.version_tag }}
permissions:
contents: write
jobs:
version:
name: Version Operations
runs-on: ubuntu-latest
outputs:
current_version: ${{ steps.get-version.outputs.current }}
new_version: ${{ steps.bump-version.outputs.new }}
version_tag: ${{ steps.bump-version.outputs.tag }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.source_branch }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22.x
- name: Get current version
id: get-version
run: |
CURRENT_VERSION=$(node -p "require('./package.json').version")
echo "current=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "Current version: $CURRENT_VERSION"
- name: Calculate new version
id: bump-version
run: |
CURRENT="${{ steps.get-version.outputs.current }}"
RELEASE_TYPE="${{ inputs.release_type }}"
# Get current date components
YEAR=$(date +%Y)
MONTH=$(date +%-m)
DAY=$(date +%-d)
TODAY="${YEAR}.${MONTH}.${DAY}"
# Parse current version to check if it's today + same type
# Patterns: YYYY.M.D or YYYY.M.D-type.N
if [[ "$CURRENT" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-([a-z]+)\.([0-9]+))?$ ]]; then
CURR_DATE="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
CURR_TYPE="${BASH_REMATCH[5]}"
CURR_NUM="${BASH_REMATCH[6]:-0}"
else
CURR_DATE=""
CURR_TYPE=""
CURR_NUM=0
fi
case "$RELEASE_TYPE" in
alpha)
if [ "$CURR_DATE" = "$TODAY" ] && [ "$CURR_TYPE" = "alpha" ]; then
# Same day, same type - increment prerelease number
NEW_NUM=$((CURR_NUM + 1))
else
# New day or different type - start at 1
NEW_NUM=1
fi
NEW_VERSION="${TODAY}-alpha.${NEW_NUM}"
;;
beta)
if [ "$CURR_DATE" = "$TODAY" ] && [ "$CURR_TYPE" = "beta" ]; then
NEW_NUM=$((CURR_NUM + 1))
else
NEW_NUM=1
fi
NEW_VERSION="${TODAY}-beta.${NEW_NUM}"
;;
stable)
# Stable releases use date; append counter if tag already exists
if git tag -l "v${TODAY}" | grep -q .; then
# Tag exists, find next available counter
COUNTER=1
while git tag -l "v${TODAY}.${COUNTER}" | grep -q .; do
COUNTER=$((COUNTER + 1))
done
NEW_VERSION="${TODAY}.${COUNTER}"
else
NEW_VERSION="${TODAY}"
fi
;;
*)
echo "Unknown release type: $RELEASE_TYPE"
exit 1
;;
esac
echo "new=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "tag=v$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"
- name: Update package.json
if: ${{ inputs.should_bump && !inputs.dry_run }}
run: |
NEW_VERSION="${{ steps.bump-version.outputs.new }}"
# Update package.json version
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.version = '$NEW_VERSION';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"
echo "Updated package.json to version $NEW_VERSION"
- name: Sync extension versions
if: ${{ inputs.should_bump && !inputs.dry_run }}
run: |
# Run plugins:sync if available (aligns extension package versions)
if npm run --silent plugins:sync 2>/dev/null; then
echo "Extension versions synced"
else
echo "plugins:sync not available, skipping"
fi
- name: Commit version bump
if: ${{ inputs.should_bump && !inputs.dry_run }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
NEW_VERSION="${{ steps.bump-version.outputs.new }}"
# Stage all version-related changes
git add package.json
git add extensions/*/package.json 2>/dev/null || true
# Check if there are changes to commit
if git diff --cached --quiet; then
echo "No version changes to commit"
else
git commit -m "chore: bump version to $NEW_VERSION"
git push origin ${{ inputs.source_branch }}
fi
- name: Create tag
if: ${{ inputs.should_bump && !inputs.dry_run }}
run: |
TAG="${{ steps.bump-version.outputs.tag }}"
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"

View File

@@ -3,6 +3,11 @@ name: Workflow Sanity
on:
pull_request:
push:
branches: [main]
concurrency:
group: workflow-sanity-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
jobs:
no-tabs:

52
.markdownlint-cli2.jsonc Normal file
View File

@@ -0,0 +1,52 @@
{
"globs": ["docs/**/*.md", "docs/**/*.mdx", "README.md"],
"ignores": ["docs/zh-CN/**", "docs/.i18n/**", "docs/reference/templates/**"],
"config": {
"default": true,
"MD013": false,
"MD025": false,
"MD029": false,
"MD033": {
"allowed_elements": [
"Note",
"Info",
"Tip",
"Warning",
"Card",
"CardGroup",
"Columns",
"Steps",
"Step",
"Tabs",
"Tab",
"Accordion",
"AccordionGroup",
"CodeGroup",
"Frame",
"Callout",
"ParamField",
"ResponseField",
"RequestExample",
"ResponseExample",
"img",
"a",
"br",
"details",
"summary",
"p",
"strong",
"picture",
"source",
"Tooltip",
"Check",
],
},
"MD036": false,
"MD040": false,
"MD041": false,
"MD046": false,
},
}

View File

@@ -24,6 +24,7 @@
"assets/",
"dist/",
"docs/_layouts/",
"extensions/",
"node_modules/",
"patches/",
"pnpm-lock.yaml/",

View File

@@ -95,6 +95,8 @@
- Group related changes; avoid bundling unrelated refactors.
- Changelog workflow: keep latest released version at top (no `Unreleased`); after publishing, bump version and start a new top section.
- PRs should summarize scope, note testing performed, and mention any user-facing changes or new flags.
- Read this when submitting a PR: `docs/help/submitting-a-pr.md` ([Submitting a PR](https://docs.openclaw.ai/help/submitting-a-pr))
- Read this when submitting an issue: `docs/help/submitting-an-issue.md` ([Submitting an Issue](https://docs.openclaw.ai/help/submitting-an-issue))
- PR review flow: when given a PR link, review via `gh pr view`/`gh pr diff` and do **not** change branches.
- PR review calls: prefer a single `gh pr view --json ...` to batch metadata/comments; run `gh pr diff` only when needed.
- Before starting a review when a GH Issue/PR is pasted: run `git pull`; if there are local changes or unpushed commits, stop and alert the user before reviewing.

View File

@@ -2,27 +2,54 @@
Docs: https://docs.openclaw.ai
## 2026.2.4
## 2026.2.6
### Changes
- Cron: default `wakeMode` is now `"now"` for new jobs (was `"next-heartbeat"`). (#10776) Thanks @tyler6204.
- Cron: `cron run` defaults to force execution; use `--due` to restrict to due-only. (#10776) Thanks @tyler6204.
- Models: support Anthropic Opus 4.6 and OpenAI Codex gpt-5.3-codex (forward-compat fallbacks). (#9853, #10720, #9995) Thanks @TinyTb, @calvin-hpnet, @tyler6204.
- Providers: add xAI (Grok) support. (#9885) Thanks @grp06.
- Providers: add Baidu Qianfan support. (#8868) Thanks @ide-rea.
- Web UI: add token usage dashboard. (#10072) Thanks @Takhoffman.
- Memory: native Voyage AI support. (#7078) Thanks @mcinteerj.
- Sessions: cap sessions_history payloads to reduce context overflow. (#10000) Thanks @gut-puncture.
- CLI: sort commands alphabetically in help output. (#8068) Thanks @deepsoumya617.
- CI: optimize pipeline throughput (macOS consolidation, Windows perf, workflow concurrency). (#10784) Thanks @mcaxtr.
- Agents: bump pi-mono to 0.52.7; add embedded forward-compat fallback for Opus 4.6 model ids.
### Added
- Cron: run history deep-links to session chat from the dashboard. (#10776) Thanks @tyler6204.
- Cron: per-run session keys in run log entries and default labels for cron sessions. (#10776) Thanks @tyler6204.
- Cron: legacy payload field compatibility (`deliver`, `channel`, `to`, `bestEffortDeliver`) in schema. (#10776) Thanks @tyler6204.
### Fixes
- Cron: scheduler reliability (timer drift, restart catch-up, lock contention, stale running markers). (#10776) Thanks @tyler6204.
- Cron: store migration hardening (legacy field migration, parse error handling, explicit delivery mode persistence). (#10776) Thanks @tyler6204.
- Memory: set Voyage embeddings `input_type` for improved retrieval. (#10818) Thanks @mcinteerj.
- Telegram: auto-inject DM topic threadId in message tool + subagent announce. (#7235) Thanks @Lukavyi.
- Security: require auth for Gateway canvas host and A2UI assets. (#9518) Thanks @coygeek.
- Cron: fix scheduling and reminder delivery regressions; harden next-run recompute + timer re-arming + legacy schedule fields. (#9733, #9823, #9948, #9932) Thanks @tyler6204, @pycckuu, @j2h4u, @fujiwara-tofu-shop.
- Update: harden Control UI asset handling in update flow. (#10146) Thanks @gumadeiras.
- Security: add skill/plugin code safety scanner; redact credentials from config.get gateway responses. (#9806, #9858) Thanks @abdelsfane.
- Exec approvals: coerce bare string allowlist entries to objects. (#9903) Thanks @mcaxtr.
- Slack: add mention stripPatterns for /new and /reset. (#9971) Thanks @ironbyte-rgb.
- Chrome extension: fix bundled path resolution. (#8914) Thanks @kelvinCB.
- Compaction/errors: allow multiple compaction retries on context overflow; show clear billing errors. (#8928, #8391) Thanks @Glucksberg.
## 2026.2.3
### Changes
- Agents: bump pi-mono packages to 0.52.5. (#9949) Thanks @gumadeiras.
- Models: default Anthropic model to `anthropic/claude-opus-4-6`. (#9853) Thanks @TinyTb.
- Models/Onboarding: refresh provider defaults, update OpenAI/OpenAI Codex wizard defaults, and harden model allowlist initialization for first-time configs with matching docs/tests. (#9911) Thanks @gumadeiras.
- Telegram: auto-inject forum topic `threadId` in message tool and subagent announce so media, buttons, and subagent results land in the correct topic instead of General. (#7235) Thanks @Lukavyi.
- Security: add skill/plugin code safety scanner that detects dangerous patterns (command injection, eval, data exfiltration, obfuscated code, crypto mining, env harvesting) in installed extensions. Integrated into `openclaw security audit --deep` and plugin install flow; scan failures surface as warnings. (#9806) Thanks @abdelsfane.
- CLI: sort `openclaw --help` commands (and options) alphabetically. (#8068) Thanks @deepsoumya617.
- Telegram: remove last `@ts-nocheck` from `bot-handlers.ts`, use Grammy types directly, deduplicate `StickerMetadata`. Zero `@ts-nocheck` remaining in `src/telegram/`. (#9206)
- Telegram: remove `@ts-nocheck` from `bot-message.ts`, type deps via `Omit<BuildTelegramMessageContextParams>`, widen `allMedia` to `TelegramMediaRef[]`. (#9180)
- Telegram: remove `@ts-nocheck` from `bot.ts`, fix duplicate `bot.catch` error handler (Grammy overrides), remove dead reaction `message_thread_id` routing, harden sticker cache guard. (#9077)
- Telegram: allow per-group and per-topic `groupPolicy` overrides under `channels.telegram.groups`. (#9775) Thanks @nicolasstanley.
- Feishu: expand channel handling (posts with images, doc links, routing, reactions/typing, replies, native commands). (#8975) Thanks @jiulingyun.
- Onboarding: add Cloudflare AI Gateway provider setup and docs. (#7914) Thanks @roerohan.
- Onboarding: add Moonshot (.cn) auth choice and keep the China base URL when preserving defaults. (#7180) Thanks @waynelwz.
- Onboarding: add xAI (Grok) auth choice and provider defaults. (#9885) Thanks @grp06.
- Docs: clarify tmux send-keys for TUI by splitting text and Enter. (#7737) Thanks @Wangnov.
- Docs: mirror the landing page revamp for zh-CN (features, quickstart, docs directory, network model, credits). (#8994) Thanks @joshp123.
- Docs: strengthen secure DM mode guidance for multi-user inboxes with an explicit warning and example. (#9377) Thanks @Shrinija17.
- Messages: add per-channel and per-account responsePrefix overrides across channels. (#9001) Thanks @mudrii.
- Cron: add announce delivery mode for isolated jobs (CLI + Control UI) and delivery mode config.
- Cron: default isolated jobs to announce delivery; accept ISO 8601 `schedule.at` in tool inputs.
@@ -33,14 +60,6 @@ Docs: https://docs.openclaw.ai
### Fixes
- Models: add forward-compat fallback for `openai-codex/gpt-5.3-codex` when model registry hasn't discovered it yet. (#9989) Thanks @w1kke.
- Auto-reply/Docs: normalize `extra-high` (and spaced variants) to `xhigh` for Codex thinking levels, and align Codex 5.3 FAQ examples. (#9976) Thanks @slonce70.
- Compaction: remove orphaned `tool_result` messages during history pruning to prevent session corruption from aborted tool calls. (#9868, fixes #9769, #9724, #9672)
- Telegram: pass `parentPeer` for forum topic binding inheritance so group-level bindings apply to all topics within the group. (#9789, fixes #9545, #9351)
- CLI: pass `--disable-warning=ExperimentalWarning` as a Node CLI option when respawning (avoid disallowed `NODE_OPTIONS` usage; fixes npm pack). (#9691) Thanks @18-RAJAT.
- CLI: resolve bundled Chrome extension assets by walking up to the nearest assets directory; add resolver and clipboard tests. (#8914) Thanks @kelvinCB.
- Tests: stabilize Windows ACL coverage with deterministic os.userInfo mocking. (#9335) Thanks @M00N7682.
- Exec approvals: coerce bare string allowlist entries to objects to prevent allowlist corruption. (#9903, fixes #9790) Thanks @mcaxtr.
- Heartbeat: allow explicit accountId routing for multi-account channels. (#8702) Thanks @lsh411.
- TUI/Gateway: handle non-streaming finals, refresh history for non-local chat runs, and avoid event gap warnings for targeted tool streams. (#8432) Thanks @gumadeiras.
- Shell completion: auto-detect and migrate slow dynamic patterns to cached files for faster terminal startup; add completion health checks to doctor/update/onboard.
@@ -50,9 +69,6 @@ Docs: https://docs.openclaw.ai
- Web UI: apply button styling to the new-messages indicator.
- Onboarding: infer auth choice from non-interactive API key flags. (#8484) Thanks @f-trycua.
- Security: keep untrusted channel metadata out of system prompts (Slack/Discord). Thanks @KonstantinMirin.
- Security: redact channel credentials (tokens, passwords, API keys, secrets) from gateway config APIs and preserve secrets during Control UI round-trips. (#9858) Thanks @abdelsfane.
- Discord: treat allowlisted senders as owner for system-prompt identity hints while keeping channel topics untrusted.
- Slack: strip `<@...>` mention tokens before command matching so `/new` and `/reset` work when prefixed with a mention. (#9971) Thanks @ironbyte-rgb.
- Security: enforce sandboxed media paths for message tool attachments. (#9182) Thanks @victormier.
- Security: require explicit credentials for gateway URL overrides to prevent credential leakage. (#8113) Thanks @victormier.
- Security: gate `whatsapp_login` tool to owner senders and default-deny non-owner contexts. (#8768) Thanks @victormier.
@@ -60,13 +76,9 @@ Docs: https://docs.openclaw.ai
- Voice call: add regression coverage for anonymous inbound caller IDs with allowlist policy. (#8104) Thanks @victormier.
- Cron: accept epoch timestamps and 0ms durations in CLI `--at` parsing.
- Cron: reload store data when the store file is recreated or mtime changes.
- Cron: prevent `recomputeNextRuns` from skipping due jobs when timer fires late by reordering `onTimer` flow. (#9823, fixes #9788) Thanks @pycckuu.
- Cron: deliver announce runs directly, honor delivery mode, and respect wakeMode for summaries. (#8540) Thanks @tyler6204.
- Cron: correct announce delivery inference for thread session keys and null delivery inputs. (#9733) Thanks @tyler6204.
- Telegram: include forward_from_chat metadata in forwarded messages and harden cron delivery target checks. (#8392) Thanks @Glucksberg.
- Telegram: preserve DM topic threadId in deliveryContext. (#9039) Thanks @lailoo.
- macOS: fix cron payload summary rendering and ISO 8601 formatter concurrency safety.
- Security: require gateway auth for Canvas host and A2UI assets. (#9518) Thanks @coygeek.
## 2026.2.2-3

View File

@@ -25,6 +25,9 @@ Welcome to the lobster tank! 🦞
- **Gustavo Madeira Santana** - Multi-agents, CLI, web UI
- GitHub: [@gumadeiras](https://github.com/gumadeiras) · X: [@gumadeiras](https://x.com/gumadeiras)
- **Maximilian Nussbaumer** - DevOps, CI/CD
- GitHub: [@quotentiroler](https://github.com/quotentiroler)
## How to Contribute
1. **Bugs & small fixes** → Open a PR!
@@ -76,3 +79,46 @@ We are currently prioritizing:
- **Performance**: Optimizing token usage and compaction logic.
Check the [GitHub Issues](https://github.com/openclaw/openclaw/issues) for "good first issue" labels!
## Core vs ClawHub
Not everything belongs in the main repo. Here's how to decide:
| Belongs in **Core** | Belongs on **[ClawHub](https://clawhub.ai)** |
| ---------------------------------------------- | ---------------------------------------------------- |
| Channel integrations (Telegram, Discord, etc.) | Domain-specific skills (QR codes, image tools, etc.) |
| CLI commands and infrastructure | Custom workflows and automations |
| Provider integrations (LLM backends) | Niche or experimental utilities |
| Security, routing, and core plumbing | Third-party service integrations |
**Rule of thumb:** if it adds new dependencies or is useful to some users but not most, it belongs on ClawHub. When in doubt, ask in Discord or open a Discussion before writing code.
Skills submitted as PRs to this repo will be redirected to ClawHub. If the core maintainers later decide certain functionality should be first-party, it will be integrated into core.
## Branch Strategy
> **Note:** The staged promotion pipeline is not yet active. Workflows are in
> place but dormant. For now, open PRs targeting `main` as usual. Once the
> pipeline is activated, the flow below will apply.
We will use staged branch promotion to keep `main` stable:
```
dev/* / feature/* / fix/* → develop → alpha → beta → main
```
### For External Contributors (once pipeline is active)
1. Fork the repo
2. Create your branch (`dev/my-feature`, `fix/some-bug`, etc.)
3. Open a PR targeting `develop` (not `main`)
4. CI runs lightweight checks only — no heavy platform tests on your PR
5. Once merged to `develop`, your changes promote through alpha → beta → main automatically
### For Maintainers (once pipeline is active)
- **Regular changes**: merge to `develop`, let the pipeline promote
- **Hotfixes**: use `hotfix/*` branches for emergency fixes that bypass staging directly to `main`
- **Docs-only changes**: skip the test pipeline automatically (paths-ignore)
See [Pipeline docs](https://docs.openclaw.ai/reference/pipeline) for full details.

View File

@@ -44,5 +44,5 @@ USER node
#
# For container platforms requiring external health checks:
# 1. Set OPENCLAW_GATEWAY_TOKEN or OPENCLAW_GATEWAY_PASSWORD env var
# 2. Override CMD: ["node","dist/index.js","gateway","--allow-unconfigured","--bind","lan"]
CMD ["node", "dist/index.js", "gateway", "--allow-unconfigured"]
# 2. Override CMD: ["node","openclaw.mjs","gateway","--allow-unconfigured","--bind","lan"]
CMD ["node", "openclaw.mjs", "gateway", "--allow-unconfigured"]

View File

@@ -496,46 +496,49 @@ Special thanks to Adam Doppelt for lobster.bot.
Thanks to all clawtributors:
<p align="left">
<a href="https://github.com/steipete"><img src="https://avatars.githubusercontent.com/u/58493?v=4&s=48" width="48" height="48" alt="steipete" title="steipete"/></a> <a href="https://github.com/joshp123"><img src="https://avatars.githubusercontent.com/u/1497361?v=4&s=48" width="48" height="48" alt="joshp123" title="joshp123"/></a> <a href="https://github.com/cpojer"><img src="https://avatars.githubusercontent.com/u/13352?v=4&s=48" width="48" height="48" alt="cpojer" title="cpojer"/></a> <a href="https://github.com/mbelinky"><img src="https://avatars.githubusercontent.com/u/132747814?v=4&s=48" width="48" height="48" alt="Mariano Belinky" title="Mariano Belinky"/></a> <a href="https://github.com/plum-dawg"><img src="https://avatars.githubusercontent.com/u/5909950?v=4&s=48" width="48" height="48" alt="plum-dawg" title="plum-dawg"/></a> <a href="https://github.com/bohdanpodvirnyi"><img src="https://avatars.githubusercontent.com/u/31819391?v=4&s=48" width="48" height="48" alt="bohdanpodvirnyi" title="bohdanpodvirnyi"/></a> <a href="https://github.com/iHildy"><img src="https://avatars.githubusercontent.com/u/25069719?v=4&s=48" width="48" height="48" alt="iHildy" title="iHildy"/></a> <a href="https://github.com/jaydenfyi"><img src="https://avatars.githubusercontent.com/u/213395523?v=4&s=48" width="48" height="48" alt="jaydenfyi" title="jaydenfyi"/></a> <a href="https://github.com/joaohlisboa"><img src="https://avatars.githubusercontent.com/u/8200873?v=4&s=48" width="48" height="48" alt="joaohlisboa" title="joaohlisboa"/></a> <a href="https://github.com/mneves75"><img src="https://avatars.githubusercontent.com/u/2423436?v=4&s=48" width="48" height="48" alt="mneves75" title="mneves75"/></a>
<a href="https://github.com/MatthieuBizien"><img src="https://avatars.githubusercontent.com/u/173090?v=4&s=48" width="48" height="48" alt="MatthieuBizien" title="MatthieuBizien"/></a> <a href="https://github.com/MaudeBot"><img src="https://avatars.githubusercontent.com/u/255777700?v=4&s=48" width="48" height="48" alt="MaudeBot" title="MaudeBot"/></a> <a href="https://github.com/sebslight"><img src="https://avatars.githubusercontent.com/u/19554889?v=4&s=48" width="48" height="48" alt="sebslight" title="sebslight"/></a> <a href="https://github.com/Glucksberg"><img src="https://avatars.githubusercontent.com/u/80581902?v=4&s=48" width="48" height="48" alt="Glucksberg" title="Glucksberg"/></a> <a href="https://github.com/rahthakor"><img src="https://avatars.githubusercontent.com/u/8470553?v=4&s=48" width="48" height="48" alt="rahthakor" title="rahthakor"/></a> <a href="https://github.com/vrknetha"><img src="https://avatars.githubusercontent.com/u/20596261?v=4&s=48" width="48" height="48" alt="vrknetha" title="vrknetha"/></a> <a href="https://github.com/tyler6204"><img src="https://avatars.githubusercontent.com/u/64381258?v=4&s=48" width="48" height="48" alt="tyler6204" title="tyler6204"/></a> <a href="https://github.com/vignesh07"><img src="https://avatars.githubusercontent.com/u/1436853?v=4&s=48" width="48" height="48" alt="vignesh07" title="vignesh07"/></a> <a href="https://github.com/radek-paclt"><img src="https://avatars.githubusercontent.com/u/50451445?v=4&s=48" width="48" height="48" alt="radek-paclt" title="radek-paclt"/></a> <a href="https://github.com/tobiasbischoff"><img src="https://avatars.githubusercontent.com/u/711564?v=4&s=48" width="48" height="48" alt="Tobias Bischoff" title="Tobias Bischoff"/></a>
<a href="https://github.com/czekaj"><img src="https://avatars.githubusercontent.com/u/1464539?v=4&s=48" width="48" height="48" alt="czekaj" title="czekaj"/></a> <a href="https://github.com/ethanpalm"><img src="https://avatars.githubusercontent.com/u/56270045?v=4&s=48" width="48" height="48" alt="ethanpalm" title="ethanpalm"/></a> <a href="https://github.com/mukhtharcm"><img src="https://avatars.githubusercontent.com/u/56378562?v=4&s=48" width="48" height="48" alt="mukhtharcm" title="mukhtharcm"/></a> <a href="https://github.com/maxsumrall"><img src="https://avatars.githubusercontent.com/u/628843?v=4&s=48" width="48" height="48" alt="maxsumrall" title="maxsumrall"/></a> <a href="https://github.com/xadenryan"><img src="https://avatars.githubusercontent.com/u/165437834?v=4&s=48" width="48" height="48" alt="xadenryan" title="xadenryan"/></a> <a href="https://github.com/VACInc"><img src="https://avatars.githubusercontent.com/u/3279061?v=4&s=48" width="48" height="48" alt="VACInc" title="VACInc"/></a> <a href="https://github.com/rodrigouroz"><img src="https://avatars.githubusercontent.com/u/384037?v=4&s=48" width="48" height="48" alt="rodrigouroz" title="rodrigouroz"/></a> <a href="https://github.com/juanpablodlc"><img src="https://avatars.githubusercontent.com/u/92012363?v=4&s=48" width="48" height="48" alt="juanpablodlc" title="juanpablodlc"/></a> <a href="https://github.com/conroywhitney"><img src="https://avatars.githubusercontent.com/u/249891?v=4&s=48" width="48" height="48" alt="conroywhitney" title="conroywhitney"/></a> <a href="https://github.com/hsrvc"><img src="https://avatars.githubusercontent.com/u/129702169?v=4&s=48" width="48" height="48" alt="hsrvc" title="hsrvc"/></a>
<a href="https://github.com/christianklotz"><img src="https://avatars.githubusercontent.com/u/69443?v=4&s=48" width="48" height="48" alt="christianklotz" title="christianklotz"/></a> <a href="https://github.com/magimetal"><img src="https://avatars.githubusercontent.com/u/36491250?v=4&s=48" width="48" height="48" alt="magimetal" title="magimetal"/></a> <a href="https://github.com/zerone0x"><img src="https://avatars.githubusercontent.com/u/39543393?v=4&s=48" width="48" height="48" alt="zerone0x" title="zerone0x"/></a> <a href="https://github.com/meaningfool"><img src="https://avatars.githubusercontent.com/u/2862331?v=4&s=48" width="48" height="48" alt="meaningfool" title="meaningfool"/></a> <a href="https://github.com/Takhoffman"><img src="https://avatars.githubusercontent.com/u/781889?v=4&s=48" width="48" height="48" alt="Takhoffman" title="Takhoffman"/></a> <a href="https://github.com/patelhiren"><img src="https://avatars.githubusercontent.com/u/172098?v=4&s=48" width="48" height="48" alt="patelhiren" title="patelhiren"/></a> <a href="https://github.com/NicholasSpisak"><img src="https://avatars.githubusercontent.com/u/129075147?v=4&s=48" width="48" height="48" alt="NicholasSpisak" title="NicholasSpisak"/></a> <a href="https://github.com/jonisjongithub"><img src="https://avatars.githubusercontent.com/u/86072337?v=4&s=48" width="48" height="48" alt="jonisjongithub" title="jonisjongithub"/></a> <a href="https://github.com/AbhisekBasu1"><img src="https://avatars.githubusercontent.com/u/40645221?v=4&s=48" width="48" height="48" alt="abhisekbasu1" title="abhisekbasu1"/></a> <a href="https://github.com/jamesgroat"><img src="https://avatars.githubusercontent.com/u/2634024?v=4&s=48" width="48" height="48" alt="jamesgroat" title="jamesgroat"/></a>
<a href="https://github.com/BunsDev"><img src="https://avatars.githubusercontent.com/u/68980965?v=4&s=48" width="48" height="48" alt="BunsDev" title="BunsDev"/></a> <a href="https://github.com/claude"><img src="https://avatars.githubusercontent.com/u/81847?v=4&s=48" width="48" height="48" alt="claude" title="claude"/></a> <a href="https://github.com/JustYannicc"><img src="https://avatars.githubusercontent.com/u/52761674?v=4&s=48" width="48" height="48" alt="JustYannicc" title="JustYannicc"/></a> <a href="https://github.com/Hyaxia"><img src="https://avatars.githubusercontent.com/u/36747317?v=4&s=48" width="48" height="48" alt="Hyaxia" title="Hyaxia"/></a> <a href="https://github.com/dantelex"><img src="https://avatars.githubusercontent.com/u/631543?v=4&s=48" width="48" height="48" alt="dantelex" title="dantelex"/></a> <a href="https://github.com/SocialNerd42069"><img src="https://avatars.githubusercontent.com/u/118244303?v=4&s=48" width="48" height="48" alt="SocialNerd42069" title="SocialNerd42069"/></a> <a href="https://github.com/daveonkels"><img src="https://avatars.githubusercontent.com/u/533642?v=4&s=48" width="48" height="48" alt="daveonkels" title="daveonkels"/></a> <a href="https://github.com/apps/google-labs-jules"><img src="https://avatars.githubusercontent.com/in/842251?v=4&s=48" width="48" height="48" alt="google-labs-jules[bot]" title="google-labs-jules[bot]"/></a> <a href="https://github.com/lc0rp"><img src="https://avatars.githubusercontent.com/u/2609441?v=4&s=48" width="48" height="48" alt="lc0rp" title="lc0rp"/></a> <a href="https://github.com/mousberg"><img src="https://avatars.githubusercontent.com/u/57605064?v=4&s=48" width="48" height="48" alt="mousberg" title="mousberg"/></a>
<a href="https://github.com/adam91holt"><img src="https://avatars.githubusercontent.com/u/9592417?v=4&s=48" width="48" height="48" alt="adam91holt" title="adam91holt"/></a> <a href="https://github.com/hougangdev"><img src="https://avatars.githubusercontent.com/u/105773686?v=4&s=48" width="48" height="48" alt="hougangdev" title="hougangdev"/></a> <a href="https://github.com/gumadeiras"><img src="https://avatars.githubusercontent.com/u/5599352?v=4&s=48" width="48" height="48" alt="gumadeiras" title="gumadeiras"/></a> <a href="https://github.com/shakkernerd"><img src="https://avatars.githubusercontent.com/u/165377636?v=4&s=48" width="48" height="48" alt="shakkernerd" title="shakkernerd"/></a> <a href="https://github.com/mteam88"><img src="https://avatars.githubusercontent.com/u/84196639?v=4&s=48" width="48" height="48" alt="mteam88" title="mteam88"/></a> <a href="https://github.com/hirefrank"><img src="https://avatars.githubusercontent.com/u/183158?v=4&s=48" width="48" height="48" alt="hirefrank" title="hirefrank"/></a> <a href="https://github.com/joeynyc"><img src="https://avatars.githubusercontent.com/u/17919866?v=4&s=48" width="48" height="48" alt="joeynyc" title="joeynyc"/></a> <a href="https://github.com/orlyjamie"><img src="https://avatars.githubusercontent.com/u/6668807?v=4&s=48" width="48" height="48" alt="orlyjamie" title="orlyjamie"/></a> <a href="https://github.com/dbhurley"><img src="https://avatars.githubusercontent.com/u/5251425?v=4&s=48" width="48" height="48" alt="dbhurley" title="dbhurley"/></a> <a href="https://github.com/omniwired"><img src="https://avatars.githubusercontent.com/u/322761?v=4&s=48" width="48" height="48" alt="Eng. Juan Combetto" title="Eng. Juan Combetto"/></a>
<a href="https://github.com/TSavo"><img src="https://avatars.githubusercontent.com/u/877990?v=4&s=48" width="48" height="48" alt="TSavo" title="TSavo"/></a> <a href="https://github.com/aerolalit"><img src="https://avatars.githubusercontent.com/u/17166039?v=4&s=48" width="48" height="48" alt="aerolalit" title="aerolalit"/></a> <a href="https://github.com/julianengel"><img src="https://avatars.githubusercontent.com/u/10634231?v=4&s=48" width="48" height="48" alt="julianengel" title="julianengel"/></a> <a href="https://github.com/bradleypriest"><img src="https://avatars.githubusercontent.com/u/167215?v=4&s=48" width="48" height="48" alt="bradleypriest" title="bradleypriest"/></a> <a href="https://github.com/benithors"><img src="https://avatars.githubusercontent.com/u/20652882?v=4&s=48" width="48" height="48" alt="benithors" title="benithors"/></a> <a href="https://github.com/rohannagpal"><img src="https://avatars.githubusercontent.com/u/4009239?v=4&s=48" width="48" height="48" alt="rohannagpal" title="rohannagpal"/></a> <a href="https://github.com/timolins"><img src="https://avatars.githubusercontent.com/u/1440854?v=4&s=48" width="48" height="48" alt="timolins" title="timolins"/></a> <a href="https://github.com/f-trycua"><img src="https://avatars.githubusercontent.com/u/195596869?v=4&s=48" width="48" height="48" alt="f-trycua" title="f-trycua"/></a> <a href="https://github.com/benostein"><img src="https://avatars.githubusercontent.com/u/31802821?v=4&s=48" width="48" height="48" alt="benostein" title="benostein"/></a> <a href="https://github.com/elliotsecops"><img src="https://avatars.githubusercontent.com/u/141947839?v=4&s=48" width="48" height="48" alt="elliotsecops" title="elliotsecops"/></a>
<a href="https://github.com/Nachx639"><img src="https://avatars.githubusercontent.com/u/71144023?v=4&s=48" width="48" height="48" alt="nachx639" title="nachx639"/></a> <a href="https://github.com/pvoo"><img src="https://avatars.githubusercontent.com/u/20116814?v=4&s=48" width="48" height="48" alt="pvoo" title="pvoo"/></a> <a href="https://github.com/sreekaransrinath"><img src="https://avatars.githubusercontent.com/u/50989977?v=4&s=48" width="48" height="48" alt="sreekaransrinath" title="sreekaransrinath"/></a> <a href="https://github.com/gupsammy"><img src="https://avatars.githubusercontent.com/u/20296019?v=4&s=48" width="48" height="48" alt="gupsammy" title="gupsammy"/></a> <a href="https://github.com/cristip73"><img src="https://avatars.githubusercontent.com/u/24499421?v=4&s=48" width="48" height="48" alt="cristip73" title="cristip73"/></a> <a href="https://github.com/stefangalescu"><img src="https://avatars.githubusercontent.com/u/52995748?v=4&s=48" width="48" height="48" alt="stefangalescu" title="stefangalescu"/></a> <a href="https://github.com/nachoiacovino"><img src="https://avatars.githubusercontent.com/u/50103937?v=4&s=48" width="48" height="48" alt="nachoiacovino" title="nachoiacovino"/></a> <a href="https://github.com/vsabavat"><img src="https://avatars.githubusercontent.com/u/50385532?v=4&s=48" width="48" height="48" alt="Vasanth Rao Naik Sabavat" title="Vasanth Rao Naik Sabavat"/></a> <a href="https://github.com/petter-b"><img src="https://avatars.githubusercontent.com/u/62076402?v=4&s=48" width="48" height="48" alt="petter-b" title="petter-b"/></a> <a href="https://github.com/thewilloftheshadow"><img src="https://avatars.githubusercontent.com/u/35580099?v=4&s=48" width="48" height="48" alt="thewilloftheshadow" title="thewilloftheshadow"/></a>
<a href="https://github.com/leszekszpunar"><img src="https://avatars.githubusercontent.com/u/13106764?v=4&s=48" width="48" height="48" alt="leszekszpunar" title="leszekszpunar"/></a> <a href="https://github.com/scald"><img src="https://avatars.githubusercontent.com/u/1215913?v=4&s=48" width="48" height="48" alt="scald" title="scald"/></a> <a href="https://github.com/andranik-sahakyan"><img src="https://avatars.githubusercontent.com/u/8908029?v=4&s=48" width="48" height="48" alt="andranik-sahakyan" title="andranik-sahakyan"/></a> <a href="https://github.com/davidguttman"><img src="https://avatars.githubusercontent.com/u/431696?v=4&s=48" width="48" height="48" alt="davidguttman" title="davidguttman"/></a> <a href="https://github.com/sleontenko"><img src="https://avatars.githubusercontent.com/u/7135949?v=4&s=48" width="48" height="48" alt="sleontenko" title="sleontenko"/></a> <a href="https://github.com/denysvitali"><img src="https://avatars.githubusercontent.com/u/4939519?v=4&s=48" width="48" height="48" alt="denysvitali" title="denysvitali"/></a> <a href="https://github.com/apps/clawdinator"><img src="https://avatars.githubusercontent.com/in/2607181?v=4&s=48" width="48" height="48" alt="clawdinator[bot]" title="clawdinator[bot]"/></a> <a href="https://github.com/sircrumpet"><img src="https://avatars.githubusercontent.com/u/4436535?v=4&s=48" width="48" height="48" alt="sircrumpet" title="sircrumpet"/></a> <a href="https://github.com/peschee"><img src="https://avatars.githubusercontent.com/u/63866?v=4&s=48" width="48" height="48" alt="peschee" title="peschee"/></a> <a href="https://github.com/davidiach"><img src="https://avatars.githubusercontent.com/u/28102235?v=4&s=48" width="48" height="48" alt="davidiach" title="davidiach"/></a>
<a href="https://github.com/nonggialiang"><img src="https://avatars.githubusercontent.com/u/14367839?v=4&s=48" width="48" height="48" alt="nonggialiang" title="nonggialiang"/></a> <a href="https://github.com/rafaelreis-r"><img src="https://avatars.githubusercontent.com/u/57492577?v=4&s=48" width="48" height="48" alt="rafaelreis-r" title="rafaelreis-r"/></a> <a href="https://github.com/dominicnunez"><img src="https://avatars.githubusercontent.com/u/43616264?v=4&s=48" width="48" height="48" alt="dominicnunez" title="dominicnunez"/></a> <a href="https://github.com/lploc94"><img src="https://avatars.githubusercontent.com/u/28453843?v=4&s=48" width="48" height="48" alt="lploc94" title="lploc94"/></a> <a href="https://github.com/ratulsarna"><img src="https://avatars.githubusercontent.com/u/105903728?v=4&s=48" width="48" height="48" alt="ratulsarna" title="ratulsarna"/></a> <a href="https://github.com/sfo2001"><img src="https://avatars.githubusercontent.com/u/103369858?v=4&s=48" width="48" height="48" alt="sfo2001" title="sfo2001"/></a> <a href="https://github.com/lutr0"><img src="https://avatars.githubusercontent.com/u/76906369?v=4&s=48" width="48" height="48" alt="lutr0" title="lutr0"/></a> <a href="https://github.com/kiranjd"><img src="https://avatars.githubusercontent.com/u/25822851?v=4&s=48" width="48" height="48" alt="kiranjd" title="kiranjd"/></a> <a href="https://github.com/danielz1z"><img src="https://avatars.githubusercontent.com/u/235270390?v=4&s=48" width="48" height="48" alt="danielz1z" title="danielz1z"/></a> <a href="https://github.com/Iranb"><img src="https://avatars.githubusercontent.com/u/49674669?v=4&s=48" width="48" height="48" alt="Iranb" title="Iranb"/></a>
<a href="https://github.com/steipete"><img src="https://avatars.githubusercontent.com/u/58493?v=4&s=48" width="48" height="48" alt="steipete" title="steipete"/></a> <a href="https://github.com/joshp123"><img src="https://avatars.githubusercontent.com/u/1497361?v=4&s=48" width="48" height="48" alt="joshp123" title="joshp123"/></a> <a href="https://github.com/cpojer"><img src="https://avatars.githubusercontent.com/u/13352?v=4&s=48" width="48" height="48" alt="cpojer" title="cpojer"/></a> <a href="https://github.com/mbelinky"><img src="https://avatars.githubusercontent.com/u/132747814?v=4&s=48" width="48" height="48" alt="Mariano Belinky" title="Mariano Belinky"/></a> <a href="https://github.com/plum-dawg"><img src="https://avatars.githubusercontent.com/u/5909950?v=4&s=48" width="48" height="48" alt="plum-dawg" title="plum-dawg"/></a> <a href="https://github.com/bohdanpodvirnyi"><img src="https://avatars.githubusercontent.com/u/31819391?v=4&s=48" width="48" height="48" alt="bohdanpodvirnyi" title="bohdanpodvirnyi"/></a> <a href="https://github.com/sebslight"><img src="https://avatars.githubusercontent.com/u/19554889?v=4&s=48" width="48" height="48" alt="sebslight" title="sebslight"/></a> <a href="https://github.com/iHildy"><img src="https://avatars.githubusercontent.com/u/25069719?v=4&s=48" width="48" height="48" alt="iHildy" title="iHildy"/></a> <a href="https://github.com/jaydenfyi"><img src="https://avatars.githubusercontent.com/u/213395523?v=4&s=48" width="48" height="48" alt="jaydenfyi" title="jaydenfyi"/></a> <a href="https://github.com/joaohlisboa"><img src="https://avatars.githubusercontent.com/u/8200873?v=4&s=48" width="48" height="48" alt="joaohlisboa" title="joaohlisboa"/></a>
<a href="https://github.com/mneves75"><img src="https://avatars.githubusercontent.com/u/2423436?v=4&s=48" width="48" height="48" alt="mneves75" title="mneves75"/></a> <a href="https://github.com/MatthieuBizien"><img src="https://avatars.githubusercontent.com/u/173090?v=4&s=48" width="48" height="48" alt="MatthieuBizien" title="MatthieuBizien"/></a> <a href="https://github.com/Glucksberg"><img src="https://avatars.githubusercontent.com/u/80581902?v=4&s=48" width="48" height="48" alt="Glucksberg" title="Glucksberg"/></a> <a href="https://github.com/MaudeBot"><img src="https://avatars.githubusercontent.com/u/255777700?v=4&s=48" width="48" height="48" alt="MaudeBot" title="MaudeBot"/></a> <a href="https://github.com/gumadeiras"><img src="https://avatars.githubusercontent.com/u/5599352?v=4&s=48" width="48" height="48" alt="gumadeiras" title="gumadeiras"/></a> <a href="https://github.com/tyler6204"><img src="https://avatars.githubusercontent.com/u/64381258?v=4&s=48" width="48" height="48" alt="tyler6204" title="tyler6204"/></a> <a href="https://github.com/rahthakor"><img src="https://avatars.githubusercontent.com/u/8470553?v=4&s=48" width="48" height="48" alt="rahthakor" title="rahthakor"/></a> <a href="https://github.com/vrknetha"><img src="https://avatars.githubusercontent.com/u/20596261?v=4&s=48" width="48" height="48" alt="vrknetha" title="vrknetha"/></a> <a href="https://github.com/vignesh07"><img src="https://avatars.githubusercontent.com/u/1436853?v=4&s=48" width="48" height="48" alt="vignesh07" title="vignesh07"/></a> <a href="https://github.com/radek-paclt"><img src="https://avatars.githubusercontent.com/u/50451445?v=4&s=48" width="48" height="48" alt="radek-paclt" title="radek-paclt"/></a>
<a href="https://github.com/abdelsfane"><img src="https://avatars.githubusercontent.com/u/32418586?v=4&s=48" width="48" height="48" alt="abdelsfane" title="abdelsfane"/></a> <a href="https://github.com/tobiasbischoff"><img src="https://avatars.githubusercontent.com/u/711564?v=4&s=48" width="48" height="48" alt="Tobias Bischoff" title="Tobias Bischoff"/></a> <a href="https://github.com/christianklotz"><img src="https://avatars.githubusercontent.com/u/69443?v=4&s=48" width="48" height="48" alt="christianklotz" title="christianklotz"/></a> <a href="https://github.com/czekaj"><img src="https://avatars.githubusercontent.com/u/1464539?v=4&s=48" width="48" height="48" alt="czekaj" title="czekaj"/></a> <a href="https://github.com/ethanpalm"><img src="https://avatars.githubusercontent.com/u/56270045?v=4&s=48" width="48" height="48" alt="ethanpalm" title="ethanpalm"/></a> <a href="https://github.com/mukhtharcm"><img src="https://avatars.githubusercontent.com/u/56378562?v=4&s=48" width="48" height="48" alt="mukhtharcm" title="mukhtharcm"/></a> <a href="https://github.com/maxsumrall"><img src="https://avatars.githubusercontent.com/u/628843?v=4&s=48" width="48" height="48" alt="maxsumrall" title="maxsumrall"/></a> <a href="https://github.com/xadenryan"><img src="https://avatars.githubusercontent.com/u/165437834?v=4&s=48" width="48" height="48" alt="xadenryan" title="xadenryan"/></a> <a href="https://github.com/VACInc"><img src="https://avatars.githubusercontent.com/u/3279061?v=4&s=48" width="48" height="48" alt="VACInc" title="VACInc"/></a> <a href="https://github.com/rodrigouroz"><img src="https://avatars.githubusercontent.com/u/384037?v=4&s=48" width="48" height="48" alt="rodrigouroz" title="rodrigouroz"/></a>
<a href="https://github.com/juanpablodlc"><img src="https://avatars.githubusercontent.com/u/92012363?v=4&s=48" width="48" height="48" alt="juanpablodlc" title="juanpablodlc"/></a> <a href="https://github.com/conroywhitney"><img src="https://avatars.githubusercontent.com/u/249891?v=4&s=48" width="48" height="48" alt="conroywhitney" title="conroywhitney"/></a> <a href="https://github.com/hsrvc"><img src="https://avatars.githubusercontent.com/u/129702169?v=4&s=48" width="48" height="48" alt="hsrvc" title="hsrvc"/></a> <a href="https://github.com/magimetal"><img src="https://avatars.githubusercontent.com/u/36491250?v=4&s=48" width="48" height="48" alt="magimetal" title="magimetal"/></a> <a href="https://github.com/zerone0x"><img src="https://avatars.githubusercontent.com/u/39543393?v=4&s=48" width="48" height="48" alt="zerone0x" title="zerone0x"/></a> <a href="https://github.com/Takhoffman"><img src="https://avatars.githubusercontent.com/u/781889?v=4&s=48" width="48" height="48" alt="Takhoffman" title="Takhoffman"/></a> <a href="https://github.com/meaningfool"><img src="https://avatars.githubusercontent.com/u/2862331?v=4&s=48" width="48" height="48" alt="meaningfool" title="meaningfool"/></a> <a href="https://github.com/mudrii"><img src="https://avatars.githubusercontent.com/u/220262?v=4&s=48" width="48" height="48" alt="mudrii" title="mudrii"/></a> <a href="https://github.com/patelhiren"><img src="https://avatars.githubusercontent.com/u/172098?v=4&s=48" width="48" height="48" alt="patelhiren" title="patelhiren"/></a> <a href="https://github.com/NicholasSpisak"><img src="https://avatars.githubusercontent.com/u/129075147?v=4&s=48" width="48" height="48" alt="NicholasSpisak" title="NicholasSpisak"/></a>
<a href="https://github.com/jonisjongithub"><img src="https://avatars.githubusercontent.com/u/86072337?v=4&s=48" width="48" height="48" alt="jonisjongithub" title="jonisjongithub"/></a> <a href="https://github.com/AbhisekBasu1"><img src="https://avatars.githubusercontent.com/u/40645221?v=4&s=48" width="48" height="48" alt="abhisekbasu1" title="abhisekbasu1"/></a> <a href="https://github.com/jamesgroat"><img src="https://avatars.githubusercontent.com/u/2634024?v=4&s=48" width="48" height="48" alt="jamesgroat" title="jamesgroat"/></a> <a href="https://github.com/BunsDev"><img src="https://avatars.githubusercontent.com/u/68980965?v=4&s=48" width="48" height="48" alt="BunsDev" title="BunsDev"/></a> <a href="https://github.com/claude"><img src="https://avatars.githubusercontent.com/u/81847?v=4&s=48" width="48" height="48" alt="claude" title="claude"/></a> <a href="https://github.com/JustYannicc"><img src="https://avatars.githubusercontent.com/u/52761674?v=4&s=48" width="48" height="48" alt="JustYannicc" title="JustYannicc"/></a> <a href="https://github.com/Hyaxia"><img src="https://avatars.githubusercontent.com/u/36747317?v=4&s=48" width="48" height="48" alt="Hyaxia" title="Hyaxia"/></a> <a href="https://github.com/dantelex"><img src="https://avatars.githubusercontent.com/u/631543?v=4&s=48" width="48" height="48" alt="dantelex" title="dantelex"/></a> <a href="https://github.com/SocialNerd42069"><img src="https://avatars.githubusercontent.com/u/118244303?v=4&s=48" width="48" height="48" alt="SocialNerd42069" title="SocialNerd42069"/></a> <a href="https://github.com/daveonkels"><img src="https://avatars.githubusercontent.com/u/533642?v=4&s=48" width="48" height="48" alt="daveonkels" title="daveonkels"/></a>
<a href="https://github.com/apps/google-labs-jules"><img src="https://avatars.githubusercontent.com/in/842251?v=4&s=48" width="48" height="48" alt="google-labs-jules[bot]" title="google-labs-jules[bot]"/></a> <a href="https://github.com/lc0rp"><img src="https://avatars.githubusercontent.com/u/2609441?v=4&s=48" width="48" height="48" alt="lc0rp" title="lc0rp"/></a> <a href="https://github.com/adam91holt"><img src="https://avatars.githubusercontent.com/u/9592417?v=4&s=48" width="48" height="48" alt="adam91holt" title="adam91holt"/></a> <a href="https://github.com/mousberg"><img src="https://avatars.githubusercontent.com/u/57605064?v=4&s=48" width="48" height="48" alt="mousberg" title="mousberg"/></a> <a href="https://github.com/hougangdev"><img src="https://avatars.githubusercontent.com/u/105773686?v=4&s=48" width="48" height="48" alt="hougangdev" title="hougangdev"/></a> <a href="https://github.com/shakkernerd"><img src="https://avatars.githubusercontent.com/u/165377636?v=4&s=48" width="48" height="48" alt="shakkernerd" title="shakkernerd"/></a> <a href="https://github.com/coygeek"><img src="https://avatars.githubusercontent.com/u/65363919?v=4&s=48" width="48" height="48" alt="coygeek" title="coygeek"/></a> <a href="https://github.com/mteam88"><img src="https://avatars.githubusercontent.com/u/84196639?v=4&s=48" width="48" height="48" alt="mteam88" title="mteam88"/></a> <a href="https://github.com/hirefrank"><img src="https://avatars.githubusercontent.com/u/183158?v=4&s=48" width="48" height="48" alt="hirefrank" title="hirefrank"/></a> <a href="https://github.com/M00N7682"><img src="https://avatars.githubusercontent.com/u/170746674?v=4&s=48" width="48" height="48" alt="M00N7682" title="M00N7682"/></a>
<a href="https://github.com/joeynyc"><img src="https://avatars.githubusercontent.com/u/17919866?v=4&s=48" width="48" height="48" alt="joeynyc" title="joeynyc"/></a> <a href="https://github.com/orlyjamie"><img src="https://avatars.githubusercontent.com/u/6668807?v=4&s=48" width="48" height="48" alt="orlyjamie" title="orlyjamie"/></a> <a href="https://github.com/dbhurley"><img src="https://avatars.githubusercontent.com/u/5251425?v=4&s=48" width="48" height="48" alt="dbhurley" title="dbhurley"/></a> <a href="https://github.com/omniwired"><img src="https://avatars.githubusercontent.com/u/322761?v=4&s=48" width="48" height="48" alt="Eng. Juan Combetto" title="Eng. Juan Combetto"/></a> <a href="https://github.com/TSavo"><img src="https://avatars.githubusercontent.com/u/877990?v=4&s=48" width="48" height="48" alt="TSavo" title="TSavo"/></a> <a href="https://github.com/aerolalit"><img src="https://avatars.githubusercontent.com/u/17166039?v=4&s=48" width="48" height="48" alt="aerolalit" title="aerolalit"/></a> <a href="https://github.com/julianengel"><img src="https://avatars.githubusercontent.com/u/10634231?v=4&s=48" width="48" height="48" alt="julianengel" title="julianengel"/></a> <a href="https://github.com/bradleypriest"><img src="https://avatars.githubusercontent.com/u/167215?v=4&s=48" width="48" height="48" alt="bradleypriest" title="bradleypriest"/></a> <a href="https://github.com/benithors"><img src="https://avatars.githubusercontent.com/u/20652882?v=4&s=48" width="48" height="48" alt="benithors" title="benithors"/></a> <a href="https://github.com/lsh411"><img src="https://avatars.githubusercontent.com/u/6801488?v=4&s=48" width="48" height="48" alt="lsh411" title="lsh411"/></a>
<a href="https://github.com/gut-puncture"><img src="https://avatars.githubusercontent.com/u/75851986?v=4&s=48" width="48" height="48" alt="gut-puncture" title="gut-puncture"/></a> <a href="https://github.com/rohannagpal"><img src="https://avatars.githubusercontent.com/u/4009239?v=4&s=48" width="48" height="48" alt="rohannagpal" title="rohannagpal"/></a> <a href="https://github.com/timolins"><img src="https://avatars.githubusercontent.com/u/1440854?v=4&s=48" width="48" height="48" alt="timolins" title="timolins"/></a> <a href="https://github.com/f-trycua"><img src="https://avatars.githubusercontent.com/u/195596869?v=4&s=48" width="48" height="48" alt="f-trycua" title="f-trycua"/></a> <a href="https://github.com/benostein"><img src="https://avatars.githubusercontent.com/u/31802821?v=4&s=48" width="48" height="48" alt="benostein" title="benostein"/></a> <a href="https://github.com/elliotsecops"><img src="https://avatars.githubusercontent.com/u/141947839?v=4&s=48" width="48" height="48" alt="elliotsecops" title="elliotsecops"/></a> <a href="https://github.com/Nachx639"><img src="https://avatars.githubusercontent.com/u/71144023?v=4&s=48" width="48" height="48" alt="nachx639" title="nachx639"/></a> <a href="https://github.com/pvoo"><img src="https://avatars.githubusercontent.com/u/20116814?v=4&s=48" width="48" height="48" alt="pvoo" title="pvoo"/></a> <a href="https://github.com/sreekaransrinath"><img src="https://avatars.githubusercontent.com/u/50989977?v=4&s=48" width="48" height="48" alt="sreekaransrinath" title="sreekaransrinath"/></a> <a href="https://github.com/gupsammy"><img src="https://avatars.githubusercontent.com/u/20296019?v=4&s=48" width="48" height="48" alt="gupsammy" title="gupsammy"/></a>
<a href="https://github.com/cristip73"><img src="https://avatars.githubusercontent.com/u/24499421?v=4&s=48" width="48" height="48" alt="cristip73" title="cristip73"/></a> <a href="https://github.com/stefangalescu"><img src="https://avatars.githubusercontent.com/u/52995748?v=4&s=48" width="48" height="48" alt="stefangalescu" title="stefangalescu"/></a> <a href="https://github.com/nachoiacovino"><img src="https://avatars.githubusercontent.com/u/50103937?v=4&s=48" width="48" height="48" alt="nachoiacovino" title="nachoiacovino"/></a> <a href="https://github.com/vsabavat"><img src="https://avatars.githubusercontent.com/u/50385532?v=4&s=48" width="48" height="48" alt="Vasanth Rao Naik Sabavat" title="Vasanth Rao Naik Sabavat"/></a> <a href="https://github.com/petter-b"><img src="https://avatars.githubusercontent.com/u/62076402?v=4&s=48" width="48" height="48" alt="petter-b" title="petter-b"/></a> <a href="https://github.com/thewilloftheshadow"><img src="https://avatars.githubusercontent.com/u/35580099?v=4&s=48" width="48" height="48" alt="thewilloftheshadow" title="thewilloftheshadow"/></a> <a href="https://github.com/leszekszpunar"><img src="https://avatars.githubusercontent.com/u/13106764?v=4&s=48" width="48" height="48" alt="leszekszpunar" title="leszekszpunar"/></a> <a href="https://github.com/scald"><img src="https://avatars.githubusercontent.com/u/1215913?v=4&s=48" width="48" height="48" alt="scald" title="scald"/></a> <a href="https://github.com/pycckuu"><img src="https://avatars.githubusercontent.com/u/1489583?v=4&s=48" width="48" height="48" alt="pycckuu" title="pycckuu"/></a> <a href="https://github.com/andranik-sahakyan"><img src="https://avatars.githubusercontent.com/u/8908029?v=4&s=48" width="48" height="48" alt="andranik-sahakyan" title="andranik-sahakyan"/></a>
<a href="https://github.com/davidguttman"><img src="https://avatars.githubusercontent.com/u/431696?v=4&s=48" width="48" height="48" alt="davidguttman" title="davidguttman"/></a> <a href="https://github.com/sleontenko"><img src="https://avatars.githubusercontent.com/u/7135949?v=4&s=48" width="48" height="48" alt="sleontenko" title="sleontenko"/></a> <a href="https://github.com/denysvitali"><img src="https://avatars.githubusercontent.com/u/4939519?v=4&s=48" width="48" height="48" alt="denysvitali" title="denysvitali"/></a> <a href="https://github.com/apps/clawdinator"><img src="https://avatars.githubusercontent.com/in/2607181?v=4&s=48" width="48" height="48" alt="clawdinator[bot]" title="clawdinator[bot]"/></a> <a href="https://github.com/TinyTb"><img src="https://avatars.githubusercontent.com/u/5957298?v=4&s=48" width="48" height="48" alt="TinyTb" title="TinyTb"/></a> <a href="https://github.com/sircrumpet"><img src="https://avatars.githubusercontent.com/u/4436535?v=4&s=48" width="48" height="48" alt="sircrumpet" title="sircrumpet"/></a> <a href="https://github.com/peschee"><img src="https://avatars.githubusercontent.com/u/63866?v=4&s=48" width="48" height="48" alt="peschee" title="peschee"/></a> <a href="https://github.com/nicolasstanley"><img src="https://avatars.githubusercontent.com/u/60584925?v=4&s=48" width="48" height="48" alt="nicolasstanley" title="nicolasstanley"/></a> <a href="https://github.com/davidiach"><img src="https://avatars.githubusercontent.com/u/28102235?v=4&s=48" width="48" height="48" alt="davidiach" title="davidiach"/></a> <a href="https://github.com/nonggialiang"><img src="https://avatars.githubusercontent.com/u/14367839?v=4&s=48" width="48" height="48" alt="nonggialiang" title="nonggialiang"/></a>
<a href="https://github.com/ironbyte-rgb"><img src="https://avatars.githubusercontent.com/u/230665944?v=4&s=48" width="48" height="48" alt="ironbyte-rgb" title="ironbyte-rgb"/></a> <a href="https://github.com/rafaelreis-r"><img src="https://avatars.githubusercontent.com/u/57492577?v=4&s=48" width="48" height="48" alt="rafaelreis-r" title="rafaelreis-r"/></a> <a href="https://github.com/dominicnunez"><img src="https://avatars.githubusercontent.com/u/43616264?v=4&s=48" width="48" height="48" alt="dominicnunez" title="dominicnunez"/></a> <a href="https://github.com/lploc94"><img src="https://avatars.githubusercontent.com/u/28453843?v=4&s=48" width="48" height="48" alt="lploc94" title="lploc94"/></a> <a href="https://github.com/ratulsarna"><img src="https://avatars.githubusercontent.com/u/105903728?v=4&s=48" width="48" height="48" alt="ratulsarna" title="ratulsarna"/></a> <a href="https://github.com/sfo2001"><img src="https://avatars.githubusercontent.com/u/103369858?v=4&s=48" width="48" height="48" alt="sfo2001" title="sfo2001"/></a> <a href="https://github.com/lutr0"><img src="https://avatars.githubusercontent.com/u/76906369?v=4&s=48" width="48" height="48" alt="lutr0" title="lutr0"/></a> <a href="https://github.com/kiranjd"><img src="https://avatars.githubusercontent.com/u/25822851?v=4&s=48" width="48" height="48" alt="kiranjd" title="kiranjd"/></a> <a href="https://github.com/danielz1z"><img src="https://avatars.githubusercontent.com/u/235270390?v=4&s=48" width="48" height="48" alt="danielz1z" title="danielz1z"/></a> <a href="https://github.com/Iranb"><img src="https://avatars.githubusercontent.com/u/49674669?v=4&s=48" width="48" height="48" alt="Iranb" title="Iranb"/></a>
<a href="https://github.com/AdeboyeDN"><img src="https://avatars.githubusercontent.com/u/65312338?v=4&s=48" width="48" height="48" alt="AdeboyeDN" title="AdeboyeDN"/></a> <a href="https://github.com/Alg0rix"><img src="https://avatars.githubusercontent.com/u/53804949?v=4&s=48" width="48" height="48" alt="Alg0rix" title="Alg0rix"/></a> <a href="https://github.com/obviyus"><img src="https://avatars.githubusercontent.com/u/22031114?v=4&s=48" width="48" height="48" alt="obviyus" title="obviyus"/></a> <a href="https://github.com/papago2355"><img src="https://avatars.githubusercontent.com/u/68721273?v=4&s=48" width="48" height="48" alt="papago2355" title="papago2355"/></a> <a href="https://github.com/emanuelst"><img src="https://avatars.githubusercontent.com/u/9994339?v=4&s=48" width="48" height="48" alt="emanuelst" title="emanuelst"/></a> <a href="https://github.com/evanotero"><img src="https://avatars.githubusercontent.com/u/13204105?v=4&s=48" width="48" height="48" alt="evanotero" title="evanotero"/></a> <a href="https://github.com/KristijanJovanovski"><img src="https://avatars.githubusercontent.com/u/8942284?v=4&s=48" width="48" height="48" alt="KristijanJovanovski" title="KristijanJovanovski"/></a> <a href="https://github.com/jlowin"><img src="https://avatars.githubusercontent.com/u/153965?v=4&s=48" width="48" height="48" alt="jlowin" title="jlowin"/></a> <a href="https://github.com/rdev"><img src="https://avatars.githubusercontent.com/u/8418866?v=4&s=48" width="48" height="48" alt="rdev" title="rdev"/></a> <a href="https://github.com/rhuanssauro"><img src="https://avatars.githubusercontent.com/u/164682191?v=4&s=48" width="48" height="48" alt="rhuanssauro" title="rhuanssauro"/></a>
<a href="https://github.com/joshrad-dev"><img src="https://avatars.githubusercontent.com/u/62785552?v=4&s=48" width="48" height="48" alt="joshrad-dev" title="joshrad-dev"/></a> <a href="https://github.com/osolmaz"><img src="https://avatars.githubusercontent.com/u/2453968?v=4&s=48" width="48" height="48" alt="osolmaz" title="osolmaz"/></a> <a href="https://github.com/adityashaw2"><img src="https://avatars.githubusercontent.com/u/41204444?v=4&s=48" width="48" height="48" alt="adityashaw2" title="adityashaw2"/></a> <a href="https://github.com/CashWilliams"><img src="https://avatars.githubusercontent.com/u/613573?v=4&s=48" width="48" height="48" alt="CashWilliams" title="CashWilliams"/></a> <a href="https://github.com/search?q=sheeek"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="sheeek" title="sheeek"/></a> <a href="https://github.com/ryancontent"><img src="https://avatars.githubusercontent.com/u/39743613?v=4&s=48" width="48" height="48" alt="ryancontent" title="ryancontent"/></a> <a href="https://github.com/jasonsschin"><img src="https://avatars.githubusercontent.com/u/1456889?v=4&s=48" width="48" height="48" alt="jasonsschin" title="jasonsschin"/></a> <a href="https://github.com/artuskg"><img src="https://avatars.githubusercontent.com/u/11966157?v=4&s=48" width="48" height="48" alt="artuskg" title="artuskg"/></a> <a href="https://github.com/onutc"><img src="https://avatars.githubusercontent.com/u/152018508?v=4&s=48" width="48" height="48" alt="onutc" title="onutc"/></a> <a href="https://github.com/pauloportella"><img src="https://avatars.githubusercontent.com/u/22947229?v=4&s=48" width="48" height="48" alt="pauloportella" title="pauloportella"/></a>
<a href="https://github.com/HirokiKobayashi-R"><img src="https://avatars.githubusercontent.com/u/37167840?v=4&s=48" width="48" height="48" alt="HirokiKobayashi-R" title="HirokiKobayashi-R"/></a> <a href="https://github.com/ThanhNguyxn"><img src="https://avatars.githubusercontent.com/u/74597207?v=4&s=48" width="48" height="48" alt="ThanhNguyxn" title="ThanhNguyxn"/></a> <a href="https://github.com/kimitaka"><img src="https://avatars.githubusercontent.com/u/167225?v=4&s=48" width="48" height="48" alt="kimitaka" title="kimitaka"/></a> <a href="https://github.com/yuting0624"><img src="https://avatars.githubusercontent.com/u/32728916?v=4&s=48" width="48" height="48" alt="yuting0624" title="yuting0624"/></a> <a href="https://github.com/neooriginal"><img src="https://avatars.githubusercontent.com/u/54811660?v=4&s=48" width="48" height="48" alt="neooriginal" title="neooriginal"/></a> <a href="https://github.com/ManuelHettich"><img src="https://avatars.githubusercontent.com/u/17690367?v=4&s=48" width="48" height="48" alt="manuelhettich" title="manuelhettich"/></a> <a href="https://github.com/minghinmatthewlam"><img src="https://avatars.githubusercontent.com/u/14224566?v=4&s=48" width="48" height="48" alt="minghinmatthewlam" title="minghinmatthewlam"/></a> <a href="https://github.com/baccula"><img src="https://avatars.githubusercontent.com/u/22080883?v=4&s=48" width="48" height="48" alt="baccula" title="baccula"/></a> <a href="https://github.com/manikv12"><img src="https://avatars.githubusercontent.com/u/49544491?v=4&s=48" width="48" height="48" alt="manikv12" title="manikv12"/></a> <a href="https://github.com/myfunc"><img src="https://avatars.githubusercontent.com/u/19294627?v=4&s=48" width="48" height="48" alt="myfunc" title="myfunc"/></a>
<a href="https://github.com/travisirby"><img src="https://avatars.githubusercontent.com/u/5958376?v=4&s=48" width="48" height="48" alt="travisirby" title="travisirby"/></a> <a href="https://github.com/buddyh"><img src="https://avatars.githubusercontent.com/u/31752869?v=4&s=48" width="48" height="48" alt="buddyh" title="buddyh"/></a> <a href="https://github.com/connorshea"><img src="https://avatars.githubusercontent.com/u/2977353?v=4&s=48" width="48" height="48" alt="connorshea" title="connorshea"/></a> <a href="https://github.com/bjesuiter"><img src="https://avatars.githubusercontent.com/u/2365676?v=4&s=48" width="48" height="48" alt="bjesuiter" title="bjesuiter"/></a> <a href="https://github.com/kyleok"><img src="https://avatars.githubusercontent.com/u/58307870?v=4&s=48" width="48" height="48" alt="kyleok" title="kyleok"/></a> <a href="https://github.com/mcinteerj"><img src="https://avatars.githubusercontent.com/u/3613653?v=4&s=48" width="48" height="48" alt="mcinteerj" title="mcinteerj"/></a> <a href="https://github.com/badlogic"><img src="https://avatars.githubusercontent.com/u/514052?v=4&s=48" width="48" height="48" alt="badlogic" title="badlogic"/></a> <a href="https://github.com/apps/dependabot"><img src="https://avatars.githubusercontent.com/in/29110?v=4&s=48" width="48" height="48" alt="dependabot[bot]" title="dependabot[bot]"/></a> <a href="https://github.com/amitbiswal007"><img src="https://avatars.githubusercontent.com/u/108086198?v=4&s=48" width="48" height="48" alt="amitbiswal007" title="amitbiswal007"/></a> <a href="https://github.com/John-Rood"><img src="https://avatars.githubusercontent.com/u/62669593?v=4&s=48" width="48" height="48" alt="John-Rood" title="John-Rood"/></a>
<a href="https://github.com/timkrase"><img src="https://avatars.githubusercontent.com/u/38947626?v=4&s=48" width="48" height="48" alt="timkrase" title="timkrase"/></a> <a href="https://github.com/uos-status"><img src="https://avatars.githubusercontent.com/u/255712580?v=4&s=48" width="48" height="48" alt="uos-status" title="uos-status"/></a> <a href="https://github.com/gerardward2007"><img src="https://avatars.githubusercontent.com/u/3002155?v=4&s=48" width="48" height="48" alt="gerardward2007" title="gerardward2007"/></a> <a href="https://github.com/roshanasingh4"><img src="https://avatars.githubusercontent.com/u/88576930?v=4&s=48" width="48" height="48" alt="roshanasingh4" title="roshanasingh4"/></a> <a href="https://github.com/tosh-hamburg"><img src="https://avatars.githubusercontent.com/u/58424326?v=4&s=48" width="48" height="48" alt="tosh-hamburg" title="tosh-hamburg"/></a> <a href="https://github.com/azade-c"><img src="https://avatars.githubusercontent.com/u/252790079?v=4&s=48" width="48" height="48" alt="azade-c" title="azade-c"/></a> <a href="https://github.com/dlauer"><img src="https://avatars.githubusercontent.com/u/757041?v=4&s=48" width="48" height="48" alt="dlauer" title="dlauer"/></a> <a href="https://github.com/JonUleis"><img src="https://avatars.githubusercontent.com/u/7644941?v=4&s=48" width="48" height="48" alt="JonUleis" title="JonUleis"/></a> <a href="https://github.com/shivamraut101"><img src="https://avatars.githubusercontent.com/u/110457469?v=4&s=48" width="48" height="48" alt="shivamraut101" title="shivamraut101"/></a> <a href="https://github.com/cheeeee"><img src="https://avatars.githubusercontent.com/u/21245729?v=4&s=48" width="48" height="48" alt="cheeeee" title="cheeeee"/></a>
<a href="https://github.com/robbyczgw-cla"><img src="https://avatars.githubusercontent.com/u/239660374?v=4&s=48" width="48" height="48" alt="robbyczgw-cla" title="robbyczgw-cla"/></a> <a href="https://github.com/YuriNachos"><img src="https://avatars.githubusercontent.com/u/19365375?v=4&s=48" width="48" height="48" alt="YuriNachos" title="YuriNachos"/></a> <a href="https://github.com/j1philli"><img src="https://avatars.githubusercontent.com/u/3744255?v=4&s=48" width="48" height="48" alt="Josh Phillips" title="Josh Phillips"/></a> <a href="https://github.com/Wangnov"><img src="https://avatars.githubusercontent.com/u/48670012?v=4&s=48" width="48" height="48" alt="Wangnov" title="Wangnov"/></a> <a href="https://github.com/kaizen403"><img src="https://avatars.githubusercontent.com/u/134706404?v=4&s=48" width="48" height="48" alt="kaizen403" title="kaizen403"/></a> <a href="https://github.com/pookNast"><img src="https://avatars.githubusercontent.com/u/14242552?v=4&s=48" width="48" height="48" alt="pookNast" title="pookNast"/></a> <a href="https://github.com/Whoaa512"><img src="https://avatars.githubusercontent.com/u/1581943?v=4&s=48" width="48" height="48" alt="Whoaa512" title="Whoaa512"/></a> <a href="https://github.com/chriseidhof"><img src="https://avatars.githubusercontent.com/u/5382?v=4&s=48" width="48" height="48" alt="chriseidhof" title="chriseidhof"/></a> <a href="https://github.com/ngutman"><img src="https://avatars.githubusercontent.com/u/1540134?v=4&s=48" width="48" height="48" alt="ngutman" title="ngutman"/></a> <a href="https://github.com/ysqander"><img src="https://avatars.githubusercontent.com/u/80843820?v=4&s=48" width="48" height="48" alt="ysqander" title="ysqander"/></a>
<a href="https://github.com/search?q=Yurii%20Chukhlib"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Yurii Chukhlib" title="Yurii Chukhlib"/></a> <a href="https://github.com/aj47"><img src="https://avatars.githubusercontent.com/u/8023513?v=4&s=48" width="48" height="48" alt="aj47" title="aj47"/></a> <a href="https://github.com/kennyklee"><img src="https://avatars.githubusercontent.com/u/1432489?v=4&s=48" width="48" height="48" alt="kennyklee" title="kennyklee"/></a> <a href="https://github.com/superman32432432"><img src="https://avatars.githubusercontent.com/u/7228420?v=4&s=48" width="48" height="48" alt="superman32432432" title="superman32432432"/></a> <a href="https://github.com/grp06"><img src="https://avatars.githubusercontent.com/u/1573959?v=4&s=48" width="48" height="48" alt="grp06" title="grp06"/></a> <a href="https://github.com/Hisleren"><img src="https://avatars.githubusercontent.com/u/83217244?v=4&s=48" width="48" height="48" alt="Hisleren" title="Hisleren"/></a> <a href="https://github.com/shatner"><img src="https://avatars.githubusercontent.com/u/17735435?v=4&s=48" width="48" height="48" alt="shatner" title="shatner"/></a> <a href="https://github.com/antons"><img src="https://avatars.githubusercontent.com/u/129705?v=4&s=48" width="48" height="48" alt="antons" title="antons"/></a> <a href="https://github.com/austinm911"><img src="https://avatars.githubusercontent.com/u/31991302?v=4&s=48" width="48" height="48" alt="austinm911" title="austinm911"/></a> <a href="https://github.com/apps/blacksmith-sh"><img src="https://avatars.githubusercontent.com/in/807020?v=4&s=48" width="48" height="48" alt="blacksmith-sh[bot]" title="blacksmith-sh[bot]"/></a>
<a href="https://github.com/damoahdominic"><img src="https://avatars.githubusercontent.com/u/4623434?v=4&s=48" width="48" height="48" alt="damoahdominic" title="damoahdominic"/></a> <a href="https://github.com/dan-dr"><img src="https://avatars.githubusercontent.com/u/6669808?v=4&s=48" width="48" height="48" alt="dan-dr" title="dan-dr"/></a> <a href="https://github.com/GHesericsu"><img src="https://avatars.githubusercontent.com/u/60202455?v=4&s=48" width="48" height="48" alt="GHesericsu" title="GHesericsu"/></a> <a href="https://github.com/HeimdallStrategy"><img src="https://avatars.githubusercontent.com/u/223014405?v=4&s=48" width="48" height="48" alt="HeimdallStrategy" title="HeimdallStrategy"/></a> <a href="https://github.com/imfing"><img src="https://avatars.githubusercontent.com/u/5097752?v=4&s=48" width="48" height="48" alt="imfing" title="imfing"/></a> <a href="https://github.com/jalehman"><img src="https://avatars.githubusercontent.com/u/550978?v=4&s=48" width="48" height="48" alt="jalehman" title="jalehman"/></a> <a href="https://github.com/jarvis-medmatic"><img src="https://avatars.githubusercontent.com/u/252428873?v=4&s=48" width="48" height="48" alt="jarvis-medmatic" title="jarvis-medmatic"/></a> <a href="https://github.com/kkarimi"><img src="https://avatars.githubusercontent.com/u/875218?v=4&s=48" width="48" height="48" alt="kkarimi" title="kkarimi"/></a> <a href="https://github.com/Lukavyi"><img src="https://avatars.githubusercontent.com/u/1013690?v=4&s=48" width="48" height="48" alt="Lukavyi" title="Lukavyi"/></a> <a href="https://github.com/mahmoudashraf93"><img src="https://avatars.githubusercontent.com/u/9130129?v=4&s=48" width="48" height="48" alt="mahmoudashraf93" title="mahmoudashraf93"/></a>
<a href="https://github.com/pkrmf"><img src="https://avatars.githubusercontent.com/u/1714267?v=4&s=48" width="48" height="48" alt="pkrmf" title="pkrmf"/></a> <a href="https://github.com/RandyVentures"><img src="https://avatars.githubusercontent.com/u/149904821?v=4&s=48" width="48" height="48" alt="RandyVentures" title="RandyVentures"/></a> <a href="https://github.com/robhparker"><img src="https://avatars.githubusercontent.com/u/7404740?v=4&s=48" width="48" height="48" alt="robhparker" title="robhparker"/></a> <a href="https://github.com/search?q=Ryan%20Lisse"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Ryan Lisse" title="Ryan Lisse"/></a> <a href="https://github.com/Yeom-JinHo"><img src="https://avatars.githubusercontent.com/u/81306489?v=4&s=48" width="48" height="48" alt="Yeom-JinHo" title="Yeom-JinHo"/></a> <a href="https://github.com/dougvk"><img src="https://avatars.githubusercontent.com/u/401660?v=4&s=48" width="48" height="48" alt="dougvk" title="dougvk"/></a> <a href="https://github.com/erikpr1994"><img src="https://avatars.githubusercontent.com/u/6299331?v=4&s=48" width="48" height="48" alt="erikpr1994" title="erikpr1994"/></a> <a href="https://github.com/fal3"><img src="https://avatars.githubusercontent.com/u/6484295?v=4&s=48" width="48" height="48" alt="fal3" title="fal3"/></a> <a href="https://github.com/search?q=Ghost"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Ghost" title="Ghost"/></a> <a href="https://github.com/jonasjancarik"><img src="https://avatars.githubusercontent.com/u/2459191?v=4&s=48" width="48" height="48" alt="jonasjancarik" title="jonasjancarik"/></a>
<a href="https://github.com/search?q=Keith%20the%20Silly%20Goose"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Keith the Silly Goose" title="Keith the Silly Goose"/></a> <a href="https://github.com/search?q=L36%20Server"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="L36 Server" title="L36 Server"/></a> <a href="https://github.com/search?q=Marc"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Marc" title="Marc"/></a> <a href="https://github.com/mitschabaude-bot"><img src="https://avatars.githubusercontent.com/u/247582884?v=4&s=48" width="48" height="48" alt="mitschabaude-bot" title="mitschabaude-bot"/></a> <a href="https://github.com/mkbehr"><img src="https://avatars.githubusercontent.com/u/1285?v=4&s=48" width="48" height="48" alt="mkbehr" title="mkbehr"/></a> <a href="https://github.com/neist"><img src="https://avatars.githubusercontent.com/u/1029724?v=4&s=48" width="48" height="48" alt="neist" title="neist"/></a> <a href="https://github.com/sibbl"><img src="https://avatars.githubusercontent.com/u/866535?v=4&s=48" width="48" height="48" alt="sibbl" title="sibbl"/></a> <a href="https://github.com/abhijeet117"><img src="https://avatars.githubusercontent.com/u/192859219?v=4&s=48" width="48" height="48" alt="abhijeet117" title="abhijeet117"/></a> <a href="https://github.com/chrisrodz"><img src="https://avatars.githubusercontent.com/u/2967620?v=4&s=48" width="48" height="48" alt="chrisrodz" title="chrisrodz"/></a> <a href="https://github.com/search?q=Friederike%20Seiler"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Friederike Seiler" title="Friederike Seiler"/></a>
<a href="https://github.com/gabriel-trigo"><img src="https://avatars.githubusercontent.com/u/38991125?v=4&s=48" width="48" height="48" alt="gabriel-trigo" title="gabriel-trigo"/></a> <a href="https://github.com/Iamadig"><img src="https://avatars.githubusercontent.com/u/102129234?v=4&s=48" width="48" height="48" alt="iamadig" title="iamadig"/></a> <a href="https://github.com/itsjling"><img src="https://avatars.githubusercontent.com/u/2521993?v=4&s=48" width="48" height="48" alt="itsjling" title="itsjling"/></a> <a href="https://github.com/jdrhyne"><img src="https://avatars.githubusercontent.com/u/7828464?v=4&s=48" width="48" height="48" alt="Jonathan D. Rhyne (DJ-D)" title="Jonathan D. Rhyne (DJ-D)"/></a> <a href="https://github.com/search?q=Joshua%20Mitchell"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Joshua Mitchell" title="Joshua Mitchell"/></a> <a href="https://github.com/kelvinCB"><img src="https://avatars.githubusercontent.com/u/50544379?v=4&s=48" width="48" height="48" alt="kelvinCB" title="kelvinCB"/></a> <a href="https://github.com/search?q=Kit"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Kit" title="Kit"/></a> <a href="https://github.com/koala73"><img src="https://avatars.githubusercontent.com/u/996596?v=4&s=48" width="48" height="48" alt="koala73" title="koala73"/></a> <a href="https://github.com/manmal"><img src="https://avatars.githubusercontent.com/u/142797?v=4&s=48" width="48" height="48" alt="manmal" title="manmal"/></a> <a href="https://github.com/mitsuhiko"><img src="https://avatars.githubusercontent.com/u/7396?v=4&s=48" width="48" height="48" alt="mitsuhiko" title="mitsuhiko"/></a>
<a href="https://github.com/ogulcancelik"><img src="https://avatars.githubusercontent.com/u/7064011?v=4&s=48" width="48" height="48" alt="ogulcancelik" title="ogulcancelik"/></a> <a href="https://github.com/pasogott"><img src="https://avatars.githubusercontent.com/u/23458152?v=4&s=48" width="48" height="48" alt="pasogott" title="pasogott"/></a> <a href="https://github.com/petradonka"><img src="https://avatars.githubusercontent.com/u/7353770?v=4&s=48" width="48" height="48" alt="petradonka" title="petradonka"/></a> <a href="https://github.com/rubyrunsstuff"><img src="https://avatars.githubusercontent.com/u/246602379?v=4&s=48" width="48" height="48" alt="rubyrunsstuff" title="rubyrunsstuff"/></a> <a href="https://github.com/siddhantjain"><img src="https://avatars.githubusercontent.com/u/4835232?v=4&s=48" width="48" height="48" alt="siddhantjain" title="siddhantjain"/></a> <a href="https://github.com/spiceoogway"><img src="https://avatars.githubusercontent.com/u/105812383?v=4&s=48" width="48" height="48" alt="spiceoogway" title="spiceoogway"/></a> <a href="https://github.com/suminhthanh"><img src="https://avatars.githubusercontent.com/u/2907636?v=4&s=48" width="48" height="48" alt="suminhthanh" title="suminhthanh"/></a> <a href="https://github.com/svkozak"><img src="https://avatars.githubusercontent.com/u/31941359?v=4&s=48" width="48" height="48" alt="svkozak" title="svkozak"/></a> <a href="https://github.com/wes-davis"><img src="https://avatars.githubusercontent.com/u/16506720?v=4&s=48" width="48" height="48" alt="wes-davis" title="wes-davis"/></a> <a href="https://github.com/zats"><img src="https://avatars.githubusercontent.com/u/2688806?v=4&s=48" width="48" height="48" alt="zats" title="zats"/></a>
<a href="https://github.com/24601"><img src="https://avatars.githubusercontent.com/u/1157207?v=4&s=48" width="48" height="48" alt="24601" title="24601"/></a> <a href="https://github.com/ameno-"><img src="https://avatars.githubusercontent.com/u/2416135?v=4&s=48" width="48" height="48" alt="ameno-" title="ameno-"/></a> <a href="https://github.com/bonald"><img src="https://avatars.githubusercontent.com/u/12394874?v=4&s=48" width="48" height="48" alt="bonald" title="bonald"/></a> <a href="https://github.com/bravostation"><img src="https://avatars.githubusercontent.com/u/257991910?v=4&s=48" width="48" height="48" alt="bravostation" title="bravostation"/></a> <a href="https://github.com/search?q=Chris%20Taylor"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Chris Taylor" title="Chris Taylor"/></a> <a href="https://github.com/dguido"><img src="https://avatars.githubusercontent.com/u/294844?v=4&s=48" width="48" height="48" alt="dguido" title="dguido"/></a> <a href="https://github.com/djangonavarro220"><img src="https://avatars.githubusercontent.com/u/251162586?v=4&s=48" width="48" height="48" alt="Django Navarro" title="Django Navarro"/></a> <a href="https://github.com/evalexpr"><img src="https://avatars.githubusercontent.com/u/23485511?v=4&s=48" width="48" height="48" alt="evalexpr" title="evalexpr"/></a> <a href="https://github.com/henrino3"><img src="https://avatars.githubusercontent.com/u/4260288?v=4&s=48" width="48" height="48" alt="henrino3" title="henrino3"/></a> <a href="https://github.com/humanwritten"><img src="https://avatars.githubusercontent.com/u/206531610?v=4&s=48" width="48" height="48" alt="humanwritten" title="humanwritten"/></a>
<a href="https://github.com/HirokiKobayashi-R"><img src="https://avatars.githubusercontent.com/u/37167840?v=4&s=48" width="48" height="48" alt="HirokiKobayashi-R" title="HirokiKobayashi-R"/></a> <a href="https://github.com/ThanhNguyxn"><img src="https://avatars.githubusercontent.com/u/74597207?v=4&s=48" width="48" height="48" alt="ThanhNguyxn" title="ThanhNguyxn"/></a> <a href="https://github.com/18-RAJAT"><img src="https://avatars.githubusercontent.com/u/78920780?v=4&s=48" width="48" height="48" alt="18-RAJAT" title="18-RAJAT"/></a> <a href="https://github.com/kimitaka"><img src="https://avatars.githubusercontent.com/u/167225?v=4&s=48" width="48" height="48" alt="kimitaka" title="kimitaka"/></a> <a href="https://github.com/yuting0624"><img src="https://avatars.githubusercontent.com/u/32728916?v=4&s=48" width="48" height="48" alt="yuting0624" title="yuting0624"/></a> <a href="https://github.com/neooriginal"><img src="https://avatars.githubusercontent.com/u/54811660?v=4&s=48" width="48" height="48" alt="neooriginal" title="neooriginal"/></a> <a href="https://github.com/ManuelHettich"><img src="https://avatars.githubusercontent.com/u/17690367?v=4&s=48" width="48" height="48" alt="manuelhettich" title="manuelhettich"/></a> <a href="https://github.com/minghinmatthewlam"><img src="https://avatars.githubusercontent.com/u/14224566?v=4&s=48" width="48" height="48" alt="minghinmatthewlam" title="minghinmatthewlam"/></a> <a href="https://github.com/unisone"><img src="https://avatars.githubusercontent.com/u/32521398?v=4&s=48" width="48" height="48" alt="unisone" title="unisone"/></a> <a href="https://github.com/baccula"><img src="https://avatars.githubusercontent.com/u/22080883?v=4&s=48" width="48" height="48" alt="baccula" title="baccula"/></a>
<a href="https://github.com/manikv12"><img src="https://avatars.githubusercontent.com/u/49544491?v=4&s=48" width="48" height="48" alt="manikv12" title="manikv12"/></a> <a href="https://github.com/myfunc"><img src="https://avatars.githubusercontent.com/u/19294627?v=4&s=48" width="48" height="48" alt="myfunc" title="myfunc"/></a> <a href="https://github.com/travisirby"><img src="https://avatars.githubusercontent.com/u/5958376?v=4&s=48" width="48" height="48" alt="travisirby" title="travisirby"/></a> <a href="https://github.com/fujiwara-tofu-shop"><img src="https://avatars.githubusercontent.com/u/259415332?v=4&s=48" width="48" height="48" alt="fujiwara-tofu-shop" title="fujiwara-tofu-shop"/></a> <a href="https://github.com/buddyh"><img src="https://avatars.githubusercontent.com/u/31752869?v=4&s=48" width="48" height="48" alt="buddyh" title="buddyh"/></a> <a href="https://github.com/connorshea"><img src="https://avatars.githubusercontent.com/u/2977353?v=4&s=48" width="48" height="48" alt="connorshea" title="connorshea"/></a> <a href="https://github.com/bjesuiter"><img src="https://avatars.githubusercontent.com/u/2365676?v=4&s=48" width="48" height="48" alt="bjesuiter" title="bjesuiter"/></a> <a href="https://github.com/kyleok"><img src="https://avatars.githubusercontent.com/u/58307870?v=4&s=48" width="48" height="48" alt="kyleok" title="kyleok"/></a> <a href="https://github.com/slonce70"><img src="https://avatars.githubusercontent.com/u/130596182?v=4&s=48" width="48" height="48" alt="slonce70" title="slonce70"/></a> <a href="https://github.com/mcinteerj"><img src="https://avatars.githubusercontent.com/u/3613653?v=4&s=48" width="48" height="48" alt="mcinteerj" title="mcinteerj"/></a>
<a href="https://github.com/badlogic"><img src="https://avatars.githubusercontent.com/u/514052?v=4&s=48" width="48" height="48" alt="badlogic" title="badlogic"/></a> <a href="https://github.com/apps/dependabot"><img src="https://avatars.githubusercontent.com/in/29110?v=4&s=48" width="48" height="48" alt="dependabot[bot]" title="dependabot[bot]"/></a> <a href="https://github.com/amitbiswal007"><img src="https://avatars.githubusercontent.com/u/108086198?v=4&s=48" width="48" height="48" alt="amitbiswal007" title="amitbiswal007"/></a> <a href="https://github.com/John-Rood"><img src="https://avatars.githubusercontent.com/u/62669593?v=4&s=48" width="48" height="48" alt="John-Rood" title="John-Rood"/></a> <a href="https://github.com/timkrase"><img src="https://avatars.githubusercontent.com/u/38947626?v=4&s=48" width="48" height="48" alt="timkrase" title="timkrase"/></a> <a href="https://github.com/uos-status"><img src="https://avatars.githubusercontent.com/u/255712580?v=4&s=48" width="48" height="48" alt="uos-status" title="uos-status"/></a> <a href="https://github.com/gerardward2007"><img src="https://avatars.githubusercontent.com/u/3002155?v=4&s=48" width="48" height="48" alt="gerardward2007" title="gerardward2007"/></a> <a href="https://github.com/roshanasingh4"><img src="https://avatars.githubusercontent.com/u/88576930?v=4&s=48" width="48" height="48" alt="roshanasingh4" title="roshanasingh4"/></a> <a href="https://github.com/tosh-hamburg"><img src="https://avatars.githubusercontent.com/u/58424326?v=4&s=48" width="48" height="48" alt="tosh-hamburg" title="tosh-hamburg"/></a> <a href="https://github.com/azade-c"><img src="https://avatars.githubusercontent.com/u/252790079?v=4&s=48" width="48" height="48" alt="azade-c" title="azade-c"/></a>
<a href="https://github.com/dlauer"><img src="https://avatars.githubusercontent.com/u/757041?v=4&s=48" width="48" height="48" alt="dlauer" title="dlauer"/></a> <a href="https://github.com/grp06"><img src="https://avatars.githubusercontent.com/u/1573959?v=4&s=48" width="48" height="48" alt="grp06" title="grp06"/></a> <a href="https://github.com/JonUleis"><img src="https://avatars.githubusercontent.com/u/7644941?v=4&s=48" width="48" height="48" alt="JonUleis" title="JonUleis"/></a> <a href="https://github.com/shivamraut101"><img src="https://avatars.githubusercontent.com/u/110457469?v=4&s=48" width="48" height="48" alt="shivamraut101" title="shivamraut101"/></a> <a href="https://github.com/cheeeee"><img src="https://avatars.githubusercontent.com/u/21245729?v=4&s=48" width="48" height="48" alt="cheeeee" title="cheeeee"/></a> <a href="https://github.com/robbyczgw-cla"><img src="https://avatars.githubusercontent.com/u/239660374?v=4&s=48" width="48" height="48" alt="robbyczgw-cla" title="robbyczgw-cla"/></a> <a href="https://github.com/YuriNachos"><img src="https://avatars.githubusercontent.com/u/19365375?v=4&s=48" width="48" height="48" alt="YuriNachos" title="YuriNachos"/></a> <a href="https://github.com/j1philli"><img src="https://avatars.githubusercontent.com/u/3744255?v=4&s=48" width="48" height="48" alt="Josh Phillips" title="Josh Phillips"/></a> <a href="https://github.com/Wangnov"><img src="https://avatars.githubusercontent.com/u/48670012?v=4&s=48" width="48" height="48" alt="Wangnov" title="Wangnov"/></a> <a href="https://github.com/kaizen403"><img src="https://avatars.githubusercontent.com/u/134706404?v=4&s=48" width="48" height="48" alt="kaizen403" title="kaizen403"/></a>
<a href="https://github.com/pookNast"><img src="https://avatars.githubusercontent.com/u/14242552?v=4&s=48" width="48" height="48" alt="pookNast" title="pookNast"/></a> <a href="https://github.com/Whoaa512"><img src="https://avatars.githubusercontent.com/u/1581943?v=4&s=48" width="48" height="48" alt="Whoaa512" title="Whoaa512"/></a> <a href="https://github.com/chriseidhof"><img src="https://avatars.githubusercontent.com/u/5382?v=4&s=48" width="48" height="48" alt="chriseidhof" title="chriseidhof"/></a> <a href="https://github.com/ngutman"><img src="https://avatars.githubusercontent.com/u/1540134?v=4&s=48" width="48" height="48" alt="ngutman" title="ngutman"/></a> <a href="https://github.com/therealZpoint-bot"><img src="https://avatars.githubusercontent.com/u/258706705?v=4&s=48" width="48" height="48" alt="therealZpoint-bot" title="therealZpoint-bot"/></a> <a href="https://github.com/wangai-studio"><img src="https://avatars.githubusercontent.com/u/256938352?v=4&s=48" width="48" height="48" alt="wangai-studio" title="wangai-studio"/></a> <a href="https://github.com/ysqander"><img src="https://avatars.githubusercontent.com/u/80843820?v=4&s=48" width="48" height="48" alt="ysqander" title="ysqander"/></a> <a href="https://github.com/search?q=Yurii%20Chukhlib"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Yurii Chukhlib" title="Yurii Chukhlib"/></a> <a href="https://github.com/aj47"><img src="https://avatars.githubusercontent.com/u/8023513?v=4&s=48" width="48" height="48" alt="aj47" title="aj47"/></a> <a href="https://github.com/kennyklee"><img src="https://avatars.githubusercontent.com/u/1432489?v=4&s=48" width="48" height="48" alt="kennyklee" title="kennyklee"/></a>
<a href="https://github.com/superman32432432"><img src="https://avatars.githubusercontent.com/u/7228420?v=4&s=48" width="48" height="48" alt="superman32432432" title="superman32432432"/></a> <a href="https://github.com/Hisleren"><img src="https://avatars.githubusercontent.com/u/83217244?v=4&s=48" width="48" height="48" alt="Hisleren" title="Hisleren"/></a> <a href="https://github.com/shatner"><img src="https://avatars.githubusercontent.com/u/17735435?v=4&s=48" width="48" height="48" alt="shatner" title="shatner"/></a> <a href="https://github.com/antons"><img src="https://avatars.githubusercontent.com/u/129705?v=4&s=48" width="48" height="48" alt="antons" title="antons"/></a> <a href="https://github.com/austinm911"><img src="https://avatars.githubusercontent.com/u/31991302?v=4&s=48" width="48" height="48" alt="austinm911" title="austinm911"/></a> <a href="https://github.com/apps/blacksmith-sh"><img src="https://avatars.githubusercontent.com/in/807020?v=4&s=48" width="48" height="48" alt="blacksmith-sh[bot]" title="blacksmith-sh[bot]"/></a> <a href="https://github.com/damoahdominic"><img src="https://avatars.githubusercontent.com/u/4623434?v=4&s=48" width="48" height="48" alt="damoahdominic" title="damoahdominic"/></a> <a href="https://github.com/dan-dr"><img src="https://avatars.githubusercontent.com/u/6669808?v=4&s=48" width="48" height="48" alt="dan-dr" title="dan-dr"/></a> <a href="https://github.com/GHesericsu"><img src="https://avatars.githubusercontent.com/u/60202455?v=4&s=48" width="48" height="48" alt="GHesericsu" title="GHesericsu"/></a> <a href="https://github.com/HeimdallStrategy"><img src="https://avatars.githubusercontent.com/u/223014405?v=4&s=48" width="48" height="48" alt="HeimdallStrategy" title="HeimdallStrategy"/></a>
<a href="https://github.com/imfing"><img src="https://avatars.githubusercontent.com/u/5097752?v=4&s=48" width="48" height="48" alt="imfing" title="imfing"/></a> <a href="https://github.com/jalehman"><img src="https://avatars.githubusercontent.com/u/550978?v=4&s=48" width="48" height="48" alt="jalehman" title="jalehman"/></a> <a href="https://github.com/jarvis-medmatic"><img src="https://avatars.githubusercontent.com/u/252428873?v=4&s=48" width="48" height="48" alt="jarvis-medmatic" title="jarvis-medmatic"/></a> <a href="https://github.com/kkarimi"><img src="https://avatars.githubusercontent.com/u/875218?v=4&s=48" width="48" height="48" alt="kkarimi" title="kkarimi"/></a> <a href="https://github.com/Lukavyi"><img src="https://avatars.githubusercontent.com/u/1013690?v=4&s=48" width="48" height="48" alt="Lukavyi" title="Lukavyi"/></a> <a href="https://github.com/mahmoudashraf93"><img src="https://avatars.githubusercontent.com/u/9130129?v=4&s=48" width="48" height="48" alt="mahmoudashraf93" title="mahmoudashraf93"/></a> <a href="https://github.com/pkrmf"><img src="https://avatars.githubusercontent.com/u/1714267?v=4&s=48" width="48" height="48" alt="pkrmf" title="pkrmf"/></a> <a href="https://github.com/RandyVentures"><img src="https://avatars.githubusercontent.com/u/149904821?v=4&s=48" width="48" height="48" alt="RandyVentures" title="RandyVentures"/></a> <a href="https://github.com/robhparker"><img src="https://avatars.githubusercontent.com/u/7404740?v=4&s=48" width="48" height="48" alt="robhparker" title="robhparker"/></a> <a href="https://github.com/search?q=Ryan%20Lisse"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Ryan Lisse" title="Ryan Lisse"/></a>
<a href="https://github.com/Yeom-JinHo"><img src="https://avatars.githubusercontent.com/u/81306489?v=4&s=48" width="48" height="48" alt="Yeom-JinHo" title="Yeom-JinHo"/></a> <a href="https://github.com/doodlewind"><img src="https://avatars.githubusercontent.com/u/7312949?v=4&s=48" width="48" height="48" alt="doodlewind" title="doodlewind"/></a> <a href="https://github.com/dougvk"><img src="https://avatars.githubusercontent.com/u/401660?v=4&s=48" width="48" height="48" alt="dougvk" title="dougvk"/></a> <a href="https://github.com/erikpr1994"><img src="https://avatars.githubusercontent.com/u/6299331?v=4&s=48" width="48" height="48" alt="erikpr1994" title="erikpr1994"/></a> <a href="https://github.com/fal3"><img src="https://avatars.githubusercontent.com/u/6484295?v=4&s=48" width="48" height="48" alt="fal3" title="fal3"/></a> <a href="https://github.com/search?q=Ghost"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Ghost" title="Ghost"/></a> <a href="https://github.com/hyf0-agent"><img src="https://avatars.githubusercontent.com/u/258783736?v=4&s=48" width="48" height="48" alt="hyf0-agent" title="hyf0-agent"/></a> <a href="https://github.com/jonasjancarik"><img src="https://avatars.githubusercontent.com/u/2459191?v=4&s=48" width="48" height="48" alt="jonasjancarik" title="jonasjancarik"/></a> <a href="https://github.com/search?q=Keith%20the%20Silly%20Goose"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Keith the Silly Goose" title="Keith the Silly Goose"/></a> <a href="https://github.com/search?q=L36%20Server"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="L36 Server" title="L36 Server"/></a>
<a href="https://github.com/search?q=Marc"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Marc" title="Marc"/></a> <a href="https://github.com/mitschabaude-bot"><img src="https://avatars.githubusercontent.com/u/247582884?v=4&s=48" width="48" height="48" alt="mitschabaude-bot" title="mitschabaude-bot"/></a> <a href="https://github.com/mkbehr"><img src="https://avatars.githubusercontent.com/u/1285?v=4&s=48" width="48" height="48" alt="mkbehr" title="mkbehr"/></a> <a href="https://github.com/neist"><img src="https://avatars.githubusercontent.com/u/1029724?v=4&s=48" width="48" height="48" alt="neist" title="neist"/></a> <a href="https://github.com/sibbl"><img src="https://avatars.githubusercontent.com/u/866535?v=4&s=48" width="48" height="48" alt="sibbl" title="sibbl"/></a> <a href="https://github.com/zats"><img src="https://avatars.githubusercontent.com/u/2688806?v=4&s=48" width="48" height="48" alt="zats" title="zats"/></a> <a href="https://github.com/abhijeet117"><img src="https://avatars.githubusercontent.com/u/192859219?v=4&s=48" width="48" height="48" alt="abhijeet117" title="abhijeet117"/></a> <a href="https://github.com/chrisrodz"><img src="https://avatars.githubusercontent.com/u/2967620?v=4&s=48" width="48" height="48" alt="chrisrodz" title="chrisrodz"/></a> <a href="https://github.com/search?q=Friederike%20Seiler"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Friederike Seiler" title="Friederike Seiler"/></a> <a href="https://github.com/gabriel-trigo"><img src="https://avatars.githubusercontent.com/u/38991125?v=4&s=48" width="48" height="48" alt="gabriel-trigo" title="gabriel-trigo"/></a>
<a href="https://github.com/Iamadig"><img src="https://avatars.githubusercontent.com/u/102129234?v=4&s=48" width="48" height="48" alt="iamadig" title="iamadig"/></a> <a href="https://github.com/itsjling"><img src="https://avatars.githubusercontent.com/u/2521993?v=4&s=48" width="48" height="48" alt="itsjling" title="itsjling"/></a> <a href="https://github.com/jdrhyne"><img src="https://avatars.githubusercontent.com/u/7828464?v=4&s=48" width="48" height="48" alt="Jonathan D. Rhyne (DJ-D)" title="Jonathan D. Rhyne (DJ-D)"/></a> <a href="https://github.com/search?q=Joshua%20Mitchell"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Joshua Mitchell" title="Joshua Mitchell"/></a> <a href="https://github.com/kelvinCB"><img src="https://avatars.githubusercontent.com/u/50544379?v=4&s=48" width="48" height="48" alt="kelvinCB" title="kelvinCB"/></a> <a href="https://github.com/search?q=Kit"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Kit" title="Kit"/></a> <a href="https://github.com/koala73"><img src="https://avatars.githubusercontent.com/u/996596?v=4&s=48" width="48" height="48" alt="koala73" title="koala73"/></a> <a href="https://github.com/manmal"><img src="https://avatars.githubusercontent.com/u/142797?v=4&s=48" width="48" height="48" alt="manmal" title="manmal"/></a> <a href="https://github.com/mattqdev"><img src="https://avatars.githubusercontent.com/u/115874885?v=4&s=48" width="48" height="48" alt="mattqdev" title="mattqdev"/></a> <a href="https://github.com/mitsuhiko"><img src="https://avatars.githubusercontent.com/u/7396?v=4&s=48" width="48" height="48" alt="mitsuhiko" title="mitsuhiko"/></a>
<a href="https://github.com/ogulcancelik"><img src="https://avatars.githubusercontent.com/u/7064011?v=4&s=48" width="48" height="48" alt="ogulcancelik" title="ogulcancelik"/></a> <a href="https://github.com/pasogott"><img src="https://avatars.githubusercontent.com/u/23458152?v=4&s=48" width="48" height="48" alt="pasogott" title="pasogott"/></a> <a href="https://github.com/petradonka"><img src="https://avatars.githubusercontent.com/u/7353770?v=4&s=48" width="48" height="48" alt="petradonka" title="petradonka"/></a> <a href="https://github.com/rubyrunsstuff"><img src="https://avatars.githubusercontent.com/u/246602379?v=4&s=48" width="48" height="48" alt="rubyrunsstuff" title="rubyrunsstuff"/></a> <a href="https://github.com/siddhantjain"><img src="https://avatars.githubusercontent.com/u/4835232?v=4&s=48" width="48" height="48" alt="siddhantjain" title="siddhantjain"/></a> <a href="https://github.com/spiceoogway"><img src="https://avatars.githubusercontent.com/u/105812383?v=4&s=48" width="48" height="48" alt="spiceoogway" title="spiceoogway"/></a> <a href="https://github.com/suminhthanh"><img src="https://avatars.githubusercontent.com/u/2907636?v=4&s=48" width="48" height="48" alt="suminhthanh" title="suminhthanh"/></a> <a href="https://github.com/svkozak"><img src="https://avatars.githubusercontent.com/u/31941359?v=4&s=48" width="48" height="48" alt="svkozak" title="svkozak"/></a> <a href="https://github.com/wes-davis"><img src="https://avatars.githubusercontent.com/u/16506720?v=4&s=48" width="48" height="48" alt="wes-davis" title="wes-davis"/></a> <a href="https://github.com/24601"><img src="https://avatars.githubusercontent.com/u/1157207?v=4&s=48" width="48" height="48" alt="24601" title="24601"/></a>
<a href="https://github.com/ameno-"><img src="https://avatars.githubusercontent.com/u/2416135?v=4&s=48" width="48" height="48" alt="ameno-" title="ameno-"/></a> <a href="https://github.com/bonald"><img src="https://avatars.githubusercontent.com/u/12394874?v=4&s=48" width="48" height="48" alt="bonald" title="bonald"/></a> <a href="https://github.com/bravostation"><img src="https://avatars.githubusercontent.com/u/257991910?v=4&s=48" width="48" height="48" alt="bravostation" title="bravostation"/></a> <a href="https://github.com/search?q=Chris%20Taylor"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Chris Taylor" title="Chris Taylor"/></a> <a href="https://github.com/dguido"><img src="https://avatars.githubusercontent.com/u/294844?v=4&s=48" width="48" height="48" alt="dguido" title="dguido"/></a> <a href="https://github.com/djangonavarro220"><img src="https://avatars.githubusercontent.com/u/251162586?v=4&s=48" width="48" height="48" alt="Django Navarro" title="Django Navarro"/></a> <a href="https://github.com/evalexpr"><img src="https://avatars.githubusercontent.com/u/23485511?v=4&s=48" width="48" height="48" alt="evalexpr" title="evalexpr"/></a> <a href="https://github.com/henrino3"><img src="https://avatars.githubusercontent.com/u/4260288?v=4&s=48" width="48" height="48" alt="henrino3" title="henrino3"/></a> <a href="https://github.com/humanwritten"><img src="https://avatars.githubusercontent.com/u/206531610?v=4&s=48" width="48" height="48" alt="humanwritten" title="humanwritten"/></a> <a href="https://github.com/j2h4u"><img src="https://avatars.githubusercontent.com/u/39818683?v=4&s=48" width="48" height="48" alt="j2h4u" title="j2h4u"/></a>
<a href="https://github.com/larlyssa"><img src="https://avatars.githubusercontent.com/u/13128869?v=4&s=48" width="48" height="48" alt="larlyssa" title="larlyssa"/></a> <a href="https://github.com/odysseus0"><img src="https://avatars.githubusercontent.com/u/8635094?v=4&s=48" width="48" height="48" alt="odysseus0" title="odysseus0"/></a> <a href="https://github.com/oswalpalash"><img src="https://avatars.githubusercontent.com/u/6431196?v=4&s=48" width="48" height="48" alt="oswalpalash" title="oswalpalash"/></a> <a href="https://github.com/pcty-nextgen-service-account"><img src="https://avatars.githubusercontent.com/u/112553441?v=4&s=48" width="48" height="48" alt="pcty-nextgen-service-account" title="pcty-nextgen-service-account"/></a> <a href="https://github.com/pi0"><img src="https://avatars.githubusercontent.com/u/5158436?v=4&s=48" width="48" height="48" alt="pi0" title="pi0"/></a> <a href="https://github.com/rmorse"><img src="https://avatars.githubusercontent.com/u/853547?v=4&s=48" width="48" height="48" alt="rmorse" title="rmorse"/></a> <a href="https://github.com/search?q=Roopak%20Nijhara"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Roopak Nijhara" title="Roopak Nijhara"/></a> <a href="https://github.com/Syhids"><img src="https://avatars.githubusercontent.com/u/671202?v=4&s=48" width="48" height="48" alt="Syhids" title="Syhids"/></a> <a href="https://github.com/search?q=Ubuntu"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Ubuntu" title="Ubuntu"/></a> <a href="https://github.com/search?q=xiaose"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="xiaose" title="xiaose"/></a>
<a href="https://github.com/search?q=Aaron%20Konyer"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Aaron Konyer" title="Aaron Konyer"/></a> <a href="https://github.com/aaronveklabs"><img src="https://avatars.githubusercontent.com/u/225997828?v=4&s=48" width="48" height="48" alt="aaronveklabs" title="aaronveklabs"/></a> <a href="https://github.com/aldoeliacim"><img src="https://avatars.githubusercontent.com/u/17973757?v=4&s=48" width="48" height="48" alt="aldoeliacim" title="aldoeliacim"/></a> <a href="https://github.com/andreabadesso"><img src="https://avatars.githubusercontent.com/u/3586068?v=4&s=48" width="48" height="48" alt="andreabadesso" title="andreabadesso"/></a> <a href="https://github.com/search?q=Andrii"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Andrii" title="Andrii"/></a> <a href="https://github.com/BinaryMuse"><img src="https://avatars.githubusercontent.com/u/189606?v=4&s=48" width="48" height="48" alt="BinaryMuse" title="BinaryMuse"/></a> <a href="https://github.com/bqcfjwhz85-arch"><img src="https://avatars.githubusercontent.com/u/239267175?v=4&s=48" width="48" height="48" alt="bqcfjwhz85-arch" title="bqcfjwhz85-arch"/></a> <a href="https://github.com/cash-echo-bot"><img src="https://avatars.githubusercontent.com/u/252747386?v=4&s=48" width="48" height="48" alt="cash-echo-bot" title="cash-echo-bot"/></a> <a href="https://github.com/search?q=Clawd"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Clawd" title="Clawd"/></a> <a href="https://github.com/search?q=ClawdFx"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="ClawdFx" title="ClawdFx"/></a>
<a href="https://github.com/search?q=damaozi"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="damaozi" title="damaozi"/></a> <a href="https://github.com/danballance"><img src="https://avatars.githubusercontent.com/u/13839912?v=4&s=48" width="48" height="48" alt="danballance" title="danballance"/></a> <a href="https://github.com/Elarwei001"><img src="https://avatars.githubusercontent.com/u/168552401?v=4&s=48" width="48" height="48" alt="Elarwei001" title="Elarwei001"/></a> <a href="https://github.com/EnzeD"><img src="https://avatars.githubusercontent.com/u/9866900?v=4&s=48" width="48" height="48" alt="EnzeD" title="EnzeD"/></a> <a href="https://github.com/erik-agens"><img src="https://avatars.githubusercontent.com/u/80908960?v=4&s=48" width="48" height="48" alt="erik-agens" title="erik-agens"/></a> <a href="https://github.com/Evizero"><img src="https://avatars.githubusercontent.com/u/10854026?v=4&s=48" width="48" height="48" alt="Evizero" title="Evizero"/></a> <a href="https://github.com/fcatuhe"><img src="https://avatars.githubusercontent.com/u/17382215?v=4&s=48" width="48" height="48" alt="fcatuhe" title="fcatuhe"/></a> <a href="https://github.com/gildo"><img src="https://avatars.githubusercontent.com/u/133645?v=4&s=48" width="48" height="48" alt="gildo" title="gildo"/></a> <a href="https://github.com/hclsys"><img src="https://avatars.githubusercontent.com/u/7755017?v=4&s=48" width="48" height="48" alt="hclsys" title="hclsys"/></a> <a href="https://github.com/itsjaydesu"><img src="https://avatars.githubusercontent.com/u/220390?v=4&s=48" width="48" height="48" alt="itsjaydesu" title="itsjaydesu"/></a>
<a href="https://github.com/ivancasco"><img src="https://avatars.githubusercontent.com/u/2452858?v=4&s=48" width="48" height="48" alt="ivancasco" title="ivancasco"/></a> <a href="https://github.com/ivanrvpereira"><img src="https://avatars.githubusercontent.com/u/183991?v=4&s=48" width="48" height="48" alt="ivanrvpereira" title="ivanrvpereira"/></a> <a href="https://github.com/search?q=Jarvis"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jarvis" title="Jarvis"/></a> <a href="https://github.com/jayhickey"><img src="https://avatars.githubusercontent.com/u/1676460?v=4&s=48" width="48" height="48" alt="jayhickey" title="jayhickey"/></a> <a href="https://github.com/jeffersonwarrior"><img src="https://avatars.githubusercontent.com/u/89030989?v=4&s=48" width="48" height="48" alt="jeffersonwarrior" title="jeffersonwarrior"/></a> <a href="https://github.com/search?q=jeffersonwarrior"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="jeffersonwarrior" title="jeffersonwarrior"/></a> <a href="https://github.com/jverdi"><img src="https://avatars.githubusercontent.com/u/345050?v=4&s=48" width="48" height="48" alt="jverdi" title="jverdi"/></a> <a href="https://github.com/longmaba"><img src="https://avatars.githubusercontent.com/u/9361500?v=4&s=48" width="48" height="48" alt="longmaba" title="longmaba"/></a> <a href="https://github.com/search?q=Marco%20Marandiz"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Marco Marandiz" title="Marco Marandiz"/></a> <a href="https://github.com/MarvinCui"><img src="https://avatars.githubusercontent.com/u/130876763?v=4&s=48" width="48" height="48" alt="MarvinCui" title="MarvinCui"/></a>
<a href="https://github.com/mjrussell"><img src="https://avatars.githubusercontent.com/u/1641895?v=4&s=48" width="48" height="48" alt="mjrussell" title="mjrussell"/></a> <a href="https://github.com/odnxe"><img src="https://avatars.githubusercontent.com/u/403141?v=4&s=48" width="48" height="48" alt="odnxe" title="odnxe"/></a> <a href="https://github.com/optimikelabs"><img src="https://avatars.githubusercontent.com/u/31423109?v=4&s=48" width="48" height="48" alt="optimikelabs" title="optimikelabs"/></a> <a href="https://github.com/p6l-richard"><img src="https://avatars.githubusercontent.com/u/18185649?v=4&s=48" width="48" height="48" alt="p6l-richard" title="p6l-richard"/></a> <a href="https://github.com/philipp-spiess"><img src="https://avatars.githubusercontent.com/u/458591?v=4&s=48" width="48" height="48" alt="philipp-spiess" title="philipp-spiess"/></a> <a href="https://github.com/search?q=Pocket%20Clawd"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Pocket Clawd" title="Pocket Clawd"/></a> <a href="https://github.com/robaxelsen"><img src="https://avatars.githubusercontent.com/u/13132899?v=4&s=48" width="48" height="48" alt="robaxelsen" title="robaxelsen"/></a> <a href="https://github.com/search?q=Sash%20Catanzarite"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Sash Catanzarite" title="Sash Catanzarite"/></a> <a href="https://github.com/Suksham-sharma"><img src="https://avatars.githubusercontent.com/u/94667656?v=4&s=48" width="48" height="48" alt="Suksham-sharma" title="Suksham-sharma"/></a> <a href="https://github.com/T5-AndyML"><img src="https://avatars.githubusercontent.com/u/22801233?v=4&s=48" width="48" height="48" alt="T5-AndyML" title="T5-AndyML"/></a>
<a href="https://github.com/tewatia"><img src="https://avatars.githubusercontent.com/u/22875334?v=4&s=48" width="48" height="48" alt="tewatia" title="tewatia"/></a> <a href="https://github.com/thejhinvirtuoso"><img src="https://avatars.githubusercontent.com/u/258521837?v=4&s=48" width="48" height="48" alt="thejhinvirtuoso" title="thejhinvirtuoso"/></a> <a href="https://github.com/travisp"><img src="https://avatars.githubusercontent.com/u/165698?v=4&s=48" width="48" height="48" alt="travisp" title="travisp"/></a> <a href="https://github.com/search?q=VAC"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="VAC" title="VAC"/></a> <a href="https://github.com/search?q=william%20arzt"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="william arzt" title="william arzt"/></a> <a href="https://github.com/yudshj"><img src="https://avatars.githubusercontent.com/u/16971372?v=4&s=48" width="48" height="48" alt="yudshj" title="yudshj"/></a> <a href="https://github.com/zknicker"><img src="https://avatars.githubusercontent.com/u/1164085?v=4&s=48" width="48" height="48" alt="zknicker" title="zknicker"/></a> <a href="https://github.com/0oAstro"><img src="https://avatars.githubusercontent.com/u/79555780?v=4&s=48" width="48" height="48" alt="0oAstro" title="0oAstro"/></a> <a href="https://github.com/abhaymundhara"><img src="https://avatars.githubusercontent.com/u/62872231?v=4&s=48" width="48" height="48" alt="abhaymundhara" title="abhaymundhara"/></a> <a href="https://github.com/aduk059"><img src="https://avatars.githubusercontent.com/u/257603478?v=4&s=48" width="48" height="48" alt="aduk059" title="aduk059"/></a>
<a href="https://github.com/akramcodez"><img src="https://avatars.githubusercontent.com/u/179671552?v=4&s=48" width="48" height="48" alt="akramcodez" title="akramcodez"/></a> <a href="https://github.com/search?q=alejandro%20maza"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="alejandro maza" title="alejandro maza"/></a> <a href="https://github.com/Alex-Alaniz"><img src="https://avatars.githubusercontent.com/u/88956822?v=4&s=48" width="48" height="48" alt="Alex-Alaniz" title="Alex-Alaniz"/></a> <a href="https://github.com/alexanderatallah"><img src="https://avatars.githubusercontent.com/u/1011391?v=4&s=48" width="48" height="48" alt="alexanderatallah" title="alexanderatallah"/></a> <a href="https://github.com/alexstyl"><img src="https://avatars.githubusercontent.com/u/1665273?v=4&s=48" width="48" height="48" alt="alexstyl" title="alexstyl"/></a> <a href="https://github.com/AlexZhangji"><img src="https://avatars.githubusercontent.com/u/3280924?v=4&s=48" width="48" height="48" alt="AlexZhangji" title="AlexZhangji"/></a> <a href="https://github.com/andrewting19"><img src="https://avatars.githubusercontent.com/u/10536704?v=4&s=48" width="48" height="48" alt="andrewting19" title="andrewting19"/></a> <a href="https://github.com/anpoirier"><img src="https://avatars.githubusercontent.com/u/1245729?v=4&s=48" width="48" height="48" alt="anpoirier" title="anpoirier"/></a> <a href="https://github.com/araa47"><img src="https://avatars.githubusercontent.com/u/22760261?v=4&s=48" width="48" height="48" alt="araa47" title="araa47"/></a> <a href="https://github.com/arthyn"><img src="https://avatars.githubusercontent.com/u/5466421?v=4&s=48" width="48" height="48" alt="arthyn" title="arthyn"/></a>
<a href="https://github.com/Asleep123"><img src="https://avatars.githubusercontent.com/u/122379135?v=4&s=48" width="48" height="48" alt="Asleep123" title="Asleep123"/></a> <a href="https://github.com/search?q=Ayush%20Ojha"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Ayush Ojha" title="Ayush Ojha"/></a> <a href="https://github.com/Ayush10"><img src="https://avatars.githubusercontent.com/u/7945279?v=4&s=48" width="48" height="48" alt="Ayush10" title="Ayush10"/></a> <a href="https://github.com/bguidolim"><img src="https://avatars.githubusercontent.com/u/987360?v=4&s=48" width="48" height="48" alt="bguidolim" title="bguidolim"/></a> <a href="https://github.com/bolismauro"><img src="https://avatars.githubusercontent.com/u/771999?v=4&s=48" width="48" height="48" alt="bolismauro" title="bolismauro"/></a> <a href="https://github.com/championswimmer"><img src="https://avatars.githubusercontent.com/u/1327050?v=4&s=48" width="48" height="48" alt="championswimmer" title="championswimmer"/></a> <a href="https://github.com/chenyuan99"><img src="https://avatars.githubusercontent.com/u/25518100?v=4&s=48" width="48" height="48" alt="chenyuan99" title="chenyuan99"/></a> <a href="https://github.com/Chloe-VP"><img src="https://avatars.githubusercontent.com/u/257371598?v=4&s=48" width="48" height="48" alt="Chloe-VP" title="Chloe-VP"/></a> <a href="https://github.com/search?q=Clawdbot%20Maintainers"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Clawdbot Maintainers" title="Clawdbot Maintainers"/></a> <a href="https://github.com/conhecendoia"><img src="https://avatars.githubusercontent.com/u/82890727?v=4&s=48" width="48" height="48" alt="conhecendoia" title="conhecendoia"/></a>
<a href="https://github.com/dasilva333"><img src="https://avatars.githubusercontent.com/u/947827?v=4&s=48" width="48" height="48" alt="dasilva333" title="dasilva333"/></a> <a href="https://github.com/David-Marsh-Photo"><img src="https://avatars.githubusercontent.com/u/228404527?v=4&s=48" width="48" height="48" alt="David-Marsh-Photo" title="David-Marsh-Photo"/></a> <a href="https://github.com/deepsoumya617"><img src="https://avatars.githubusercontent.com/u/80877391?v=4&s=48" width="48" height="48" alt="deepsoumya617" title="deepsoumya617"/></a> <a href="https://github.com/search?q=Developer"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Developer" title="Developer"/></a> <a href="https://github.com/search?q=Dimitrios%20Ploutarchos"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Dimitrios Ploutarchos" title="Dimitrios Ploutarchos"/></a> <a href="https://github.com/search?q=Drake%20Thomsen"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Drake Thomsen" title="Drake Thomsen"/></a> <a href="https://github.com/dylanneve1"><img src="https://avatars.githubusercontent.com/u/31746704?v=4&s=48" width="48" height="48" alt="dylanneve1" title="dylanneve1"/></a> <a href="https://github.com/search?q=Felix%20Krause"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Felix Krause" title="Felix Krause"/></a> <a href="https://github.com/foeken"><img src="https://avatars.githubusercontent.com/u/13864?v=4&s=48" width="48" height="48" alt="foeken" title="foeken"/></a> <a href="https://github.com/frankekn"><img src="https://avatars.githubusercontent.com/u/4488090?v=4&s=48" width="48" height="48" alt="frankekn" title="frankekn"/></a>
<a href="https://github.com/fredheir"><img src="https://avatars.githubusercontent.com/u/3304869?v=4&s=48" width="48" height="48" alt="fredheir" title="fredheir"/></a> <a href="https://github.com/search?q=ganghyun%20kim"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="ganghyun kim" title="ganghyun kim"/></a> <a href="https://github.com/grrowl"><img src="https://avatars.githubusercontent.com/u/907140?v=4&s=48" width="48" height="48" alt="grrowl" title="grrowl"/></a> <a href="https://github.com/gtsifrikas"><img src="https://avatars.githubusercontent.com/u/8904378?v=4&s=48" width="48" height="48" alt="gtsifrikas" title="gtsifrikas"/></a> <a href="https://github.com/HassanFleyah"><img src="https://avatars.githubusercontent.com/u/228002017?v=4&s=48" width="48" height="48" alt="HassanFleyah" title="HassanFleyah"/></a> <a href="https://github.com/HazAT"><img src="https://avatars.githubusercontent.com/u/363802?v=4&s=48" width="48" height="48" alt="HazAT" title="HazAT"/></a> <a href="https://github.com/hrdwdmrbl"><img src="https://avatars.githubusercontent.com/u/554881?v=4&s=48" width="48" height="48" alt="hrdwdmrbl" title="hrdwdmrbl"/></a> <a href="https://github.com/hugobarauna"><img src="https://avatars.githubusercontent.com/u/2719?v=4&s=48" width="48" height="48" alt="hugobarauna" title="hugobarauna"/></a> <a href="https://github.com/hyf0-agent"><img src="https://avatars.githubusercontent.com/u/258783736?v=4&s=48" width="48" height="48" alt="hyf0-agent" title="hyf0-agent"/></a> <a href="https://github.com/iamEvanYT"><img src="https://avatars.githubusercontent.com/u/47493765?v=4&s=48" width="48" height="48" alt="iamEvanYT" title="iamEvanYT"/></a>
<a href="https://github.com/ichbinlucaskim"><img src="https://avatars.githubusercontent.com/u/125564751?v=4&s=48" width="48" height="48" alt="ichbinlucaskim" title="ichbinlucaskim"/></a> <a href="https://github.com/search?q=Jamie%20Openshaw"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jamie Openshaw" title="Jamie Openshaw"/></a> <a href="https://github.com/search?q=Jane"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jane" title="Jane"/></a> <a href="https://github.com/search?q=Jarvis%20Deploy"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jarvis Deploy" title="Jarvis Deploy"/></a> <a href="https://github.com/search?q=Jefferson%20Nunn"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jefferson Nunn" title="Jefferson Nunn"/></a> <a href="https://github.com/jogi47"><img src="https://avatars.githubusercontent.com/u/1710139?v=4&s=48" width="48" height="48" alt="jogi47" title="jogi47"/></a> <a href="https://github.com/kentaro"><img src="https://avatars.githubusercontent.com/u/3458?v=4&s=48" width="48" height="48" alt="kentaro" title="kentaro"/></a> <a href="https://github.com/search?q=Kevin%20Lin"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Kevin Lin" title="Kevin Lin"/></a> <a href="https://github.com/kira-ariaki"><img src="https://avatars.githubusercontent.com/u/257352493?v=4&s=48" width="48" height="48" alt="kira-ariaki" title="kira-ariaki"/></a> <a href="https://github.com/kitze"><img src="https://avatars.githubusercontent.com/u/1160594?v=4&s=48" width="48" height="48" alt="kitze" title="kitze"/></a>
<a href="https://github.com/Kiwitwitter"><img src="https://avatars.githubusercontent.com/u/25277769?v=4&s=48" width="48" height="48" alt="Kiwitwitter" title="Kiwitwitter"/></a> <a href="https://github.com/lailoo"><img src="https://avatars.githubusercontent.com/u/20536249?v=4&s=48" width="48" height="48" alt="lailoo" title="lailoo"/></a> <a href="https://github.com/levifig"><img src="https://avatars.githubusercontent.com/u/1605?v=4&s=48" width="48" height="48" alt="levifig" title="levifig"/></a> <a href="https://github.com/search?q=Lloyd"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Lloyd" title="Lloyd"/></a> <a href="https://github.com/loganaden"><img src="https://avatars.githubusercontent.com/u/1688420?v=4&s=48" width="48" height="48" alt="loganaden" title="loganaden"/></a> <a href="https://github.com/longjos"><img src="https://avatars.githubusercontent.com/u/740160?v=4&s=48" width="48" height="48" alt="longjos" title="longjos"/></a> <a href="https://github.com/loukotal"><img src="https://avatars.githubusercontent.com/u/18210858?v=4&s=48" width="48" height="48" alt="loukotal" title="loukotal"/></a> <a href="https://github.com/louzhixian"><img src="https://avatars.githubusercontent.com/u/7994361?v=4&s=48" width="48" height="48" alt="louzhixian" title="louzhixian"/></a> <a href="https://github.com/lsh411"><img src="https://avatars.githubusercontent.com/u/6801488?v=4&s=48" width="48" height="48" alt="lsh411" title="lsh411"/></a> <a href="https://github.com/M00N7682"><img src="https://avatars.githubusercontent.com/u/170746674?v=4&s=48" width="48" height="48" alt="M00N7682" title="M00N7682"/></a>
<a href="https://github.com/search?q=mac%20mimi"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="mac mimi" title="mac mimi"/></a> <a href="https://github.com/martinpucik"><img src="https://avatars.githubusercontent.com/u/5503097?v=4&s=48" width="48" height="48" alt="martinpucik" title="martinpucik"/></a> <a href="https://github.com/search?q=Matt%20mini"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Matt mini" title="Matt mini"/></a> <a href="https://github.com/mertcicekci0"><img src="https://avatars.githubusercontent.com/u/179321902?v=4&s=48" width="48" height="48" alt="mertcicekci0" title="mertcicekci0"/></a> <a href="https://github.com/search?q=Miles"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Miles" title="Miles"/></a> <a href="https://github.com/mrdbstn"><img src="https://avatars.githubusercontent.com/u/58957632?v=4&s=48" width="48" height="48" alt="mrdbstn" title="mrdbstn"/></a> <a href="https://github.com/MSch"><img src="https://avatars.githubusercontent.com/u/7475?v=4&s=48" width="48" height="48" alt="MSch" title="MSch"/></a> <a href="https://github.com/mudrii"><img src="https://avatars.githubusercontent.com/u/220262?v=4&s=48" width="48" height="48" alt="mudrii" title="mudrii"/></a> <a href="https://github.com/search?q=Mustafa%20Tag%20Eldeen"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Mustafa Tag Eldeen" title="Mustafa Tag Eldeen"/></a> <a href="https://github.com/mylukin"><img src="https://avatars.githubusercontent.com/u/1021019?v=4&s=48" width="48" height="48" alt="mylukin" title="mylukin"/></a>
<a href="https://github.com/nathanbosse"><img src="https://avatars.githubusercontent.com/u/4040669?v=4&s=48" width="48" height="48" alt="nathanbosse" title="nathanbosse"/></a> <a href="https://github.com/ndraiman"><img src="https://avatars.githubusercontent.com/u/12609607?v=4&s=48" width="48" height="48" alt="ndraiman" title="ndraiman"/></a> <a href="https://github.com/nexty5870"><img src="https://avatars.githubusercontent.com/u/3869659?v=4&s=48" width="48" height="48" alt="nexty5870" title="nexty5870"/></a> <a href="https://github.com/Noctivoro"><img src="https://avatars.githubusercontent.com/u/183974570?v=4&s=48" width="48" height="48" alt="Noctivoro" title="Noctivoro"/></a> <a href="https://github.com/ozgur-polat"><img src="https://avatars.githubusercontent.com/u/26483942?v=4&s=48" width="48" height="48" alt="ozgur-polat" title="ozgur-polat"/></a> <a href="https://github.com/ppamment"><img src="https://avatars.githubusercontent.com/u/2122919?v=4&s=48" width="48" height="48" alt="ppamment" title="ppamment"/></a> <a href="https://github.com/prathamdby"><img src="https://avatars.githubusercontent.com/u/134331217?v=4&s=48" width="48" height="48" alt="prathamdby" title="prathamdby"/></a> <a href="https://github.com/ptn1411"><img src="https://avatars.githubusercontent.com/u/57529765?v=4&s=48" width="48" height="48" alt="ptn1411" title="ptn1411"/></a> <a href="https://github.com/reeltimeapps"><img src="https://avatars.githubusercontent.com/u/637338?v=4&s=48" width="48" height="48" alt="reeltimeapps" title="reeltimeapps"/></a> <a href="https://github.com/RLTCmpe"><img src="https://avatars.githubusercontent.com/u/10762242?v=4&s=48" width="48" height="48" alt="RLTCmpe" title="RLTCmpe"/></a>
<a href="https://github.com/search?q=Rony%20Kelner"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Rony Kelner" title="Rony Kelner"/></a> <a href="https://github.com/ryancnelson"><img src="https://avatars.githubusercontent.com/u/347171?v=4&s=48" width="48" height="48" alt="ryancnelson" title="ryancnelson"/></a> <a href="https://github.com/search?q=Samrat%20Jha"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Samrat Jha" title="Samrat Jha"/></a> <a href="https://github.com/senoldogann"><img src="https://avatars.githubusercontent.com/u/45736551?v=4&s=48" width="48" height="48" alt="senoldogann" title="senoldogann"/></a> <a href="https://github.com/Seredeep"><img src="https://avatars.githubusercontent.com/u/22802816?v=4&s=48" width="48" height="48" alt="Seredeep" title="Seredeep"/></a> <a href="https://github.com/sergical"><img src="https://avatars.githubusercontent.com/u/3760543?v=4&s=48" width="48" height="48" alt="sergical" title="sergical"/></a> <a href="https://github.com/shiv19"><img src="https://avatars.githubusercontent.com/u/9407019?v=4&s=48" width="48" height="48" alt="shiv19" title="shiv19"/></a> <a href="https://github.com/shiyuanhai"><img src="https://avatars.githubusercontent.com/u/1187370?v=4&s=48" width="48" height="48" alt="shiyuanhai" title="shiyuanhai"/></a> <a href="https://github.com/siraht"><img src="https://avatars.githubusercontent.com/u/73152895?v=4&s=48" width="48" height="48" alt="siraht" title="siraht"/></a> <a href="https://github.com/snopoke"><img src="https://avatars.githubusercontent.com/u/249606?v=4&s=48" width="48" height="48" alt="snopoke" title="snopoke"/></a>
<a href="https://github.com/stephenchen2025"><img src="https://avatars.githubusercontent.com/u/218387130?v=4&s=48" width="48" height="48" alt="stephenchen2025" title="stephenchen2025"/></a> <a href="https://github.com/search?q=techboss"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="techboss" title="techboss"/></a> <a href="https://github.com/testingabc321"><img src="https://avatars.githubusercontent.com/u/8577388?v=4&s=48" width="48" height="48" alt="testingabc321" title="testingabc321"/></a> <a href="https://github.com/search?q=The%20Admiral"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="The Admiral" title="The Admiral"/></a> <a href="https://github.com/thesash"><img src="https://avatars.githubusercontent.com/u/1166151?v=4&s=48" width="48" height="48" alt="thesash" title="thesash"/></a> <a href="https://github.com/search?q=Vibe%20Kanban"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Vibe Kanban" title="Vibe Kanban"/></a> <a href="https://github.com/voidserf"><img src="https://avatars.githubusercontent.com/u/477673?v=4&s=48" width="48" height="48" alt="voidserf" title="voidserf"/></a> <a href="https://github.com/search?q=Vultr-Clawd%20Admin"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Vultr-Clawd Admin" title="Vultr-Clawd Admin"/></a> <a href="https://github.com/search?q=Wimmie"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Wimmie" title="Wimmie"/></a> <a href="https://github.com/search?q=wolfred"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="wolfred" title="wolfred"/></a>
<a href="https://github.com/wstock"><img src="https://avatars.githubusercontent.com/u/1394687?v=4&s=48" width="48" height="48" alt="wstock" title="wstock"/></a> <a href="https://github.com/wytheme"><img src="https://avatars.githubusercontent.com/u/5009358?v=4&s=48" width="48" height="48" alt="wytheme" title="wytheme"/></a> <a href="https://github.com/YangHuang2280"><img src="https://avatars.githubusercontent.com/u/201681634?v=4&s=48" width="48" height="48" alt="YangHuang2280" title="YangHuang2280"/></a> <a href="https://github.com/yazinsai"><img src="https://avatars.githubusercontent.com/u/1846034?v=4&s=48" width="48" height="48" alt="yazinsai" title="yazinsai"/></a> <a href="https://github.com/yevhen"><img src="https://avatars.githubusercontent.com/u/107726?v=4&s=48" width="48" height="48" alt="yevhen" title="yevhen"/></a> <a href="https://github.com/YiWang24"><img src="https://avatars.githubusercontent.com/u/176262341?v=4&s=48" width="48" height="48" alt="YiWang24" title="YiWang24"/></a> <a href="https://github.com/search?q=ymat19"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="ymat19" title="ymat19"/></a> <a href="https://github.com/search?q=Zach%20Knickerbocker"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Zach Knickerbocker" title="Zach Knickerbocker"/></a> <a href="https://github.com/zackerthescar"><img src="https://avatars.githubusercontent.com/u/38077284?v=4&s=48" width="48" height="48" alt="zackerthescar" title="zackerthescar"/></a> <a href="https://github.com/0xJonHoldsCrypto"><img src="https://avatars.githubusercontent.com/u/81202085?v=4&s=48" width="48" height="48" alt="0xJonHoldsCrypto" title="0xJonHoldsCrypto"/></a>
<a href="https://github.com/aaronn"><img src="https://avatars.githubusercontent.com/u/1653630?v=4&s=48" width="48" height="48" alt="aaronn" title="aaronn"/></a> <a href="https://github.com/Alphonse-arianee"><img src="https://avatars.githubusercontent.com/u/254457365?v=4&s=48" width="48" height="48" alt="Alphonse-arianee" title="Alphonse-arianee"/></a> <a href="https://github.com/atalovesyou"><img src="https://avatars.githubusercontent.com/u/3534502?v=4&s=48" width="48" height="48" alt="atalovesyou" title="atalovesyou"/></a> <a href="https://github.com/search?q=Azade"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Azade" title="Azade"/></a> <a href="https://github.com/carlulsoe"><img src="https://avatars.githubusercontent.com/u/34673973?v=4&s=48" width="48" height="48" alt="carlulsoe" title="carlulsoe"/></a> <a href="https://github.com/search?q=ddyo"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="ddyo" title="ddyo"/></a> <a href="https://github.com/search?q=Erik"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Erik" title="Erik"/></a> <a href="https://github.com/jiulingyun"><img src="https://avatars.githubusercontent.com/u/126459548?v=4&s=48" width="48" height="48" alt="jiulingyun" title="jiulingyun"/></a> <a href="https://github.com/latitudeki5223"><img src="https://avatars.githubusercontent.com/u/119656367?v=4&s=48" width="48" height="48" alt="latitudeki5223" title="latitudeki5223"/></a> <a href="https://github.com/search?q=Manuel%20Maly"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Manuel Maly" title="Manuel Maly"/></a>
<a href="https://github.com/search?q=Mourad%20Boustani"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Mourad Boustani" title="Mourad Boustani"/></a> <a href="https://github.com/odrobnik"><img src="https://avatars.githubusercontent.com/u/333270?v=4&s=48" width="48" height="48" alt="odrobnik" title="odrobnik"/></a> <a href="https://github.com/pcty-nextgen-ios-builder"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="pcty-nextgen-ios-builder" title="pcty-nextgen-ios-builder"/></a> <a href="https://github.com/search?q=Quentin"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Quentin" title="Quentin"/></a> <a href="https://github.com/search?q=Randy%20Torres"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Randy Torres" title="Randy Torres"/></a> <a href="https://github.com/rhjoh"><img src="https://avatars.githubusercontent.com/u/105699450?v=4&s=48" width="48" height="48" alt="rhjoh" title="rhjoh"/></a> <a href="https://github.com/search?q=Rolf%20Fredheim"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Rolf Fredheim" title="Rolf Fredheim"/></a> <a href="https://github.com/ronak-guliani"><img src="https://avatars.githubusercontent.com/u/23518228?v=4&s=48" width="48" height="48" alt="ronak-guliani" title="ronak-guliani"/></a> <a href="https://github.com/search?q=William%20Stock"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="William Stock" title="William Stock"/></a>
<a href="https://github.com/ivancasco"><img src="https://avatars.githubusercontent.com/u/2452858?v=4&s=48" width="48" height="48" alt="ivancasco" title="ivancasco"/></a> <a href="https://github.com/ivanrvpereira"><img src="https://avatars.githubusercontent.com/u/183991?v=4&s=48" width="48" height="48" alt="ivanrvpereira" title="ivanrvpereira"/></a> <a href="https://github.com/search?q=Jarvis"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jarvis" title="Jarvis"/></a> <a href="https://github.com/jayhickey"><img src="https://avatars.githubusercontent.com/u/1676460?v=4&s=48" width="48" height="48" alt="jayhickey" title="jayhickey"/></a> <a href="https://github.com/jeffersonwarrior"><img src="https://avatars.githubusercontent.com/u/89030989?v=4&s=48" width="48" height="48" alt="jeffersonwarrior" title="jeffersonwarrior"/></a> <a href="https://github.com/search?q=jeffersonwarrior"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="jeffersonwarrior" title="jeffersonwarrior"/></a> <a href="https://github.com/jverdi"><img src="https://avatars.githubusercontent.com/u/345050?v=4&s=48" width="48" height="48" alt="jverdi" title="jverdi"/></a> <a href="https://github.com/lailoo"><img src="https://avatars.githubusercontent.com/u/20536249?v=4&s=48" width="48" height="48" alt="lailoo" title="lailoo"/></a> <a href="https://github.com/longmaba"><img src="https://avatars.githubusercontent.com/u/9361500?v=4&s=48" width="48" height="48" alt="longmaba" title="longmaba"/></a> <a href="https://github.com/search?q=Marco%20Marandiz"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Marco Marandiz" title="Marco Marandiz"/></a>
<a href="https://github.com/MarvinCui"><img src="https://avatars.githubusercontent.com/u/130876763?v=4&s=48" width="48" height="48" alt="MarvinCui" title="MarvinCui"/></a> <a href="https://github.com/mattezell"><img src="https://avatars.githubusercontent.com/u/361409?v=4&s=48" width="48" height="48" alt="mattezell" title="mattezell"/></a> <a href="https://github.com/mjrussell"><img src="https://avatars.githubusercontent.com/u/1641895?v=4&s=48" width="48" height="48" alt="mjrussell" title="mjrussell"/></a> <a href="https://github.com/odnxe"><img src="https://avatars.githubusercontent.com/u/403141?v=4&s=48" width="48" height="48" alt="odnxe" title="odnxe"/></a> <a href="https://github.com/optimikelabs"><img src="https://avatars.githubusercontent.com/u/31423109?v=4&s=48" width="48" height="48" alt="optimikelabs" title="optimikelabs"/></a> <a href="https://github.com/p6l-richard"><img src="https://avatars.githubusercontent.com/u/18185649?v=4&s=48" width="48" height="48" alt="p6l-richard" title="p6l-richard"/></a> <a href="https://github.com/philipp-spiess"><img src="https://avatars.githubusercontent.com/u/458591?v=4&s=48" width="48" height="48" alt="philipp-spiess" title="philipp-spiess"/></a> <a href="https://github.com/search?q=Pocket%20Clawd"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Pocket Clawd" title="Pocket Clawd"/></a> <a href="https://github.com/robaxelsen"><img src="https://avatars.githubusercontent.com/u/13132899?v=4&s=48" width="48" height="48" alt="robaxelsen" title="robaxelsen"/></a> <a href="https://github.com/search?q=Sash%20Catanzarite"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Sash Catanzarite" title="Sash Catanzarite"/></a>
<a href="https://github.com/Suksham-sharma"><img src="https://avatars.githubusercontent.com/u/94667656?v=4&s=48" width="48" height="48" alt="Suksham-sharma" title="Suksham-sharma"/></a> <a href="https://github.com/T5-AndyML"><img src="https://avatars.githubusercontent.com/u/22801233?v=4&s=48" width="48" height="48" alt="T5-AndyML" title="T5-AndyML"/></a> <a href="https://github.com/tewatia"><img src="https://avatars.githubusercontent.com/u/22875334?v=4&s=48" width="48" height="48" alt="tewatia" title="tewatia"/></a> <a href="https://github.com/thejhinvirtuoso"><img src="https://avatars.githubusercontent.com/u/258521837?v=4&s=48" width="48" height="48" alt="thejhinvirtuoso" title="thejhinvirtuoso"/></a> <a href="https://github.com/travisp"><img src="https://avatars.githubusercontent.com/u/165698?v=4&s=48" width="48" height="48" alt="travisp" title="travisp"/></a> <a href="https://github.com/search?q=VAC"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="VAC" title="VAC"/></a> <a href="https://github.com/search?q=william%20arzt"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="william arzt" title="william arzt"/></a> <a href="https://github.com/yudshj"><img src="https://avatars.githubusercontent.com/u/16971372?v=4&s=48" width="48" height="48" alt="yudshj" title="yudshj"/></a> <a href="https://github.com/zknicker"><img src="https://avatars.githubusercontent.com/u/1164085?v=4&s=48" width="48" height="48" alt="zknicker" title="zknicker"/></a> <a href="https://github.com/0oAstro"><img src="https://avatars.githubusercontent.com/u/79555780?v=4&s=48" width="48" height="48" alt="0oAstro" title="0oAstro"/></a>
<a href="https://github.com/abhaymundhara"><img src="https://avatars.githubusercontent.com/u/62872231?v=4&s=48" width="48" height="48" alt="abhaymundhara" title="abhaymundhara"/></a> <a href="https://github.com/aduk059"><img src="https://avatars.githubusercontent.com/u/257603478?v=4&s=48" width="48" height="48" alt="aduk059" title="aduk059"/></a> <a href="https://github.com/aisling404"><img src="https://avatars.githubusercontent.com/u/211950534?v=4&s=48" width="48" height="48" alt="aisling404" title="aisling404"/></a> <a href="https://github.com/akramcodez"><img src="https://avatars.githubusercontent.com/u/179671552?v=4&s=48" width="48" height="48" alt="akramcodez" title="akramcodez"/></a> <a href="https://github.com/search?q=alejandro%20maza"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="alejandro maza" title="alejandro maza"/></a> <a href="https://github.com/Alex-Alaniz"><img src="https://avatars.githubusercontent.com/u/88956822?v=4&s=48" width="48" height="48" alt="Alex-Alaniz" title="Alex-Alaniz"/></a> <a href="https://github.com/alexanderatallah"><img src="https://avatars.githubusercontent.com/u/1011391?v=4&s=48" width="48" height="48" alt="alexanderatallah" title="alexanderatallah"/></a> <a href="https://github.com/alexstyl"><img src="https://avatars.githubusercontent.com/u/1665273?v=4&s=48" width="48" height="48" alt="alexstyl" title="alexstyl"/></a> <a href="https://github.com/AlexZhangji"><img src="https://avatars.githubusercontent.com/u/3280924?v=4&s=48" width="48" height="48" alt="AlexZhangji" title="AlexZhangji"/></a> <a href="https://github.com/andrewting19"><img src="https://avatars.githubusercontent.com/u/10536704?v=4&s=48" width="48" height="48" alt="andrewting19" title="andrewting19"/></a>
<a href="https://github.com/anpoirier"><img src="https://avatars.githubusercontent.com/u/1245729?v=4&s=48" width="48" height="48" alt="anpoirier" title="anpoirier"/></a> <a href="https://github.com/araa47"><img src="https://avatars.githubusercontent.com/u/22760261?v=4&s=48" width="48" height="48" alt="araa47" title="araa47"/></a> <a href="https://github.com/arthyn"><img src="https://avatars.githubusercontent.com/u/5466421?v=4&s=48" width="48" height="48" alt="arthyn" title="arthyn"/></a> <a href="https://github.com/Asleep123"><img src="https://avatars.githubusercontent.com/u/122379135?v=4&s=48" width="48" height="48" alt="Asleep123" title="Asleep123"/></a> <a href="https://github.com/search?q=Ayush%20Ojha"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Ayush Ojha" title="Ayush Ojha"/></a> <a href="https://github.com/Ayush10"><img src="https://avatars.githubusercontent.com/u/7945279?v=4&s=48" width="48" height="48" alt="Ayush10" title="Ayush10"/></a> <a href="https://github.com/bguidolim"><img src="https://avatars.githubusercontent.com/u/987360?v=4&s=48" width="48" height="48" alt="bguidolim" title="bguidolim"/></a> <a href="https://github.com/bolismauro"><img src="https://avatars.githubusercontent.com/u/771999?v=4&s=48" width="48" height="48" alt="bolismauro" title="bolismauro"/></a> <a href="https://github.com/caelum0x"><img src="https://avatars.githubusercontent.com/u/130079063?v=4&s=48" width="48" height="48" alt="caelum0x" title="caelum0x"/></a> <a href="https://github.com/championswimmer"><img src="https://avatars.githubusercontent.com/u/1327050?v=4&s=48" width="48" height="48" alt="championswimmer" title="championswimmer"/></a>
<a href="https://github.com/chenyuan99"><img src="https://avatars.githubusercontent.com/u/25518100?v=4&s=48" width="48" height="48" alt="chenyuan99" title="chenyuan99"/></a> <a href="https://github.com/Chloe-VP"><img src="https://avatars.githubusercontent.com/u/257371598?v=4&s=48" width="48" height="48" alt="Chloe-VP" title="Chloe-VP"/></a> <a href="https://github.com/search?q=Clawdbot%20Maintainers"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Clawdbot Maintainers" title="Clawdbot Maintainers"/></a> <a href="https://github.com/conhecendoia"><img src="https://avatars.githubusercontent.com/u/82890727?v=4&s=48" width="48" height="48" alt="conhecendoia" title="conhecendoia"/></a> <a href="https://github.com/dasilva333"><img src="https://avatars.githubusercontent.com/u/947827?v=4&s=48" width="48" height="48" alt="dasilva333" title="dasilva333"/></a> <a href="https://github.com/David-Marsh-Photo"><img src="https://avatars.githubusercontent.com/u/228404527?v=4&s=48" width="48" height="48" alt="David-Marsh-Photo" title="David-Marsh-Photo"/></a> <a href="https://github.com/deepsoumya617"><img src="https://avatars.githubusercontent.com/u/80877391?v=4&s=48" width="48" height="48" alt="deepsoumya617" title="deepsoumya617"/></a> <a href="https://github.com/search?q=Developer"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Developer" title="Developer"/></a> <a href="https://github.com/search?q=Dimitrios%20Ploutarchos"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Dimitrios Ploutarchos" title="Dimitrios Ploutarchos"/></a> <a href="https://github.com/search?q=Drake%20Thomsen"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Drake Thomsen" title="Drake Thomsen"/></a>
<a href="https://github.com/dvrshil"><img src="https://avatars.githubusercontent.com/u/81693876?v=4&s=48" width="48" height="48" alt="dvrshil" title="dvrshil"/></a> <a href="https://github.com/dxd5001"><img src="https://avatars.githubusercontent.com/u/1886046?v=4&s=48" width="48" height="48" alt="dxd5001" title="dxd5001"/></a> <a href="https://github.com/dylanneve1"><img src="https://avatars.githubusercontent.com/u/31746704?v=4&s=48" width="48" height="48" alt="dylanneve1" title="dylanneve1"/></a> <a href="https://github.com/search?q=Felix%20Krause"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Felix Krause" title="Felix Krause"/></a> <a href="https://github.com/foeken"><img src="https://avatars.githubusercontent.com/u/13864?v=4&s=48" width="48" height="48" alt="foeken" title="foeken"/></a> <a href="https://github.com/frankekn"><img src="https://avatars.githubusercontent.com/u/4488090?v=4&s=48" width="48" height="48" alt="frankekn" title="frankekn"/></a> <a href="https://github.com/fredheir"><img src="https://avatars.githubusercontent.com/u/3304869?v=4&s=48" width="48" height="48" alt="fredheir" title="fredheir"/></a> <a href="https://github.com/search?q=ganghyun%20kim"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="ganghyun kim" title="ganghyun kim"/></a> <a href="https://github.com/grrowl"><img src="https://avatars.githubusercontent.com/u/907140?v=4&s=48" width="48" height="48" alt="grrowl" title="grrowl"/></a> <a href="https://github.com/gtsifrikas"><img src="https://avatars.githubusercontent.com/u/8904378?v=4&s=48" width="48" height="48" alt="gtsifrikas" title="gtsifrikas"/></a>
<a href="https://github.com/HassanFleyah"><img src="https://avatars.githubusercontent.com/u/228002017?v=4&s=48" width="48" height="48" alt="HassanFleyah" title="HassanFleyah"/></a> <a href="https://github.com/HazAT"><img src="https://avatars.githubusercontent.com/u/363802?v=4&s=48" width="48" height="48" alt="HazAT" title="HazAT"/></a> <a href="https://github.com/hrdwdmrbl"><img src="https://avatars.githubusercontent.com/u/554881?v=4&s=48" width="48" height="48" alt="hrdwdmrbl" title="hrdwdmrbl"/></a> <a href="https://github.com/hugobarauna"><img src="https://avatars.githubusercontent.com/u/2719?v=4&s=48" width="48" height="48" alt="hugobarauna" title="hugobarauna"/></a> <a href="https://github.com/iamEvanYT"><img src="https://avatars.githubusercontent.com/u/47493765?v=4&s=48" width="48" height="48" alt="iamEvanYT" title="iamEvanYT"/></a> <a href="https://github.com/ichbinlucaskim"><img src="https://avatars.githubusercontent.com/u/125564751?v=4&s=48" width="48" height="48" alt="ichbinlucaskim" title="ichbinlucaskim"/></a> <a href="https://github.com/search?q=Jamie%20Openshaw"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jamie Openshaw" title="Jamie Openshaw"/></a> <a href="https://github.com/search?q=Jane"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jane" title="Jane"/></a> <a href="https://github.com/search?q=Jarvis%20Deploy"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jarvis Deploy" title="Jarvis Deploy"/></a> <a href="https://github.com/search?q=Jefferson%20Nunn"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Jefferson Nunn" title="Jefferson Nunn"/></a>
<a href="https://github.com/jogi47"><img src="https://avatars.githubusercontent.com/u/1710139?v=4&s=48" width="48" height="48" alt="jogi47" title="jogi47"/></a> <a href="https://github.com/kentaro"><img src="https://avatars.githubusercontent.com/u/3458?v=4&s=48" width="48" height="48" alt="kentaro" title="kentaro"/></a> <a href="https://github.com/search?q=Kevin%20Lin"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Kevin Lin" title="Kevin Lin"/></a> <a href="https://github.com/kira-ariaki"><img src="https://avatars.githubusercontent.com/u/257352493?v=4&s=48" width="48" height="48" alt="kira-ariaki" title="kira-ariaki"/></a> <a href="https://github.com/kitze"><img src="https://avatars.githubusercontent.com/u/1160594?v=4&s=48" width="48" height="48" alt="kitze" title="kitze"/></a> <a href="https://github.com/Kiwitwitter"><img src="https://avatars.githubusercontent.com/u/25277769?v=4&s=48" width="48" height="48" alt="Kiwitwitter" title="Kiwitwitter"/></a> <a href="https://github.com/levifig"><img src="https://avatars.githubusercontent.com/u/1605?v=4&s=48" width="48" height="48" alt="levifig" title="levifig"/></a> <a href="https://github.com/search?q=Lloyd"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Lloyd" title="Lloyd"/></a> <a href="https://github.com/loganaden"><img src="https://avatars.githubusercontent.com/u/1688420?v=4&s=48" width="48" height="48" alt="loganaden" title="loganaden"/></a> <a href="https://github.com/longjos"><img src="https://avatars.githubusercontent.com/u/740160?v=4&s=48" width="48" height="48" alt="longjos" title="longjos"/></a>
<a href="https://github.com/loukotal"><img src="https://avatars.githubusercontent.com/u/18210858?v=4&s=48" width="48" height="48" alt="loukotal" title="loukotal"/></a> <a href="https://github.com/louzhixian"><img src="https://avatars.githubusercontent.com/u/7994361?v=4&s=48" width="48" height="48" alt="louzhixian" title="louzhixian"/></a> <a href="https://github.com/search?q=mac%20mimi"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="mac mimi" title="mac mimi"/></a> <a href="https://github.com/martinpucik"><img src="https://avatars.githubusercontent.com/u/5503097?v=4&s=48" width="48" height="48" alt="martinpucik" title="martinpucik"/></a> <a href="https://github.com/search?q=Matt%20mini"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Matt mini" title="Matt mini"/></a> <a href="https://github.com/mcaxtr"><img src="https://avatars.githubusercontent.com/u/7562095?v=4&s=48" width="48" height="48" alt="mcaxtr" title="mcaxtr"/></a> <a href="https://github.com/mertcicekci0"><img src="https://avatars.githubusercontent.com/u/179321902?v=4&s=48" width="48" height="48" alt="mertcicekci0" title="mertcicekci0"/></a> <a href="https://github.com/search?q=Miles"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Miles" title="Miles"/></a> <a href="https://github.com/mrdbstn"><img src="https://avatars.githubusercontent.com/u/58957632?v=4&s=48" width="48" height="48" alt="mrdbstn" title="mrdbstn"/></a> <a href="https://github.com/MSch"><img src="https://avatars.githubusercontent.com/u/7475?v=4&s=48" width="48" height="48" alt="MSch" title="MSch"/></a>
<a href="https://github.com/search?q=Mustafa%20Tag%20Eldeen"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Mustafa Tag Eldeen" title="Mustafa Tag Eldeen"/></a> <a href="https://github.com/mylukin"><img src="https://avatars.githubusercontent.com/u/1021019?v=4&s=48" width="48" height="48" alt="mylukin" title="mylukin"/></a> <a href="https://github.com/nathanbosse"><img src="https://avatars.githubusercontent.com/u/4040669?v=4&s=48" width="48" height="48" alt="nathanbosse" title="nathanbosse"/></a> <a href="https://github.com/ndraiman"><img src="https://avatars.githubusercontent.com/u/12609607?v=4&s=48" width="48" height="48" alt="ndraiman" title="ndraiman"/></a> <a href="https://github.com/nexty5870"><img src="https://avatars.githubusercontent.com/u/3869659?v=4&s=48" width="48" height="48" alt="nexty5870" title="nexty5870"/></a> <a href="https://github.com/Noctivoro"><img src="https://avatars.githubusercontent.com/u/183974570?v=4&s=48" width="48" height="48" alt="Noctivoro" title="Noctivoro"/></a> <a href="https://github.com/Omar-Khaleel"><img src="https://avatars.githubusercontent.com/u/240748662?v=4&s=48" width="48" height="48" alt="Omar-Khaleel" title="Omar-Khaleel"/></a> <a href="https://github.com/ozgur-polat"><img src="https://avatars.githubusercontent.com/u/26483942?v=4&s=48" width="48" height="48" alt="ozgur-polat" title="ozgur-polat"/></a> <a href="https://github.com/ppamment"><img src="https://avatars.githubusercontent.com/u/2122919?v=4&s=48" width="48" height="48" alt="ppamment" title="ppamment"/></a> <a href="https://github.com/prathamdby"><img src="https://avatars.githubusercontent.com/u/134331217?v=4&s=48" width="48" height="48" alt="prathamdby" title="prathamdby"/></a>
<a href="https://github.com/ptn1411"><img src="https://avatars.githubusercontent.com/u/57529765?v=4&s=48" width="48" height="48" alt="ptn1411" title="ptn1411"/></a> <a href="https://github.com/rafelbev"><img src="https://avatars.githubusercontent.com/u/467120?v=4&s=48" width="48" height="48" alt="rafelbev" title="rafelbev"/></a> <a href="https://github.com/reeltimeapps"><img src="https://avatars.githubusercontent.com/u/637338?v=4&s=48" width="48" height="48" alt="reeltimeapps" title="reeltimeapps"/></a> <a href="https://github.com/RLTCmpe"><img src="https://avatars.githubusercontent.com/u/10762242?v=4&s=48" width="48" height="48" alt="RLTCmpe" title="RLTCmpe"/></a> <a href="https://github.com/search?q=Rony%20Kelner"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Rony Kelner" title="Rony Kelner"/></a> <a href="https://github.com/ryancnelson"><img src="https://avatars.githubusercontent.com/u/347171?v=4&s=48" width="48" height="48" alt="ryancnelson" title="ryancnelson"/></a> <a href="https://github.com/search?q=Samrat%20Jha"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Samrat Jha" title="Samrat Jha"/></a> <a href="https://github.com/senoldogann"><img src="https://avatars.githubusercontent.com/u/45736551?v=4&s=48" width="48" height="48" alt="senoldogann" title="senoldogann"/></a> <a href="https://github.com/Seredeep"><img src="https://avatars.githubusercontent.com/u/22802816?v=4&s=48" width="48" height="48" alt="Seredeep" title="Seredeep"/></a> <a href="https://github.com/sergical"><img src="https://avatars.githubusercontent.com/u/3760543?v=4&s=48" width="48" height="48" alt="sergical" title="sergical"/></a>
<a href="https://github.com/shiv19"><img src="https://avatars.githubusercontent.com/u/9407019?v=4&s=48" width="48" height="48" alt="shiv19" title="shiv19"/></a> <a href="https://github.com/shiyuanhai"><img src="https://avatars.githubusercontent.com/u/1187370?v=4&s=48" width="48" height="48" alt="shiyuanhai" title="shiyuanhai"/></a> <a href="https://github.com/Shrinija17"><img src="https://avatars.githubusercontent.com/u/199155426?v=4&s=48" width="48" height="48" alt="Shrinija17" title="Shrinija17"/></a> <a href="https://github.com/siraht"><img src="https://avatars.githubusercontent.com/u/73152895?v=4&s=48" width="48" height="48" alt="siraht" title="siraht"/></a> <a href="https://github.com/snopoke"><img src="https://avatars.githubusercontent.com/u/249606?v=4&s=48" width="48" height="48" alt="snopoke" title="snopoke"/></a> <a href="https://github.com/stephenchen2025"><img src="https://avatars.githubusercontent.com/u/218387130?v=4&s=48" width="48" height="48" alt="stephenchen2025" title="stephenchen2025"/></a> <a href="https://github.com/search?q=techboss"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="techboss" title="techboss"/></a> <a href="https://github.com/testingabc321"><img src="https://avatars.githubusercontent.com/u/8577388?v=4&s=48" width="48" height="48" alt="testingabc321" title="testingabc321"/></a> <a href="https://github.com/search?q=The%20Admiral"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="The Admiral" title="The Admiral"/></a> <a href="https://github.com/thesash"><img src="https://avatars.githubusercontent.com/u/1166151?v=4&s=48" width="48" height="48" alt="thesash" title="thesash"/></a>
<a href="https://github.com/search?q=Vibe%20Kanban"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Vibe Kanban" title="Vibe Kanban"/></a> <a href="https://github.com/vincentkoc"><img src="https://avatars.githubusercontent.com/u/25068?v=4&s=48" width="48" height="48" alt="vincentkoc" title="vincentkoc"/></a> <a href="https://github.com/voidserf"><img src="https://avatars.githubusercontent.com/u/477673?v=4&s=48" width="48" height="48" alt="voidserf" title="voidserf"/></a> <a href="https://github.com/search?q=Vultr-Clawd%20Admin"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Vultr-Clawd Admin" title="Vultr-Clawd Admin"/></a> <a href="https://github.com/search?q=Wimmie"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Wimmie" title="Wimmie"/></a> <a href="https://github.com/search?q=wolfred"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="wolfred" title="wolfred"/></a> <a href="https://github.com/wstock"><img src="https://avatars.githubusercontent.com/u/1394687?v=4&s=48" width="48" height="48" alt="wstock" title="wstock"/></a> <a href="https://github.com/wytheme"><img src="https://avatars.githubusercontent.com/u/5009358?v=4&s=48" width="48" height="48" alt="wytheme" title="wytheme"/></a> <a href="https://github.com/YangHuang2280"><img src="https://avatars.githubusercontent.com/u/201681634?v=4&s=48" width="48" height="48" alt="YangHuang2280" title="YangHuang2280"/></a> <a href="https://github.com/yazinsai"><img src="https://avatars.githubusercontent.com/u/1846034?v=4&s=48" width="48" height="48" alt="yazinsai" title="yazinsai"/></a>
<a href="https://github.com/yevhen"><img src="https://avatars.githubusercontent.com/u/107726?v=4&s=48" width="48" height="48" alt="yevhen" title="yevhen"/></a> <a href="https://github.com/YiWang24"><img src="https://avatars.githubusercontent.com/u/176262341?v=4&s=48" width="48" height="48" alt="YiWang24" title="YiWang24"/></a> <a href="https://github.com/search?q=ymat19"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="ymat19" title="ymat19"/></a> <a href="https://github.com/search?q=Zach%20Knickerbocker"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Zach Knickerbocker" title="Zach Knickerbocker"/></a> <a href="https://github.com/zackerthescar"><img src="https://avatars.githubusercontent.com/u/38077284?v=4&s=48" width="48" height="48" alt="zackerthescar" title="zackerthescar"/></a> <a href="https://github.com/0xJonHoldsCrypto"><img src="https://avatars.githubusercontent.com/u/81202085?v=4&s=48" width="48" height="48" alt="0xJonHoldsCrypto" title="0xJonHoldsCrypto"/></a> <a href="https://github.com/aaronn"><img src="https://avatars.githubusercontent.com/u/1653630?v=4&s=48" width="48" height="48" alt="aaronn" title="aaronn"/></a> <a href="https://github.com/Alphonse-arianee"><img src="https://avatars.githubusercontent.com/u/254457365?v=4&s=48" width="48" height="48" alt="Alphonse-arianee" title="Alphonse-arianee"/></a> <a href="https://github.com/atalovesyou"><img src="https://avatars.githubusercontent.com/u/3534502?v=4&s=48" width="48" height="48" alt="atalovesyou" title="atalovesyou"/></a> <a href="https://github.com/search?q=Azade"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Azade" title="Azade"/></a>
<a href="https://github.com/carlulsoe"><img src="https://avatars.githubusercontent.com/u/34673973?v=4&s=48" width="48" height="48" alt="carlulsoe" title="carlulsoe"/></a> <a href="https://github.com/search?q=ddyo"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="ddyo" title="ddyo"/></a> <a href="https://github.com/search?q=Erik"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Erik" title="Erik"/></a> <a href="https://github.com/jiulingyun"><img src="https://avatars.githubusercontent.com/u/126459548?v=4&s=48" width="48" height="48" alt="jiulingyun" title="jiulingyun"/></a> <a href="https://github.com/latitudeki5223"><img src="https://avatars.githubusercontent.com/u/119656367?v=4&s=48" width="48" height="48" alt="latitudeki5223" title="latitudeki5223"/></a> <a href="https://github.com/search?q=Manuel%20Maly"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Manuel Maly" title="Manuel Maly"/></a> <a href="https://github.com/search?q=Mourad%20Boustani"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Mourad Boustani" title="Mourad Boustani"/></a> <a href="https://github.com/odrobnik"><img src="https://avatars.githubusercontent.com/u/333270?v=4&s=48" width="48" height="48" alt="odrobnik" title="odrobnik"/></a> <a href="https://github.com/pcty-nextgen-ios-builder"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="pcty-nextgen-ios-builder" title="pcty-nextgen-ios-builder"/></a> <a href="https://github.com/search?q=Quentin"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Quentin" title="Quentin"/></a>
<a href="https://github.com/search?q=Randy%20Torres"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Randy Torres" title="Randy Torres"/></a> <a href="https://github.com/rhjoh"><img src="https://avatars.githubusercontent.com/u/105699450?v=4&s=48" width="48" height="48" alt="rhjoh" title="rhjoh"/></a> <a href="https://github.com/search?q=Rolf%20Fredheim"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="Rolf Fredheim" title="Rolf Fredheim"/></a> <a href="https://github.com/ronak-guliani"><img src="https://avatars.githubusercontent.com/u/23518228?v=4&s=48" width="48" height="48" alt="ronak-guliani" title="ronak-guliani"/></a> <a href="https://github.com/search?q=William%20Stock"><img src="assets/avatar-placeholder.svg" width="48" height="48" alt="William Stock" title="William Stock"/></a>
</p>

View File

@@ -22,7 +22,7 @@ android {
minSdk = 31
targetSdk = 36
versionCode = 202602030
versionName = "2026.2.4"
versionName = "2026.2.6"
}
buildTypes {

View File

@@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2026.2.4</string>
<string>2026.2.6</string>
<key>CFBundleVersion</key>
<string>20260202</string>
<key>NSAppTransportSecurity</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>2026.2.4</string>
<string>2026.2.6</string>
<key>CFBundleVersion</key>
<string>20260202</string>
</dict>

View File

@@ -81,7 +81,7 @@ targets:
properties:
CFBundleDisplayName: OpenClaw
CFBundleIconName: AppIcon
CFBundleShortVersionString: "2026.2.4"
CFBundleShortVersionString: "2026.2.6"
CFBundleVersion: "20260202"
UILaunchScreen: {}
UIApplicationSceneManifest:
@@ -130,5 +130,5 @@ targets:
path: Tests/Info.plist
properties:
CFBundleDisplayName: OpenClawTests
CFBundleShortVersionString: "2026.2.4"
CFBundleShortVersionString: "2026.2.6"
CFBundleVersion: "20260202"

View File

@@ -29,7 +29,7 @@ struct CronJobEditor: View {
@State var agentId: String = ""
@State var enabled: Bool = true
@State var sessionTarget: CronSessionTarget = .main
@State var wakeMode: CronWakeMode = .nextHeartbeat
@State var wakeMode: CronWakeMode = .now
@State var deleteAfterRun: Bool = false
enum ScheduleKind: String, CaseIterable, Identifiable { case at, every, cron; var id: String { rawValue } }
@@ -119,8 +119,8 @@ struct CronJobEditor: View {
GridRow {
self.gridLabel("Wake mode")
Picker("", selection: self.$wakeMode) {
Text("next-heartbeat").tag(CronWakeMode.nextHeartbeat)
Text("now").tag(CronWakeMode.now)
Text("next-heartbeat").tag(CronWakeMode.nextHeartbeat)
}
.labelsHidden()
.pickerStyle(.segmented)

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2026.2.4</string>
<string>2026.2.6</string>
<key>CFBundleVersion</key>
<string>202602020</string>
<key>CFBundleIconFile</key>

View File

@@ -1119,6 +1119,35 @@ public struct SessionsCompactParams: Codable, Sendable {
}
}
public struct SessionsUsageParams: Codable, Sendable {
public let key: String?
public let startdate: String?
public let enddate: String?
public let limit: Int?
public let includecontextweight: Bool?
public init(
key: String?,
startdate: String?,
enddate: String?,
limit: Int?,
includecontextweight: Bool?
) {
self.key = key
self.startdate = startdate
self.enddate = enddate
self.limit = limit
self.includecontextweight = includecontextweight
}
private enum CodingKeys: String, CodingKey {
case key
case startdate = "startDate"
case enddate = "endDate"
case limit
case includecontextweight = "includeContextWeight"
}
}
public struct ConfigGetParams: Codable, Sendable {
}
@@ -1996,6 +2025,8 @@ public struct CronRunLogEntry: Codable, Sendable {
public let status: AnyCodable?
public let error: String?
public let summary: String?
public let sessionid: String?
public let sessionkey: String?
public let runatms: Int?
public let durationms: Int?
public let nextrunatms: Int?
@@ -2007,6 +2038,8 @@ public struct CronRunLogEntry: Codable, Sendable {
status: AnyCodable?,
error: String?,
summary: String?,
sessionid: String?,
sessionkey: String?,
runatms: Int?,
durationms: Int?,
nextrunatms: Int?
@@ -2017,6 +2050,8 @@ public struct CronRunLogEntry: Codable, Sendable {
self.status = status
self.error = error
self.summary = summary
self.sessionid = sessionid
self.sessionkey = sessionkey
self.runatms = runatms
self.durationms = durationms
self.nextrunatms = nextrunatms
@@ -2028,6 +2063,8 @@ public struct CronRunLogEntry: Codable, Sendable {
case status
case error
case summary
case sessionid = "sessionId"
case sessionkey = "sessionKey"
case runatms = "runAtMs"
case durationms = "durationMs"
case nextrunatms = "nextRunAtMs"

View File

@@ -1119,6 +1119,35 @@ public struct SessionsCompactParams: Codable, Sendable {
}
}
public struct SessionsUsageParams: Codable, Sendable {
public let key: String?
public let startdate: String?
public let enddate: String?
public let limit: Int?
public let includecontextweight: Bool?
public init(
key: String?,
startdate: String?,
enddate: String?,
limit: Int?,
includecontextweight: Bool?
) {
self.key = key
self.startdate = startdate
self.enddate = enddate
self.limit = limit
self.includecontextweight = includecontextweight
}
private enum CodingKeys: String, CodingKey {
case key
case startdate = "startDate"
case enddate = "endDate"
case limit
case includecontextweight = "includeContextWeight"
}
}
public struct ConfigGetParams: Codable, Sendable {
}
@@ -1996,6 +2025,8 @@ public struct CronRunLogEntry: Codable, Sendable {
public let status: AnyCodable?
public let error: String?
public let summary: String?
public let sessionid: String?
public let sessionkey: String?
public let runatms: Int?
public let durationms: Int?
public let nextrunatms: Int?
@@ -2007,6 +2038,8 @@ public struct CronRunLogEntry: Codable, Sendable {
status: AnyCodable?,
error: String?,
summary: String?,
sessionid: String?,
sessionkey: String?,
runatms: Int?,
durationms: Int?,
nextrunatms: Int?
@@ -2017,6 +2050,8 @@ public struct CronRunLogEntry: Codable, Sendable {
self.status = status
self.error = error
self.summary = summary
self.sessionid = sessionid
self.sessionkey = sessionkey
self.runatms = runatms
self.durationms = durationms
self.nextrunatms = nextrunatms
@@ -2028,6 +2063,8 @@ public struct CronRunLogEntry: Codable, Sendable {
case status
case error
case summary
case sessionid = "sessionId"
case sessionkey = "sessionKey"
case runatms = "runAtMs"
case durationms = "durationMs"
case nextrunatms = "nextRunAtMs"

View File

@@ -17,6 +17,8 @@ the right time, and can optionally deliver output back to a chat.
If you want _“run this every morning”_ or _“poke the agent in 20 minutes”_,
cron is the mechanism.
Troubleshooting: [/automation/troubleshooting](/automation/troubleshooting)
## TL;DR
- Cron runs **inside the Gateway** (not inside the model).
@@ -40,7 +42,7 @@ openclaw cron add \
--delete-after-run
openclaw cron list
openclaw cron run <job-id> --force
openclaw cron run <job-id>
openclaw cron runs --id <job-id>
```
@@ -123,8 +125,8 @@ local timezone is used.
Main jobs enqueue a system event and optionally wake the heartbeat runner.
They must use `payload.kind = "systemEvent"`.
- `wakeMode: "next-heartbeat"` (default): event waits for the next scheduled heartbeat.
- `wakeMode: "now"`: event triggers an immediate heartbeat run.
- `wakeMode: "now"` (default): event triggers an immediate heartbeat run.
- `wakeMode: "next-heartbeat"`: event waits for the next scheduled heartbeat.
This is the best fit when you want the normal heartbeat prompt + main-session context.
See [Heartbeat](/gateway/heartbeat).
@@ -288,7 +290,7 @@ Notes:
- `sessionTarget` must be `"main"` or `"isolated"` and must match `payload.kind`.
- Optional fields: `agentId`, `description`, `enabled`, `deleteAfterRun` (defaults to true for `at`),
`delivery`.
- `wakeMode` defaults to `"next-heartbeat"` when omitted.
- `wakeMode` defaults to `"now"` when omitted.
### cron.update params
@@ -420,10 +422,11 @@ openclaw cron edit <jobId> --agent ops
openclaw cron edit <jobId> --clear-agent
```
Manual run (debug):
Manual run (force is the default, use `--due` to only run when due):
```bash
openclaw cron run <jobId> --force
openclaw cron run <jobId>
openclaw cron run <jobId> --due
```
Edit an existing job (patch fields):

View File

@@ -0,0 +1,122 @@
---
summary: "Troubleshoot cron and heartbeat scheduling and delivery"
read_when:
- Cron did not run
- Cron ran but no message was delivered
- Heartbeat seems silent or skipped
title: "Automation Troubleshooting"
---
# Automation troubleshooting
Use this page for scheduler and delivery issues (`cron` + `heartbeat`).
## Command ladder
```bash
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
```
Then run automation checks:
```bash
openclaw cron status
openclaw cron list
openclaw system heartbeat last
```
## Cron not firing
```bash
openclaw cron status
openclaw cron list
openclaw cron runs --id <jobId> --limit 20
openclaw logs --follow
```
Good output looks like:
- `cron status` reports enabled and a future `nextWakeAtMs`.
- Job is enabled and has a valid schedule/timezone.
- `cron runs` shows `ok` or explicit skip reason.
Common signatures:
- `cron: scheduler disabled; jobs will not run automatically` → cron disabled in config/env.
- `cron: timer tick failed` → scheduler tick crashed; inspect surrounding stack/log context.
- `reason: not-due` in run output → manual run called without `--force` and job not due yet.
## Cron fired but no delivery
```bash
openclaw cron runs --id <jobId> --limit 20
openclaw cron list
openclaw channels status --probe
openclaw logs --follow
```
Good output looks like:
- Run status is `ok`.
- Delivery mode/target are set for isolated jobs.
- Channel probe reports target channel connected.
Common signatures:
- Run succeeded but delivery mode is `none` → no external message is expected.
- Delivery target missing/invalid (`channel`/`to`) → run may succeed internally but skip outbound.
- Channel auth errors (`unauthorized`, `missing_scope`, `Forbidden`) → delivery blocked by channel credentials/permissions.
## Heartbeat suppressed or skipped
```bash
openclaw system heartbeat last
openclaw logs --follow
openclaw config get agents.defaults.heartbeat
openclaw channels status --probe
```
Good output looks like:
- Heartbeat enabled with non-zero interval.
- Last heartbeat result is `ran` (or skip reason is understood).
Common signatures:
- `heartbeat skipped` with `reason=quiet-hours` → outside `activeHours`.
- `requests-in-flight` → main lane busy; heartbeat deferred.
- `empty-heartbeat-file``HEARTBEAT.md` exists but has no actionable content.
- `alerts-disabled` → visibility settings suppress outbound heartbeat messages.
## Timezone and activeHours gotchas
```bash
openclaw config get agents.defaults.heartbeat.activeHours
openclaw config get agents.defaults.heartbeat.activeHours.timezone
openclaw config get agents.defaults.userTimezone || echo "agents.defaults.userTimezone not set"
openclaw cron list
openclaw logs --follow
```
Quick rules:
- `Config path not found: agents.defaults.userTimezone` means the key is unset; heartbeat falls back to host timezone (or `activeHours.timezone` if set).
- Cron without `--tz` uses gateway host timezone.
- Heartbeat `activeHours` uses configured timezone resolution (`user`, `local`, or explicit IANA tz).
- ISO timestamps without timezone are treated as UTC for cron `at` schedules.
Common signatures:
- Jobs run at the wrong wall-clock time after host timezone changes.
- Heartbeat always skipped during your daytime because `activeHours.timezone` is wrong.
Related:
- [/automation/cron-jobs](/automation/cron-jobs)
- [/gateway/heartbeat](/gateway/heartbeat)
- [/automation/cron-vs-heartbeat](/automation/cron-vs-heartbeat)
- [/concepts/timezone](/concepts/timezone)

View File

@@ -12,7 +12,7 @@ OpenClaw uses Brave Search as the default provider for `web_search`.
## Get an API key
1. Create a Brave Search API account at https://brave.com/search/api/
1. Create a Brave Search API account at [https://brave.com/search/api/](https://brave.com/search/api/)
2. In the dashboard, choose the **Data for Search** plan and generate an API key.
3. Store the key in config (recommended) or set `BRAVE_API_KEY` in the Gateway environment.

View File

@@ -27,6 +27,7 @@ Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. **R
1. Install the BlueBubbles server on your Mac (follow the instructions at [bluebubbles.app/install](https://bluebubbles.app/install)).
2. In the BlueBubbles config, enable the web API and set a password.
3. Run `openclaw onboard` and select BlueBubbles, or configure manually:
```json5
{
channels: {
@@ -39,6 +40,7 @@ Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. **R
},
}
```
4. Point BlueBubbles webhooks to your gateway (example: `https://your-gateway-host:3000/bluebubbles-webhook?password=<password>`).
5. Start the gateway; it will register the webhook handler and start pairing.
@@ -335,4 +337,4 @@ Prefer `chat_guid` for stable routing:
- OpenClaw auto-hides known-broken actions based on the BlueBubbles server's macOS version. If edit still appears on macOS 26 (Tahoe), disable it manually with `channels.bluebubbles.actions.edit=false`.
- For status/health info: `openclaw status --all` or `openclaw status --deep`.
For general channel workflow reference, see [Channels](/channels) and the [Plugins](/plugins) guide.
For general channel workflow reference, see [Channels](/channels) and the [Plugins](/plugin) guide.

View File

@@ -75,7 +75,7 @@ Choose **Feishu**, then enter the App ID and App Secret.
Visit [Feishu Open Platform](https://open.feishu.cn/app) and sign in.
Lark (global) tenants should use https://open.larksuite.com/app and set `domain: "lark"` in the Feishu config.
Lark (global) tenants should use [https://open.larksuite.com/app](https://open.larksuite.com/app) and set `domain: "lark"` in the Feishu config.
### 2. Create an app
@@ -261,10 +261,12 @@ After approval, you can chat normally.
- **Default**: `dmPolicy: "pairing"` (unknown users get a pairing code)
- **Approve pairing**:
```bash
openclaw pairing list feishu
openclaw pairing approve feishu <CODE>
```
- **Allowlist mode**: set `channels.feishu.allowFrom` with allowed Open IDs
### Group chats

View File

@@ -101,6 +101,7 @@ Use Tailscale Serve for the private dashboard and Funnel for the public webhook
If prompted, visit the authorization URL shown in the output to enable Funnel for this node in your tailnet policy.
5. **Verify the configuration:**
```bash
tailscale serve status
tailscale funnel status
@@ -225,6 +226,7 @@ This means the webhook handler isn't registered. Common causes:
If it shows "disabled", add `plugins.entries.googlechat.enabled: true` to your config.
3. **Gateway not restarted**: After adding config, restart the gateway:
```bash
openclaw gateway restart
```

View File

@@ -62,6 +62,28 @@ Disable with:
- Automation permission when sending.
- `channels.imessage.cliPath` can point to any command that proxies stdin/stdout (for example, a wrapper script that SSHes to another Mac and runs `imsg rpc`).
## Troubleshooting macOS Privacy and Security TCC
If sending/receiving fails (for example, `imsg rpc` exits non-zero, times out, or the gateway appears to hang), a common cause is a macOS permission prompt that was never approved.
macOS grants TCC permissions per app/process context. Approve prompts in the same context that runs `imsg` (for example, Terminal/iTerm, a LaunchAgent session, or an SSH-launched process).
Checklist:
- **Full Disk Access**: allow access for the process running OpenClaw (and any shell/SSH wrapper that executes `imsg`). This is required to read the Messages database (`chat.db`).
- **Automation → Messages**: allow the process running OpenClaw (and/or your terminal) to control **Messages.app** for outbound sends.
- **`imsg` CLI health**: verify `imsg` is installed and supports RPC (`imsg rpc --help`).
Tip: If OpenClaw is running headless (LaunchAgent/systemd/SSH) the macOS prompt can be easy to miss. Run a one-time interactive command in a GUI terminal to force the prompt, then retry:
```bash
imsg chats --limit 1
# or
imsg send <handle> "test"
```
Related macOS folder permissions (Desktop/Documents/Downloads): [/platforms/mac/permissions](/platforms/mac/permissions).
## Setup (fast path)
1. Ensure Messages is signed in on this Mac.
@@ -81,7 +103,7 @@ If you want the bot to send from a **separate iMessage identity** (and keep your
6. Set up SSH so `ssh <bot-macos-user>@localhost true` works without a password.
7. Point `channels.imessage.accounts.bot.cliPath` at an SSH wrapper that runs `imsg` as the bot user.
First-run note: sending/receiving may require GUI approvals (Automation + Full Disk Access) in the _bot macOS user_. If `imsg rpc` looks stuck or exits, log into that user (Screen Sharing helps), run a one-time `imsg chats --limit 1` / `imsg send ...`, approve prompts, then retry.
First-run note: sending/receiving may require GUI approvals (Automation + Full Disk Access) in the _bot macOS user_. If `imsg rpc` looks stuck or exits, log into that user (Screen Sharing helps), run a one-time `imsg chats --limit 1` / `imsg send ...`, approve prompts, then retry. See [Troubleshooting macOS Privacy and Security TCC](#troubleshooting-macos-privacy-and-security-tcc).
Example wrapper (`chmod +x`). Replace `<bot-macos-user>` with your actual macOS username:

View File

@@ -34,7 +34,7 @@ openclaw plugins install ./extensions/line
## Setup
1. Create a LINE Developers account and open the Console:
https://developers.line.biz/console/
[https://developers.line.biz/console/](https://developers.line.biz/console/)
2. Create (or pick) a Provider and add a **Messaging API** channel.
3. Copy the **Channel access token** and **Channel secret** from the channel settings.
4. Enable **Use webhook** in the Messaging API settings.

View File

@@ -74,7 +74,7 @@ Details: [Plugins](/plugin)
- When set, `channels.matrix.userId` should be the full Matrix ID (example: `@bot:example.org`).
5. Restart the gateway (or finish onboarding).
6. Start a DM with the bot or invite it to a room from any Matrix client
(Element, Beeper, etc.; see https://matrix.org/ecosystem/clients/). Beeper requires E2EE,
(Element, Beeper, etc.; see [https://matrix.org/ecosystem/clients/](https://matrix.org/ecosystem/clients/)). Beeper requires E2EE,
so set `channels.matrix.encryption: true` and verify the device.
Minimal config (access token, user ID auto-fetched):
@@ -202,6 +202,32 @@ Once verified, the bot can decrypt messages in encrypted rooms.
| Location | ✅ Supported (geo URI; altitude ignored) |
| Native commands | ✅ Supported |
## Troubleshooting
Run this ladder first:
```bash
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
```
Then confirm DM pairing state if needed:
```bash
openclaw pairing list matrix
```
Common failures:
- Logged in but room messages ignored: room blocked by `groupPolicy` or room allowlist.
- DMs ignored: sender pending approval when `channels.matrix.dm.policy="pairing"`.
- Encrypted rooms fail: crypto support or encryption settings mismatch.
For triage flow: [/channels/troubleshooting](/channels/troubleshooting).
## Configuration reference (Matrix)
Full configuration: [Configuration](/gateway/configuration)

View File

@@ -558,6 +558,7 @@ Bots don't have a personal OneDrive drive (the `/me/drive` Graph API endpoint do
```
4. **Configure OpenClaw:**
```json5
{
channels: {
@@ -747,7 +748,7 @@ Bots have limited support in private channels:
- **"Icon file cannot be empty":** The manifest references icon files that are 0 bytes. Create valid PNG icons (32x32 for `outline.png`, 192x192 for `color.png`).
- **"webApplicationInfo.Id already in use":** The app is still installed in another team/chat. Find and uninstall it first, or wait 5-10 minutes for propagation.
- **"Something went wrong" on upload:** Upload via https://admin.teams.microsoft.com instead, open browser DevTools (F12) → Network tab, and check the response body for the actual error.
- **"Something went wrong" on upload:** Upload via [https://admin.teams.microsoft.com](https://admin.teams.microsoft.com) instead, open browser DevTools (F12) → Network tab, and check the response body for the actual error.
- **Sideload failing:** Try "Upload an app to your org's app catalog" instead of "Upload a custom app" - this often bypasses sideload restrictions.
### RSC permissions not working

View File

@@ -34,9 +34,11 @@ Details: [Plugins](/plugin)
1. Install the Nextcloud Talk plugin.
2. On your Nextcloud server, create a bot:
```bash
./occ talk:bot:install "OpenClaw" "<shared-secret>" "<webhook-url>" --feature reaction
```
3. Enable the bot in the target room settings.
4. Configure OpenClaw:
- Config: `channels.nextcloud-talk.baseUrl` + `channels.nextcloud-talk.botSecret`

View File

@@ -168,6 +168,32 @@ Config:
- Groups: `signal:group:<groupId>`.
- Usernames: `username:<name>` (if supported by your Signal account).
## Troubleshooting
Run this ladder first:
```bash
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
```
Then confirm DM pairing state if needed:
```bash
openclaw pairing list signal
```
Common failures:
- Daemon reachable but no replies: verify account/daemon settings (`httpUrl`, `account`) and receive mode.
- DMs ignored: sender is pending pairing approval.
- Group messages ignored: group sender/mention gating blocks delivery.
For triage flow: [/channels/troubleshooting](/channels/troubleshooting).
## Configuration reference (Signal)
Full configuration: [Configuration](/gateway/configuration)

View File

@@ -30,7 +30,7 @@ Minimal config:
### Setup
1. Create a Slack app (From scratch) in https://api.slack.com/apps.
1. Create a Slack app (From scratch) in [https://api.slack.com/apps](https://api.slack.com/apps).
2. **Socket Mode** → toggle on. Then go to **Basic Information****App-Level Tokens****Generate Token and Scopes** with scope `connections:write`. Copy the **App Token** (`xapp-...`).
3. **OAuth & Permissions** → add bot token scopes (use the manifest below). Click **Install to Workspace**. Copy the **Bot User OAuth Token** (`xoxb-...`).
4. Optional: **OAuth & Permissions** → add **User Token Scopes** (see the read-only list below). Reinstall the app and copy the **User OAuth Token** (`xoxp-...`).
@@ -49,7 +49,7 @@ Use the manifest below so scopes and events stay in sync.
Multi-account support: use `channels.slack.accounts` with per-account tokens and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern.
### OpenClaw config (minimal)
### OpenClaw config (Socket mode)
Set tokens via env vars (recommended):
@@ -130,7 +130,7 @@ Example with userTokenReadOnly explicitly set (allow user token writes):
Use HTTP webhook mode when your Gateway is reachable by Slack over HTTPS (typical for server deployments).
HTTP mode uses the Events API + Interactivity + Slash Commands with a shared request URL.
### Setup
### Setup (HTTP mode)
1. Create a Slack app and **disable Socket Mode** (optional if you only use HTTP).
2. **Basic Information** → copy the **Signing Secret**.
@@ -260,30 +260,30 @@ If you enable native commands, add one `slash_commands` entry per command you wa
Slack's Conversations API is type-scoped: you only need the scopes for the
conversation types you actually touch (channels, groups, im, mpim). See
https://docs.slack.dev/apis/web-api/using-the-conversations-api/ for the overview.
[https://docs.slack.dev/apis/web-api/using-the-conversations-api/](https://docs.slack.dev/apis/web-api/using-the-conversations-api/) for the overview.
### Bot token scopes (required)
- `chat:write` (send/update/delete messages via `chat.postMessage`)
https://docs.slack.dev/reference/methods/chat.postMessage
[https://docs.slack.dev/reference/methods/chat.postMessage](https://docs.slack.dev/reference/methods/chat.postMessage)
- `im:write` (open DMs via `conversations.open` for user DMs)
https://docs.slack.dev/reference/methods/conversations.open
[https://docs.slack.dev/reference/methods/conversations.open](https://docs.slack.dev/reference/methods/conversations.open)
- `channels:history`, `groups:history`, `im:history`, `mpim:history`
https://docs.slack.dev/reference/methods/conversations.history
[https://docs.slack.dev/reference/methods/conversations.history](https://docs.slack.dev/reference/methods/conversations.history)
- `channels:read`, `groups:read`, `im:read`, `mpim:read`
https://docs.slack.dev/reference/methods/conversations.info
[https://docs.slack.dev/reference/methods/conversations.info](https://docs.slack.dev/reference/methods/conversations.info)
- `users:read` (user lookup)
https://docs.slack.dev/reference/methods/users.info
[https://docs.slack.dev/reference/methods/users.info](https://docs.slack.dev/reference/methods/users.info)
- `reactions:read`, `reactions:write` (`reactions.get` / `reactions.add`)
https://docs.slack.dev/reference/methods/reactions.get
https://docs.slack.dev/reference/methods/reactions.add
[https://docs.slack.dev/reference/methods/reactions.get](https://docs.slack.dev/reference/methods/reactions.get)
[https://docs.slack.dev/reference/methods/reactions.add](https://docs.slack.dev/reference/methods/reactions.add)
- `pins:read`, `pins:write` (`pins.list` / `pins.add` / `pins.remove`)
https://docs.slack.dev/reference/scopes/pins.read
https://docs.slack.dev/reference/scopes/pins.write
[https://docs.slack.dev/reference/scopes/pins.read](https://docs.slack.dev/reference/scopes/pins.read)
[https://docs.slack.dev/reference/scopes/pins.write](https://docs.slack.dev/reference/scopes/pins.write)
- `emoji:read` (`emoji.list`)
https://docs.slack.dev/reference/scopes/emoji.read
[https://docs.slack.dev/reference/scopes/emoji.read](https://docs.slack.dev/reference/scopes/emoji.read)
- `files:write` (uploads via `files.uploadV2`)
https://docs.slack.dev/messaging/working-with-files/#upload
[https://docs.slack.dev/messaging/working-with-files/#upload](https://docs.slack.dev/messaging/working-with-files/#upload)
### User token scopes (optional, read-only by default)
@@ -302,9 +302,9 @@ Add these under **User Token Scopes** if you configure `channels.slack.userToken
- `mpim:write` (only if we add group-DM open/DM start via `conversations.open`)
- `groups:write` (only if we add private-channel management: create/rename/invite/archive)
- `chat:write.public` (only if we want to post to channels the bot isn't in)
https://docs.slack.dev/reference/scopes/chat.write.public
[https://docs.slack.dev/reference/scopes/chat.write.public](https://docs.slack.dev/reference/scopes/chat.write.public)
- `users:read.email` (only if we need email fields from `users.info`)
https://docs.slack.dev/changelog/2017-04-narrowing-email-access
[https://docs.slack.dev/changelog/2017-04-narrowing-email-access](https://docs.slack.dev/changelog/2017-04-narrowing-email-access)
- `files:read` (only if we start listing/reading file metadata)
## Config
@@ -537,6 +537,32 @@ Slack tool actions can be gated with `channels.slack.actions.*`:
scopes you expect (`chat:write`, `reactions:write`, `pins:write`,
`files:write`) or those operations will fail.
## Troubleshooting
Run this ladder first:
```bash
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
```
Then confirm DM pairing state if needed:
```bash
openclaw pairing list slack
```
Common failures:
- Connected but no channel replies: channel blocked by `groupPolicy` or not in `channels.slack.channels` allowlist.
- DMs ignored: sender not approved when `channels.slack.dm.policy="pairing"`.
- API errors (`missing_scope`, `not_in_channel`, auth failures): bot/app tokens or Slack scopes are incomplete.
For triage flow: [/channels/troubleshooting](/channels/troubleshooting).
## Notes
- Mention gating is controlled via `channels.slack.channels` (set `requireMention` to `true`); `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`) also count as mentions.

View File

@@ -147,7 +147,7 @@ You can add custom commands to the menu via config:
}
```
## Troubleshooting
## Setup troubleshooting (commands)
- `setMyCommands failed` in logs usually means outbound HTTPS/DNS is blocked to `api.telegram.org`.
- If you see `sendMessage` or `sendChatAction` failures, check IPv6 routing and DNS.
@@ -365,6 +365,7 @@ Alternate (official Bot API):
1. DM your bot.
2. Fetch updates with your bot token and read `message.from.id`:
```bash
curl "https://api.telegram.org/bot<bot_token>/getUpdates"
```

View File

@@ -1,29 +1,116 @@
---
summary: "Channel-specific troubleshooting shortcuts (Discord/Telegram/WhatsApp)"
summary: "Fast channel level troubleshooting with per channel failure signatures and fixes"
read_when:
- A channel connects but messages dont flow
- Investigating channel misconfiguration (intents, permissions, privacy mode)
- Channel transport says connected but replies fail
- You need channel specific checks before deep provider docs
title: "Channel Troubleshooting"
---
# Channel troubleshooting
Start with:
Use this page when a channel connects but behavior is wrong.
## Command ladder
Run these in order first:
```bash
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
```
`channels status --probe` prints warnings when it can detect common channel misconfigurations, and includes small live checks (credentials, some permissions/membership).
Healthy baseline:
## Channels
- `Runtime: running`
- `RPC probe: ok`
- Channel probe shows connected/ready
- Discord: [/channels/discord#troubleshooting](/channels/discord#troubleshooting)
- Telegram: [/channels/telegram#troubleshooting](/channels/telegram#troubleshooting)
- WhatsApp: [/channels/whatsapp#troubleshooting-quick](/channels/whatsapp#troubleshooting-quick)
## WhatsApp
## Telegram quick fixes
### WhatsApp failure signatures
- Logs show `HttpError: Network request for 'sendMessage' failed` or `sendChatAction` → check IPv6 DNS. If `api.telegram.org` resolves to IPv6 first and the host lacks IPv6 egress, force IPv4 or enable IPv6. See [/channels/telegram#troubleshooting](/channels/telegram#troubleshooting).
- Logs show `setMyCommands failed` → check outbound HTTPS and DNS reachability to `api.telegram.org` (common on locked-down VPS or proxies).
| Symptom | Fastest check | Fix |
| ------------------------------- | --------------------------------------------------- | ------------------------------------------------------- |
| Connected but no DM replies | `openclaw pairing list whatsapp` | Approve sender or switch DM policy/allowlist. |
| Group messages ignored | Check `requireMention` + mention patterns in config | Mention the bot or relax mention policy for that group. |
| Random disconnect/relogin loops | `openclaw channels status --probe` + logs | Re-login and verify credentials directory is healthy. |
Full troubleshooting: [/channels/whatsapp#troubleshooting-quick](/channels/whatsapp#troubleshooting-quick)
## Telegram
### Telegram failure signatures
| Symptom | Fastest check | Fix |
| --------------------------------- | ----------------------------------------------- | --------------------------------------------------------- |
| `/start` but no usable reply flow | `openclaw pairing list telegram` | Approve pairing or change DM policy. |
| Bot online but group stays silent | Verify mention requirement and bot privacy mode | Disable privacy mode for group visibility or mention bot. |
| Send failures with network errors | Inspect logs for Telegram API call failures | Fix DNS/IPv6/proxy routing to `api.telegram.org`. |
Full troubleshooting: [/channels/telegram#troubleshooting](/channels/telegram#troubleshooting)
## Discord
### Discord failure signatures
| Symptom | Fastest check | Fix |
| ------------------------------- | ----------------------------------- | --------------------------------------------------------- |
| Bot online but no guild replies | `openclaw channels status --probe` | Allow guild/channel and verify message content intent. |
| Group messages ignored | Check logs for mention gating drops | Mention bot or set guild/channel `requireMention: false`. |
| DM replies missing | `openclaw pairing list discord` | Approve DM pairing or adjust DM policy. |
Full troubleshooting: [/channels/discord#troubleshooting](/channels/discord#troubleshooting)
## Slack
### Slack failure signatures
| Symptom | Fastest check | Fix |
| -------------------------------------- | ----------------------------------------- | ------------------------------------------------- |
| Socket mode connected but no responses | `openclaw channels status --probe` | Verify app token + bot token and required scopes. |
| DMs blocked | `openclaw pairing list slack` | Approve pairing or relax DM policy. |
| Channel message ignored | Check `groupPolicy` and channel allowlist | Allow the channel or switch policy to `open`. |
Full troubleshooting: [/channels/slack#troubleshooting](/channels/slack#troubleshooting)
## iMessage and BlueBubbles
### iMessage and BlueBubbles failure signatures
| Symptom | Fastest check | Fix |
| -------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------- |
| No inbound events | Verify webhook/server reachability and app permissions | Fix webhook URL or BlueBubbles server state. |
| Can send but no receive on macOS | Check macOS privacy permissions for Messages automation | Re-grant TCC permissions and restart channel process. |
| DM sender blocked | `openclaw pairing list imessage` or `openclaw pairing list bluebubbles` | Approve pairing or update allowlist. |
Full troubleshooting:
- [/channels/imessage#troubleshooting-macos-privacy-and-security-tcc](/channels/imessage#troubleshooting-macos-privacy-and-security-tcc)
- [/channels/bluebubbles#troubleshooting](/channels/bluebubbles#troubleshooting)
## Signal
### Signal failure signatures
| Symptom | Fastest check | Fix |
| ------------------------------- | ------------------------------------------ | -------------------------------------------------------- |
| Daemon reachable but bot silent | `openclaw channels status --probe` | Verify `signal-cli` daemon URL/account and receive mode. |
| DM blocked | `openclaw pairing list signal` | Approve sender or adjust DM policy. |
| Group replies do not trigger | Check group allowlist and mention patterns | Add sender/group or loosen gating. |
Full troubleshooting: [/channels/signal#troubleshooting](/channels/signal#troubleshooting)
## Matrix
### Matrix failure signatures
| Symptom | Fastest check | Fix |
| ----------------------------------- | -------------------------------------------- | ----------------------------------------------- |
| Logged in but ignores room messages | `openclaw channels status --probe` | Check `groupPolicy` and room allowlist. |
| DMs do not process | `openclaw pairing list matrix` | Approve sender or adjust DM policy. |
| Encrypted rooms fail | Verify crypto module and encryption settings | Enable encryption support and rejoin/sync room. |
Full troubleshooting: [/channels/matrix#troubleshooting](/channels/matrix#troubleshooting)

View File

@@ -34,7 +34,7 @@ Details: [Plugins](/plugin)
- Select **Bot Token**
- Verify scopes `chat:read` and `chat:write` are selected
- Copy the **Client ID** and **Access Token**
3. Find your Twitch user ID: https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/
3. Find your Twitch user ID: [https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/](https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/)
4. Configure the token:
- Env: `OPENCLAW_TWITCH_ACCESS_TOKEN=...` (default account only)
- Or config: `channels.twitch.accessToken`
@@ -123,7 +123,7 @@ Prefer `allowFrom` for a hard allowlist. Use `allowedRoles` instead if you want
**Why user IDs?** Usernames can change, allowing impersonation. User IDs are permanent.
Find your Twitch user ID: https://www.streamweasels.com/tools/convert-twitch-username-%20to-user-id/ (Convert your Twitch username to ID)
Find your Twitch user ID: [https://www.streamweasels.com/tools/convert-twitch-username-%20to-user-id/](https://www.streamweasels.com/tools/convert-twitch-username-%20to-user-id/) (Convert your Twitch username to ID)
## Token refresh (optional)

View File

@@ -205,11 +205,13 @@ The wizard uses it to set your **allowlist/owner** so your own DMs are permitted
- `Body` is the current message body with envelope.
- Quoted reply context is **always appended**:
```
[Replying to +1555 id:ABC123]
<quoted text or <media:...>>
[/Replying]
```
- Reply metadata also set:
- `ReplyToId` = stanzaId
- `ReplyToBody` = quoted body or media placeholder

View File

@@ -57,7 +57,7 @@ It is a good fit for support or notifications where you want deterministic routi
### 1) Create a bot token (Zalo Bot Platform)
1. Go to **https://bot.zaloplatforms.com** and sign in.
1. Go to [https://bot.zaloplatforms.com](https://bot.zaloplatforms.com) and sign in.
2. Create a new bot and configure its settings.
3. Copy the bot token (format: `12345689:abc-xyz`).

View File

@@ -14,7 +14,7 @@ Provided by the active memory plugin (default: `memory-core`; set `plugins.slots
Related:
- Memory concept: [Memory](/concepts/memory)
- Plugins: [Plugins](/plugins)
- Plugins: [Plugins](/plugin)
## Examples

View File

@@ -110,9 +110,11 @@ Details: [Gateway protocol](/gateway/protocol), [Pairing](/start/pairing),
- Preferred: Tailscale or VPN.
- Alternative: SSH tunnel
```bash
ssh -N -L 18789:127.0.0.1:18789 user@host
```
- The same handshake + auth token apply over the tunnel.
- TLS + optional pinning can be enabled for WS in remote setups.

View File

@@ -39,12 +39,13 @@ otherwise -> reply
![Group message flow](/images/groups-flow.svg)
If you want...
| Goal | What to set |
|------|-------------|
| Allow all groups but only reply on @mentions | `groups: { "*": { requireMention: true } }` |
| Disable all group replies | `groupPolicy: "disabled"` |
| Only specific groups | `groups: { "<group-id>": { ... } }` (no `"*"` key) |
| Only you can trigger in groups | `groupPolicy: "allowlist"`, `groupAllowFrom: ["+1555..."]` |
| Goal | What to set |
| -------------------------------------------- | ---------------------------------------------------------- |
| Allow all groups but only reply on @mentions | `groups: { "*": { requireMention: true } }` |
| Disable all group replies | `groupPolicy: "disabled"` |
| Only specific groups | `groups: { "<group-id>": { ... } }` (no `"*"` key) |
| Only you can trigger in groups | `groupPolicy: "allowlist"`, `groupAllowFrom: ["+1555..."]` |
## Session keys

View File

@@ -25,7 +25,7 @@ The default workspace layout uses two memory layers:
- **Only load in the main, private session** (never in group contexts).
These files live under the workspace (`agents.defaults.workspace`, default
`~/clawd`). See [Agent workspace](/concepts/agent-workspace) for the full layout.
`~/.openclaw/workspace`). See [Agent workspace](/concepts/agent-workspace) for the full layout.
## When to write memory
@@ -88,7 +88,8 @@ Defaults:
1. `local` if a `memorySearch.local.modelPath` is configured and the file exists.
2. `openai` if an OpenAI key can be resolved.
3. `gemini` if a Gemini key can be resolved.
4. Otherwise memory search stays disabled until configured.
4. `voyage` if a Voyage key can be resolved.
5. Otherwise memory search stays disabled until configured.
- Local mode uses node-llama-cpp and may require `pnpm approve-builds`.
- Uses sqlite-vec (when available) to accelerate vector search inside SQLite.
@@ -96,7 +97,8 @@ Remote embeddings **require** an API key for the embedding provider. OpenClaw
resolves keys from auth profiles, `models.providers.*.apiKey`, or environment
variables. Codex OAuth only covers chat/completions and does **not** satisfy
embeddings for memory search. For Gemini, use `GEMINI_API_KEY` or
`models.providers.google.apiKey`. When using a custom OpenAI-compatible endpoint,
`models.providers.google.apiKey`. For Voyage, use `VOYAGE_API_KEY` or
`models.providers.voyage.apiKey`. When using a custom OpenAI-compatible endpoint,
set `memorySearch.remote.apiKey` (and optional `memorySearch.remote.headers`).
### QMD backend (experimental)
@@ -109,7 +111,7 @@ out to QMD for retrieval. Key points:
**Prereqs**
- Disabled by default. Opt in per-config (`memory.backend = "qmd"`).
- Install the QMD CLI separately (`bun install -g github.com/tobi/qmd` or grab
- Install the QMD CLI separately (`bun install -g https://github.com/tobi/qmd` or grab
a release) and make sure the `qmd` binary is on the gateways `PATH`.
- QMD needs an SQLite build that allows extensions (`brew install sqlite` on
macOS).
@@ -302,8 +304,8 @@ Why OpenAI batch is fast + cheap:
- For large backfills, OpenAI is typically the fastest option we support because we can submit many embedding requests in a single batch job and let OpenAI process them asynchronously.
- OpenAI offers discounted pricing for Batch API workloads, so large indexing runs are usually cheaper than sending the same requests synchronously.
- See the OpenAI Batch API docs and pricing for details:
- https://platform.openai.com/docs/api-reference/batch
- https://platform.openai.com/pricing
- [https://platform.openai.com/docs/api-reference/batch](https://platform.openai.com/docs/api-reference/batch)
- [https://platform.openai.com/pricing](https://platform.openai.com/pricing)
Config example:

View File

@@ -136,14 +136,14 @@ Moonshot uses OpenAI-compatible endpoints, so configure it as a custom provider:
Kimi K2 model IDs:
{/_ moonshot-kimi-k2-model-refs:start _/ && null}
{/_moonshot-kimi-k2-model-refs:start_/ && null}
- `moonshot/kimi-k2.5`
- `moonshot/kimi-k2-0905-preview`
- `moonshot/kimi-k2-turbo-preview`
- `moonshot/kimi-k2-thinking`
- `moonshot/kimi-k2-thinking-turbo`
{/_ moonshot-kimi-k2-model-refs:end _/ && null}
{/_moonshot-kimi-k2-model-refs:end_/ && null}
```json5
{
@@ -242,7 +242,7 @@ Ollama is a local LLM runtime that provides an OpenAI-compatible API:
- Provider: `ollama`
- Auth: None required (local server)
- Example model: `ollama/llama3.3`
- Installation: https://ollama.ai
- Installation: [https://ollama.ai](https://ollama.ai)
```bash
# Install Ollama, then pull a model:

View File

@@ -17,7 +17,7 @@ Use `session.dmScope` to control how **direct messages** are grouped:
- `per-account-channel-peer`: isolate by account + channel + sender (recommended for multi-account inboxes).
Use `session.identityLinks` to map provider-prefixed peer ids to a canonical identity so the same person shares a DM session across channels when using `per-peer`, `per-channel-peer`, or `per-account-channel-peer`.
### Secure DM mode (recommended for multi-user setups)
## Secure DM mode (recommended for multi-user setups)
> **Security Warning:** If your agent can receive DMs from **multiple people**, you should strongly consider enabling secure DM mode. Without it, all users share the same conversation context, which can leak private information between users.

View File

@@ -110,6 +110,6 @@ This keeps the base prompt small while still enabling targeted skill usage.
When available, the system prompt includes a **Documentation** section that points to the
local OpenClaw docs directory (either `docs/` in the repo workspace or the bundled npm
package docs) and also notes the public mirror, source repo, community Discord, and
ClawHub (https://clawhub.com) for skills discovery. The prompt instructs the model to consult local docs first
ClawHub ([https://clawhub.com](https://clawhub.com)) for skills discovery. The prompt instructs the model to consult local docs first
for OpenClaw behavior, commands, configuration, or architecture, and to run
`openclaw status` itself when possible (asking the user only when it lacks access).

View File

@@ -280,7 +280,7 @@ Unknown frame types are preserved as raw payloads for forward compatibility.
Generated JSON Schema is in the repo at `dist/protocol.schema.json`. The
published raw file is typically available at:
- https://raw.githubusercontent.com/openclaw/openclaw/main/dist/protocol.schema.json
- [https://raw.githubusercontent.com/openclaw/openclaw/main/dist/protocol.schema.json](https://raw.githubusercontent.com/openclaw/openclaw/main/dist/protocol.schema.json)
## When you change schemas

View File

@@ -62,19 +62,21 @@ node --import tsx scripts/repro/tsx-name-repro.ts
- Use Bun for dev scripts (current temporary revert).
- Use Node + tsc watch, then run compiled output:
```bash
pnpm exec tsc --watch --preserveWatchOutput
node --watch openclaw.mjs status
```
- Confirmed locally: `pnpm exec tsc -p tsconfig.json` + `node openclaw.mjs status` works on Node 25.
- Disable esbuild keepNames in the TS loader if possible (prevents `__name` helper insertion); tsx does not currently expose this.
- Test Node LTS (22/24) with `tsx` to see if the issue is Node 25specific.
## References
- https://opennext.js.org/cloudflare/howtos/keep_names
- https://esbuild.github.io/api/#keep-names
- https://github.com/evanw/esbuild/issues/1031
- [https://opennext.js.org/cloudflare/howtos/keep_names](https://opennext.js.org/cloudflare/howtos/keep_names)
- [https://esbuild.github.io/api/#keep-names](https://esbuild.github.io/api/#keep-names)
- [https://github.com/evanw/esbuild/issues/1031](https://github.com/evanw/esbuild/issues/1031)
## Next steps

View File

@@ -98,6 +98,10 @@
"source": "/opencode",
"destination": "/providers/opencode"
},
{
"source": "/qianfan",
"destination": "/providers/qianfan"
},
{
"source": "/mattermost",
"destination": "/channels/mattermost"
@@ -660,7 +664,7 @@
},
{
"source": "/troubleshooting",
"destination": "/gateway/troubleshooting"
"destination": "/help/troubleshooting"
},
{
"source": "/web/tui",
@@ -801,14 +805,8 @@
"pages": ["install/index", "install/installer"]
},
{
"group": "Install methods",
"pages": [
"install/node",
"install/docker",
"install/nix",
"install/ansible",
"install/bun"
]
"group": "Other install methods",
"pages": ["install/docker", "install/nix", "install/ansible", "install/bun"]
},
{
"group": "Maintenance",
@@ -968,6 +966,7 @@
"hooks/soul-evil",
"automation/cron-jobs",
"automation/cron-vs-heartbeat",
"automation/troubleshooting",
"automation/webhook",
"automation/gmail-pubsub",
"automation/poll",
@@ -978,6 +977,7 @@
"group": "Media and devices",
"pages": [
"nodes/index",
"nodes/troubleshooting",
"nodes/images",
"nodes/audio",
"nodes/camera",
@@ -1012,7 +1012,8 @@
"providers/opencode",
"providers/glm",
"providers/zai",
"providers/synthetic"
"providers/synthetic",
"providers/qianfan"
]
}
]
@@ -1221,6 +1222,7 @@
{
"group": "Environment and debugging",
"pages": [
"install/node",
"environment",
"debugging",
"testing",
@@ -1230,7 +1232,7 @@
},
{
"group": "Developer workflows",
"pages": ["start/setup"]
"pages": ["start/setup", "help/submitting-a-pr", "help/submitting-an-issue"]
},
{
"group": "Docs meta",

View File

@@ -105,10 +105,13 @@ The Gateway advertises small nonsecret hints to make UI flows convenient:
Useful builtin tools:
- Browse instances:
```bash
dns-sd -B _openclaw-gw._tcp local.
```
- Resolve one instance (replace `<instance>`):
```bash
dns-sd -L "<instance>" _openclaw-gw._tcp local.
```

View File

@@ -1310,13 +1310,14 @@ Thread session isolation:
- `channels.slack.thread.inheritParent` controls whether new thread sessions inherit the parent channel transcript (default: false).
Slack action groups (gate `slack` tool actions):
| Action group | Default | Notes |
| --- | --- | --- |
| reactions | enabled | React + list reactions |
| messages | enabled | Read/send/edit/delete |
| pins | enabled | Pin/unpin/list |
| memberInfo | enabled | Member info |
| emojiList | enabled | Custom emoji list |
| Action group | Default | Notes |
| ------------ | ------- | ---------------------- |
| reactions | enabled | React + list reactions |
| messages | enabled | Read/send/edit/delete |
| pins | enabled | Pin/unpin/list |
| memberInfo | enabled | Member info |
| emojiList | enabled | Custom emoji list |
### `channels.mattermost` (bot token)
@@ -1452,7 +1453,7 @@ working directory). The path must exist to be used.
### `agents.defaults.skipBootstrap`
Disables automatic creation of the workspace bootstrap files (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, and `BOOTSTRAP.md`).
Disables automatic creation of the workspace bootstrap files (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, and `BOOTSTRAP.md`).
Use this for pre-seeded deployments where your workspace files come from a repo.
@@ -1977,11 +1978,13 @@ Block streaming:
- `agents.defaults.blockStreamingChunk`: soft chunking for streamed blocks. Defaults to
8001200 chars, prefers paragraph breaks (`\n\n`), then newlines, then sentences.
Example:
```json5
{
agents: { defaults: { blockStreamingChunk: { minChars: 800, maxChars: 1200 } } },
}
```
- `agents.defaults.blockStreamingCoalesce`: merge streamed blocks before sending.
Defaults to `{ idleMs: 1000 }` and inherits `minChars` from `blockStreamingChunk`
with `maxChars` capped to the channel text limit. Signal/Slack/Discord/Google Chat default
@@ -1995,11 +1998,13 @@ Block streaming:
Modes: `off` (default), `natural` (8002500ms), `custom` (use `minMs`/`maxMs`).
Per-agent override: `agents.list[].humanDelay`.
Example:
```json5
{
agents: { defaults: { humanDelay: { mode: "natural" } } },
}
```
See [/concepts/streaming](/concepts/streaming) for behavior + chunking details.
Typing indicators:
@@ -2065,7 +2070,7 @@ of `every`, keep `HEARTBEAT.md` tiny, and/or choose a cheaper `model`.
- `tools.web.fetch.readability` (default true; disable to use basic HTML cleanup only)
- `tools.web.fetch.firecrawl.enabled` (default true when an API key is set)
- `tools.web.fetch.firecrawl.apiKey` (optional; defaults to `FIRECRAWL_API_KEY`)
- `tools.web.fetch.firecrawl.baseUrl` (default https://api.firecrawl.dev)
- `tools.web.fetch.firecrawl.baseUrl` (default [https://api.firecrawl.dev](https://api.firecrawl.dev))
- `tools.web.fetch.firecrawl.onlyMainContent` (default true)
- `tools.web.fetch.firecrawl.maxAgeMs` (optional)
- `tools.web.fetch.firecrawl.timeoutSeconds` (optional)
@@ -2481,7 +2486,7 @@ Select the model via `agents.defaults.model.primary` (provider/model).
OpenCode Zen is a multi-model gateway with per-model endpoints. OpenClaw uses
the built-in `opencode` provider from pi-ai; set `OPENCODE_API_KEY` (or
`OPENCODE_ZEN_API_KEY`) from https://opencode.ai/auth.
`OPENCODE_ZEN_API_KEY`) from [https://opencode.ai/auth](https://opencode.ai/auth).
Notes:
@@ -3173,8 +3178,7 @@ Defaults:
Requests must include the hook token:
- `Authorization: Bearer <token>` **or**
- `x-openclaw-token: <token>` **or**
- `?token=<token>`
- `x-openclaw-token: <token>`
Endpoints:
@@ -3367,7 +3371,7 @@ openclaw dns setup --apply
}
```
## Template variables
## Media model template variables
Template placeholders are expanded in `tools.media.*.models[].args` and `tools.media.models[].args` (and any future templated argument fields).

View File

@@ -13,6 +13,8 @@ title: "Heartbeat"
Heartbeat runs **periodic agent turns** in the main session so the model can
surface anything that needs attention without spamming you.
Troubleshooting: [/automation/troubleshooting](/automation/troubleshooting)
## Quick start (beginner)
1. Leave heartbeats enabled (default is `30m`, or `1h` for Anthropic OAuth/setup-token) or set your own cadence.
@@ -137,6 +139,30 @@ Example: two agents, only the second agent runs heartbeats.
}
```
### Active hours example
Restrict heartbeats to business hours in a specific timezone:
```json5
{
agents: {
defaults: {
heartbeat: {
every: "30m",
target: "last",
activeHours: {
start: "09:00",
end: "22:00",
timezone: "America/New_York", // optional; uses your userTimezone if set, otherwise host tz
},
},
},
},
}
```
Outside this window (before 9am or after 10pm Eastern), heartbeats are skipped. The next scheduled tick inside the window will run normally.
### Multi account example
Use `accountId` to target a specific account on multi-account channels like Telegram:
@@ -183,6 +209,11 @@ Use `accountId` to target a specific account on multi-account channels like Tele
- `accountId`: optional account id for multi-account channels. When `target: "last"`, the account id applies to the resolved last channel if it supports accounts; otherwise it is ignored. If the account id does not match a configured account for the resolved channel, delivery is skipped.
- `prompt`: overrides the default prompt body (not merged).
- `ackMaxChars`: max chars allowed after `HEARTBEAT_OK` before delivery.
- `activeHours`: restricts heartbeat runs to a time window. Object with `start` (HH:MM, inclusive), `end` (HH:MM exclusive; `24:00` allowed for end-of-day), and optional `timezone`.
- Omitted or `"user"`: uses your `agents.defaults.userTimezone` if set, otherwise falls back to the host system timezone.
- `"local"`: always uses the host system timezone.
- Any IANA identifier (e.g. `America/New_York`): used directly; if invalid, falls back to the `"user"` behavior above.
- Outside the active window, heartbeats are skipped until the next tick inside the window.
## Delivery behavior

View File

@@ -49,9 +49,11 @@ pnpm gateway:watch
## Remote access
- Tailscale/VPN preferred; otherwise SSH tunnel:
```bash
ssh -N -L 18789:127.0.0.1:18789 user@host
```
- Clients then connect to `ws://127.0.0.1:18789` through the tunnel.
- If a token is configured, clients must include it in `connect.params.auth.token` even over the tunnel.

View File

@@ -52,7 +52,7 @@ Best current local stack. Load MiniMax M2.1 in LM Studio, enable the local serve
**Setup checklist**
- Install LM Studio: https://lmstudio.ai
- Install LM Studio: [https://lmstudio.ai](https://lmstudio.ai)
- In LM Studio, download the **largest MiniMax M2.1 build available** (avoid “small”/heavily quantized variants), start the server, confirm `http://127.0.0.1:1234/v1/models` lists it.
- Keep the model loaded; cold-load adds startup latency.
- Adjust `contextWindow`/`maxTokens` if your LM Studio build differs.

View File

@@ -23,7 +23,7 @@ misconfiguration safety), under explicit assumptions.
## Where the models live
Models are maintained in a separate repo: [vignesh07/openclaw-formal-models](https://github.com/vignesh07/openclaw-formal-models).
Models are maintained in a separate repo: [vignesh07/clawdbot-formal-models](https://github.com/vignesh07/clawdbot-formal-models).
## Important caveats
@@ -41,8 +41,8 @@ Today, results are reproduced by cloning the models repo locally and running TLC
Getting started:
```bash
git clone https://github.com/vignesh07/openclaw-formal-models
cd openclaw-formal-models
git clone https://github.com/vignesh07/clawdbot-formal-models
cd clawdbot-formal-models
# Java 11+ required (TLC runs on the JVM).
# The repo vendors a pinned `tla2tools.jar` (TLA+ tools) and provides `bin/tlc` + Make targets.

View File

@@ -773,18 +773,22 @@ If it fails, there are new candidates not yet in the baseline.
### If CI fails
1. Reproduce locally:
```bash
detect-secrets scan --baseline .secrets.baseline
```
2. Understand the tools:
- `detect-secrets scan` finds candidates and compares them to the baseline.
- `detect-secrets audit` opens an interactive review to mark each baseline
item as real or false positive.
3. For real secrets: rotate/remove them, then re-run the scan to update the baseline.
4. For false positives: run the interactive audit and mark them as false:
```bash
detect-secrets audit .secrets.baseline
```
5. If you need new excludes, add them to `.detect-secrets.cfg` and regenerate the
baseline with matching `--exclude-files` / `--exclude-lines` flags (the config
file is reference-only; detect-secrets doesnt read it automatically).
@@ -814,7 +818,7 @@ Mario asking for find ~
Found a vulnerability in OpenClaw? Please report responsibly:
1. Email: security@openclaw.ai
1. Email: [security@openclaw.ai](mailto:security@openclaw.ai)
2. Don't post publicly until fixed
3. We'll credit you (unless you prefer anonymity)

View File

@@ -121,7 +121,7 @@ Avoid Funnel for browser control; treat node pairing like operator access.
## Learn more
- Tailscale Serve overview: https://tailscale.com/kb/1312/serve
- `tailscale serve` command: https://tailscale.com/kb/1242/tailscale-serve
- Tailscale Funnel overview: https://tailscale.com/kb/1223/tailscale-funnel
- `tailscale funnel` command: https://tailscale.com/kb/1311/tailscale-funnel
- Tailscale Serve overview: [https://tailscale.com/kb/1312/serve](https://tailscale.com/kb/1312/serve)
- `tailscale serve` command: [https://tailscale.com/kb/1242/tailscale-serve](https://tailscale.com/kb/1242/tailscale-serve)
- Tailscale Funnel overview: [https://tailscale.com/kb/1223/tailscale-funnel](https://tailscale.com/kb/1223/tailscale-funnel)
- `tailscale funnel` command: [https://tailscale.com/kb/1311/tailscale-funnel](https://tailscale.com/kb/1311/tailscale-funnel)

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
## Table of contents
- [Quick start and first-run setup](#quick-start-and-firstrun-setup)
- [Quick start and first-run setup]
- [Im stuck whats the fastest way to get unstuck?](#im-stuck-whats-the-fastest-way-to-get-unstuck)
- [What's the recommended way to install and set up OpenClaw?](#whats-the-recommended-way-to-install-and-set-up-openclaw)
- [How do I open the dashboard after onboarding?](#how-do-i-open-the-dashboard-after-onboarding)
@@ -37,7 +37,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
- [Can I use Claude Max subscription without an API key](#can-i-use-claude-max-subscription-without-an-api-key)
- [How does Anthropic "setup-token" auth work?](#how-does-anthropic-setuptoken-auth-work)
- [Where do I find an Anthropic setup-token?](#where-do-i-find-an-anthropic-setuptoken)
- [Do you support Claude subscription auth (Claude Code OAuth)?](#do-you-support-claude-subscription-auth-claude-code-oauth)
- [Do you support Claude subscription auth (Claude Pro or Max)?](#do-you-support-claude-subscription-auth-claude-pro-or-max)
- [Why am I seeing `HTTP 429: rate_limit_error` from Anthropic?](#why-am-i-seeing-http-429-ratelimiterror-from-anthropic)
- [Is AWS Bedrock supported?](#is-aws-bedrock-supported)
- [How does Codex auth work?](#how-does-codex-auth-work)
@@ -74,7 +74,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
- [Cron or reminders do not fire. What should I check?](#cron-or-reminders-do-not-fire-what-should-i-check)
- [How do I install skills on Linux?](#how-do-i-install-skills-on-linux)
- [Can OpenClaw run tasks on a schedule or continuously in the background?](#can-openclaw-run-tasks-on-a-schedule-or-continuously-in-the-background)
- [Can I run Apple/macOS-only skills from Linux?](#can-i-run-applemacosonly-skills-from-linux)
- [Can I run Apple macOS-only skills from Linux?](#can-i-run-apple-macos-only-skills-from-linux)
- [Do you have a Notion or HeyGen integration?](#do-you-have-a-notion-or-heygen-integration)
- [How do I install the Chrome extension for browser takeover?](#how-do-i-install-the-chrome-extension-for-browser-takeover)
- [Sandboxing and memory](#sandboxing-and-memory)
@@ -102,7 +102,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
- [How do I run a central Gateway with specialized workers across devices?](#how-do-i-run-a-central-gateway-with-specialized-workers-across-devices)
- [Can the OpenClaw browser run headless?](#can-the-openclaw-browser-run-headless)
- [How do I use Brave for browser control?](#how-do-i-use-brave-for-browser-control)
- [Remote gateways + nodes](#remote-gateways-nodes)
- [Remote gateways and nodes](#remote-gateways-and-nodes)
- [How do commands propagate between Telegram, the gateway, and nodes?](#how-do-commands-propagate-between-telegram-the-gateway-and-nodes)
- [How can my agent access my computer if the Gateway is hosted remotely?](#how-can-my-agent-access-my-computer-if-the-gateway-is-hosted-remotely)
- [Tailscale is connected but I get no replies. What now?](#tailscale-is-connected-but-i-get-no-replies-what-now)
@@ -119,7 +119,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
- [How does OpenClaw load environment variables?](#how-does-openclaw-load-environment-variables)
- ["I started the Gateway via the service and my env vars disappeared." What now?](#i-started-the-gateway-via-the-service-and-my-env-vars-disappeared-what-now)
- [I set `COPILOT_GITHUB_TOKEN`, but models status shows "Shell env: off." Why?](#i-set-copilotgithubtoken-but-models-status-shows-shell-env-off-why)
- [Sessions & multiple chats](#sessions-multiple-chats)
- [Sessions and multiple chats](#sessions-and-multiple-chats)
- [How do I start a fresh conversation?](#how-do-i-start-a-fresh-conversation)
- [Do sessions reset automatically if I never send `/new`?](#do-sessions-reset-automatically-if-i-never-send-new)
- [Is there a way to make a team of OpenClaw instances one CEO and many agents](#is-there-a-way-to-make-a-team-of-openclaw-instances-one-ceo-and-many-agents)
@@ -179,7 +179,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
- [How do I completely stop then start the Gateway?](#how-do-i-completely-stop-then-start-the-gateway)
- [ELI5: `openclaw gateway restart` vs `openclaw gateway`](#eli5-openclaw-gateway-restart-vs-openclaw-gateway)
- [What's the fastest way to get more details when something fails?](#whats-the-fastest-way-to-get-more-details-when-something-fails)
- [Media & attachments](#media-attachments)
- [Media and attachments](#media-and-attachments)
- [My skill generated an image/PDF, but nothing was sent](#my-skill-generated-an-imagepdf-but-nothing-was-sent)
- [Security and access control](#security-and-access-control)
- [Is it safe to expose OpenClaw to inbound DMs?](#is-it-safe-to-expose-openclaw-to-inbound-dms)
@@ -252,10 +252,12 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
Repairs/migrates config/state + runs health checks. See [Doctor](/gateway/doctor).
7. **Gateway snapshot**
```bash
openclaw health --json
openclaw health --verbose # shows the target URL + config path on errors
```
Asks the running gateway for a full snapshot (WS-only). See [Health](/gateway/health).
## Quick start and first-run setup
@@ -266,8 +268,8 @@ Use a local AI agent that can **see your machine**. That is far more effective t
in Discord, because most "I'm stuck" cases are **local config or environment issues** that
remote helpers cannot inspect.
- **Claude Code**: https://www.anthropic.com/claude-code/
- **OpenAI Codex**: https://openai.com/codex/
- **Claude Code**: [https://www.anthropic.com/claude-code/](https://www.anthropic.com/claude-code/)
- **OpenAI Codex**: [https://openai.com/codex/](https://openai.com/codex/)
These tools can read the repo, run commands, inspect logs, and help fix your machine-level
setup (PATH, services, permissions, auth files). Give them the **full source checkout** via
@@ -285,8 +287,8 @@ Tip: ask the agent to **plan and supervise** the fix (step-by-step), then execut
necessary commands. That keeps changes small and easier to audit.
If you discover a real bug or fix, please file a GitHub issue or send a PR:
https://github.com/openclaw/openclaw/issues
https://github.com/openclaw/openclaw/pulls
[https://github.com/openclaw/openclaw/issues](https://github.com/openclaw/openclaw/issues)
[https://github.com/openclaw/openclaw/pulls](https://github.com/openclaw/openclaw/pulls)
Start with these commands (share outputs when asking for help):
@@ -334,21 +336,21 @@ If you don't have a global install yet, run it via `pnpm openclaw onboard`.
### How do I open the dashboard after onboarding
The wizard now opens your browser with a tokenized dashboard URL right after onboarding and also prints the full link (with token) in the summary. Keep that tab open; if it didn't launch, copy/paste the printed URL on the same machine. Tokens stay local to your host-nothing is fetched from the browser.
The wizard opens your browser with a clean (non-tokenized) dashboard URL right after onboarding and also prints the link in the summary. Keep that tab open; if it didn't launch, copy/paste the printed URL on the same machine.
### How do I authenticate the dashboard token on localhost vs remote
**Localhost (same machine):**
- Open `http://127.0.0.1:18789/`.
- If it asks for auth, run `openclaw dashboard` and use the tokenized link (`?token=...`).
- The token is the same value as `gateway.auth.token` (or `OPENCLAW_GATEWAY_TOKEN`) and is stored by the UI after first load.
- If it asks for auth, paste the token from `gateway.auth.token` (or `OPENCLAW_GATEWAY_TOKEN`) into Control UI settings.
- Retrieve it from the gateway host: `openclaw config get gateway.auth.token` (or generate one: `openclaw doctor --generate-gateway-token`).
**Not on localhost:**
- **Tailscale Serve** (recommended): keep bind loopback, run `openclaw gateway --tailscale serve`, open `https://<magicdns>/`. If `gateway.auth.allowTailscale` is `true`, identity headers satisfy auth (no token).
- **Tailnet bind**: run `openclaw gateway --bind tailnet --token "<token>"`, open `http://<tailscale-ip>:18789/`, paste token in dashboard settings.
- **SSH tunnel**: `ssh -N -L 18789:127.0.0.1:18789 user@host` then open `http://127.0.0.1:18789/?token=...` from `openclaw dashboard`.
- **SSH tunnel**: `ssh -N -L 18789:127.0.0.1:18789 user@host` then open `http://127.0.0.1:18789/` and paste the token in Control UI settings.
See [Dashboard](/web/dashboard) and [Web surfaces](/web) for bind modes and auth details.
@@ -432,7 +434,7 @@ Related: [Migrating](/install/migrating), [Where things live on disk](/help/faq#
### Where do I see what is new in the latest version
Check the GitHub changelog:
https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md
[https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md](https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md)
Newest entries are at the top. If the top section is marked **Unreleased**, the next dated
section is the latest shipped version. Entries are grouped by **Highlights**, **Changes**, and
@@ -443,10 +445,10 @@ section is the latest shipped version. Entries are grouped by **Highlights**, **
Some Comcast/Xfinity connections incorrectly block `docs.openclaw.ai` via Xfinity
Advanced Security. Disable it or allowlist `docs.openclaw.ai`, then retry. More
detail: [Troubleshooting](/help/troubleshooting#docsopenclawai-shows-an-ssl-error-comcastxfinity).
Please help us unblock it by reporting here: https://spa.xfinity.com/check_url_status.
Please help us unblock it by reporting here: [https://spa.xfinity.com/check_url_status](https://spa.xfinity.com/check_url_status).
If you still can't reach the site, the docs are mirrored on GitHub:
https://github.com/openclaw/openclaw/tree/main/docs
[https://github.com/openclaw/openclaw/tree/main/docs](https://github.com/openclaw/openclaw/tree/main/docs)
### What's the difference between stable and beta
@@ -460,7 +462,7 @@ that same version to `latest`**. That's why beta and stable can point at the
**same version**.
See what changed:
https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md
[https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md](https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md)
### How do I install the beta version and whats the difference between beta and dev
@@ -478,7 +480,7 @@ curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -
```
Windows installer (PowerShell):
https://openclaw.ai/install.ps1
[https://openclaw.ai/install.ps1](https://openclaw.ai/install.ps1)
More detail: [Development channels](/install/development-channels) and [Installer flags](/install/installer).
@@ -559,9 +561,11 @@ Two common Windows issues:
- Your npm global bin folder is not on PATH.
- Check the path:
```powershell
npm config get prefix
```
- Ensure `<prefix>\\bin` is on PATH (on most systems it is `%AppData%\\npm`).
- Close and reopen PowerShell after updating PATH.
@@ -685,7 +689,7 @@ claude setup-token
Copy the token it prints, then choose **Anthropic token (paste setup-token)** in the wizard. If you want to run it on the gateway host, use `openclaw models auth setup-token --provider anthropic`. If you ran `claude setup-token` elsewhere, paste it on the gateway host with `openclaw models auth paste-token --provider anthropic`. See [Anthropic](/providers/anthropic).
### Do you support Claude subscription auth (Claude Pro/Max)
### Do you support Claude subscription auth (Claude Pro or Max)
Yes - via **setup-token**. OpenClaw no longer reuses Claude Code CLI OAuth tokens; use a setup-token or an Anthropic API key. Generate the token anywhere and paste it on the gateway host. See [Anthropic](/providers/anthropic) and [OAuth](/concepts/oauth).
@@ -988,7 +992,7 @@ Advantages:
- **Always-on Gateway** (run on a VPS, interact from anywhere)
- **Nodes** for local browser/screen/camera/exec
Showcase: https://openclaw.ai/showcase
Showcase: [https://openclaw.ai/showcase](https://openclaw.ai/showcase)
## Skills and automation
@@ -1046,7 +1050,7 @@ Docs: [Cron jobs](/automation/cron-jobs), [Cron vs Heartbeat](/automation/cron-v
### How do I install skills on Linux
Use **ClawHub** (CLI) or drop skills into your workspace. The macOS Skills UI isn't available on Linux.
Browse skills at https://clawhub.com.
Browse skills at [https://clawhub.com](https://clawhub.com).
Install the ClawHub CLI (pick one package manager):
@@ -1069,7 +1073,7 @@ Yes. Use the Gateway scheduler:
Docs: [Cron jobs](/automation/cron-jobs), [Cron vs Heartbeat](/automation/cron-vs-heartbeat),
[Heartbeat](/gateway/heartbeat).
**Can I run Apple macOS only skills from Linux**
### Can I run Apple macOS-only skills from Linux?
Not directly. macOS skills are gated by `metadata.openclaw.os` plus required binaries, and skills only appear in the system prompt when they are eligible on the **Gateway host**. On Linux, `darwin`-only skills (like `apple-notes`, `apple-reminders`, `things-mac`) will not load unless you override the gating.
@@ -1085,13 +1089,16 @@ Run the Gateway on Linux, pair a macOS node (menubar app), and set **Node Run Co
Keep the Gateway on Linux, but make the required CLI binaries resolve to SSH wrappers that run on a Mac. Then override the skill to allow Linux so it stays eligible.
1. Create an SSH wrapper for the binary (example: `memo` for Apple Notes):
```bash
#!/usr/bin/env bash
set -euo pipefail
exec ssh -T user@mac-host /opt/homebrew/bin/memo "$@"
```
2. Put the wrapper on `PATH` on the Linux host (for example `~/bin/memo`).
3. Override the skill metadata (workspace or `~/.openclaw/skills`) to allow Linux:
```markdown
---
name: apple-notes
@@ -1099,6 +1106,7 @@ Keep the Gateway on Linux, but make the required CLI binaries resolve to SSH wra
metadata: { "openclaw": { "os": ["darwin", "linux"], "requires": { "bins": ["memo"] } } }
---
```
4. Start a new session so the skills snapshot refreshes.
### Do you have a Notion or HeyGen integration
@@ -1449,7 +1457,7 @@ Headless uses the **same Chromium engine** and works for most automation (forms,
Set `browser.executablePath` to your Brave binary (or any Chromium-based browser) and restart the Gateway.
See the full config examples in [Browser](/tools/browser#use-brave-or-another-chromium-based-browser).
## Remote gateways + nodes
## Remote gateways and nodes
### How do commands propagate between Telegram the gateway and nodes
@@ -1473,6 +1481,7 @@ Typical setup:
4. Open the macOS app locally and connect in **Remote over SSH** mode (or direct tailnet)
so it can register as a node.
5. Approve the node on the Gateway:
```bash
openclaw nodes pending
openclaw nodes approve <requestId>
@@ -1610,10 +1619,12 @@ This sets your workspace and restricts who can trigger the bot.
Minimal steps:
1. **Install + login on the VPS**
```bash
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
```
2. **Install + login on your Mac**
- Use the Tailscale app and sign in to the same tailnet.
3. **Enable MagicDNS (recommended)**
@@ -1640,6 +1651,7 @@ Recommended setup:
2. **Use the macOS app in Remote mode** (SSH target can be the tailnet hostname).
The app will tunnel the Gateway port and connect as a node.
3. **Approve the node** on the gateway:
```bash
openclaw nodes pending
openclaw nodes approve <requestId>
@@ -1702,9 +1714,11 @@ If the Gateway runs as a service (launchd/systemd), it won't inherit your shell
environment. Fix by doing one of these:
1. Put the token in `~/.openclaw/.env`:
```
COPILOT_GITHUB_TOKEN=...
```
2. Or enable shell import (`env.shellEnv.enabled: true`).
3. Or add it to your config `env` block (applies only if missing).
@@ -1717,7 +1731,7 @@ openclaw models status
Copilot tokens are read from `COPILOT_GITHUB_TOKEN` (also `GH_TOKEN` / `GITHUB_TOKEN`).
See [/concepts/model-providers](/concepts/model-providers) and [/environment](/environment).
## Sessions & multiple chats
## Sessions and multiple chats
### How do I start a fresh conversation
@@ -1801,6 +1815,7 @@ Use one of these:
or `/compact <instructions>` to guide the summary.
- **Reset** (fresh session ID for the same chat key):
```
/new
/reset
@@ -2071,9 +2086,11 @@ Fix checklist:
3. Use the exact model id (case-sensitive): `minimax/MiniMax-M2.1` or
`minimax/MiniMax-M2.1-lightning`.
4. Run:
```bash
openclaw models list
```
and pick from the list (or `/model list` in chat).
See [MiniMax](/providers/minimax) and [Models](/concepts/models).
@@ -2238,9 +2255,11 @@ can't find it in its auth store.
- **If you want to use an API key instead**
- Put `ANTHROPIC_API_KEY` in `~/.openclaw/.env` on the **gateway host**.
- Clear any pinned order that forces a missing profile:
```bash
openclaw models auth order clear --provider anthropic
```
- **Confirm you're running commands on the gateway host**
- In remote mode, auth profiles live on the gateway machine, not your laptop.
@@ -2383,15 +2402,14 @@ Your gateway is running with auth enabled (`gateway.auth.*`), but the UI is not
Facts (from code):
- The Control UI stores the token in browser localStorage key `openclaw.control.settings.v1`.
- The UI can import `?token=...` (and/or `?password=...`) once, then strips it from the URL.
Fix:
- Fastest: `openclaw dashboard` (prints + copies tokenized link, tries to open; shows SSH hint if headless).
- Fastest: `openclaw dashboard` (prints + copies the dashboard URL, tries to open; shows SSH hint if headless).
- If you don't have a token yet: `openclaw doctor --generate-gateway-token`.
- If remote, tunnel first: `ssh -N -L 18789:127.0.0.1:18789 user@host` then open `http://127.0.0.1:18789/?token=...`.
- If remote, tunnel first: `ssh -N -L 18789:127.0.0.1:18789 user@host` then open `http://127.0.0.1:18789/`.
- Set `gateway.auth.token` (or `OPENCLAW_GATEWAY_TOKEN`) on the gateway host.
- In the Control UI settings, paste the same token (or refresh with a one-time `?token=...` link).
- In the Control UI settings, paste the same token.
- Still stuck? Run `openclaw status --all` and follow [Troubleshooting](/gateway/troubleshooting). See [Dashboard](/web/dashboard) for auth details.
### I set gatewaybind tailnet but it cant bind nothing listens
@@ -2625,7 +2643,7 @@ you want a one-off, foreground run.
Start the Gateway with `--verbose` to get more console detail. Then inspect the log file for channel auth, model routing, and RPC errors.
## Media & attachments
## Media and attachments
### My skill generated an imagePDF but nothing was sent

View File

@@ -0,0 +1,398 @@
---
summary: "How to submit a high signal PR"
title: "Submitting a PR"
---
Good PRs are easy to review: reviewers should quickly know the intent, verify behavior, and land changes safely. This guide covers concise, high-signal submissions for human and LLM review.
## What makes a good PR
- [ ] Explain the problem, why it matters, and the change.
- [ ] Keep changes focused. Avoid broad refactors.
- [ ] Summarize user-visible/config/default changes.
- [ ] List test coverage, skips, and reasons.
- [ ] Add evidence: logs, screenshots, or recordings (UI/UX).
- [ ] Code word: put “lobster-biscuit” in the PR description if you read this guide.
- [ ] Run/fix relevant `pnpm` commands before creating PR.
- [ ] Search codebase and GitHub for related functionality/issues/fixes.
- [ ] Base claims on evidence or observation.
- [ ] Good title: verb + scope + outcome (e.g., `Docs: add PR and issue templates`).
Be concise; concise review > grammar. Omit any non-applicable sections.
### Baseline validation commands (run/fix failures for your change)
- `pnpm lint`
- `pnpm check`
- `pnpm build`
- `pnpm test`
- Protocol changes: `pnpm protocol:check`
## Progressive disclosure
- Top: summary/intent
- Next: changes/risks
- Next: test/verification
- Last: implementation/evidence
## Common PR types: specifics
- [ ] Fix: Add repro, root cause, verification.
- [ ] Feature: Add use cases, behavior/demos/screenshots (UI).
- [ ] Refactor: State "no behavior change", list what moved/simplified.
- [ ] Chore: State why (e.g., build time, CI, dependencies).
- [ ] Docs: Before/after context, link updated page, run `pnpm format`.
- [ ] Test: What gap is covered; how it prevents regressions.
- [ ] Perf: Add before/after metrics, and how measured.
- [ ] UX/UI: Screenshots/video, note accessibility impact.
- [ ] Infra/Build: Environments/validation.
- [ ] Security: Summarize risk, repro, verification, no sensitive data. Grounded claims only.
## Checklist
- [ ] Clear problem/intent
- [ ] Focused scope
- [ ] List behavior changes
- [ ] List and result of tests
- [ ] Manual test steps (when applicable)
- [ ] No secrets/private data
- [ ] Evidence-based
## General PR Template
```md
#### Summary
#### Behavior Changes
#### Codebase and GitHub Search
#### Tests
#### Manual Testing (omit if N/A)
### Prerequisites
-
### Steps
1.
2.
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort (self-reported):
- Agent notes (optional, cite evidence):
```
## PR Type templates (replace with your type)
### Fix
```md
#### Summary
#### Repro Steps
#### Root Cause
#### Behavior Changes
#### Tests
#### Manual Testing (omit if N/A)
### Prerequisites
-
### Steps
1.
2.
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```
### Feature
```md
#### Summary
#### Use Cases
#### Behavior Changes
#### Existing Functionality Check
- [ ] I searched the codebase for existing functionality.
Searches performed (1-3 bullets):
-
-
#### Tests
#### Manual Testing (omit if N/A)
### Prerequisites
-
### Steps
1.
2.
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```
### Refactor
```md
#### Summary
#### Scope
#### No Behavior Change Statement
#### Tests
#### Manual Testing (omit if N/A)
### Prerequisites
-
### Steps
1.
2.
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```
### Chore/Maintenance
```md
#### Summary
#### Why This Matters
#### Tests
#### Manual Testing (omit if N/A)
### Prerequisites
-
### Steps
1.
2.
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```
### Docs
```md
#### Summary
#### Pages Updated
#### Before/After
#### Formatting
pnpm format
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```
### Test
```md
#### Summary
#### Gap Covered
#### Tests
#### Manual Testing (omit if N/A)
### Prerequisites
-
### Steps
1.
2.
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```
### Perf
```md
#### Summary
#### Baseline
#### After
#### Measurement Method
#### Tests
#### Manual Testing (omit if N/A)
### Prerequisites
-
### Steps
1.
2.
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```
### UX/UI
```md
#### Summary
#### Screenshots or Video
#### Accessibility Impact
#### Tests
#### Manual Testing
### Prerequisites
-
### Steps
1.
2. **Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```
### Infra/Build
```md
#### Summary
#### Environments Affected
#### Validation Steps
#### Manual Testing (omit if N/A)
### Prerequisites
-
### Steps
1.
2.
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```
### Security
```md
#### Summary
#### Risk Summary
#### Repro Steps
#### Mitigation or Fix
#### Verification
#### Tests
#### Manual Testing (omit if N/A)
### Prerequisites
-
### Steps
1.
2.
#### Evidence (omit if N/A)
**Sign-Off**
- Models used:
- Submitter effort:
- Agent notes:
```

View File

@@ -0,0 +1,152 @@
---
summary: "Filing high-signal issues and bug reports"
title: "Submitting an Issue"
---
## Submitting an Issue
Clear, concise issues speed up diagnosis and fixes. Include the following for bugs, regressions, or feature gaps:
### What to include
- [ ] Title: area & symptom
- [ ] Minimal repro steps
- [ ] Expected vs actual
- [ ] Impact & severity
- [ ] Environment: OS, runtime, versions, config
- [ ] Evidence: redacted logs, screenshots (non-PII)
- [ ] Scope: new, regression, or longstanding
- [ ] Code word: lobster-biscuit in your issue
- [ ] Searched codebase & GitHub for existing issue
- [ ] Confirmed not recently fixed/addressed (esp. security)
- [ ] Claims backed by evidence or repro
Be brief. Terseness > perfect grammar.
Validation (run/fix before PR):
- `pnpm lint`
- `pnpm check`
- `pnpm build`
- `pnpm test`
- If protocol code: `pnpm protocol:check`
### Templates
#### Bug report
```md
- [ ] Minimal repro
- [ ] Expected vs actual
- [ ] Environment
- [ ] Affected channels, where not seen
- [ ] Logs/screenshots (redacted)
- [ ] Impact/severity
- [ ] Workarounds
### Summary
### Repro Steps
### Expected
### Actual
### Environment
### Logs/Evidence
### Impact
### Workarounds
```
#### Security issue
```md
### Summary
### Impact
### Versions
### Repro Steps (safe to share)
### Mitigation/workaround
### Evidence (redacted)
```
_Avoid secrets/exploit details in public. For sensitive issues, minimize detail and request private disclosure._
#### Regression report
```md
### Summary
### Last Known Good
### First Known Bad
### Repro Steps
### Expected
### Actual
### Environment
### Logs/Evidence
### Impact
```
#### Feature request
```md
### Summary
### Problem
### Proposed Solution
### Alternatives
### Impact
### Evidence/examples
```
#### Enhancement
```md
### Summary
### Current vs Desired Behavior
### Rationale
### Alternatives
### Evidence/examples
```
#### Investigation
```md
### Summary
### Symptoms
### What Was Tried
### Environment
### Logs/Evidence
### Impact
```
### Submitting a fix PR
Issue before PR is optional. Include details in PR if skipping. Keep the PR focused, note issue number, add tests or explain absence, document behavior changes/risks, include redacted logs/screenshots as proof, and run proper validation before submitting.

View File

@@ -1,98 +1,265 @@
---
summary: "Troubleshooting hub: symptoms → checks → fixes"
summary: "Symptom first troubleshooting hub for OpenClaw"
read_when:
- You see an error and want the fix path
- The installer says “success” but the CLI doesnt work
- OpenClaw is not working and you need the fastest path to a fix
- You want a triage flow before diving into deep runbooks
title: "Troubleshooting"
---
# Troubleshooting
If you only have 2 minutes, use this page as a triage front door.
## First 60 seconds
Run these in order:
Run this exact ladder in order:
```bash
openclaw status
openclaw status --all
openclaw gateway probe
openclaw logs --follow
openclaw gateway status
openclaw doctor
openclaw channels status --probe
openclaw logs --follow
```
If the gateway is reachable, deep probes:
Good output in one line:
```bash
openclaw status --deep
- `openclaw status` → shows configured channels and no obvious auth errors.
- `openclaw status --all` → full report is present and shareable.
- `openclaw gateway probe` → expected gateway target is reachable.
- `openclaw gateway status``Runtime: running` and `RPC probe: ok`.
- `openclaw doctor` → no blocking config/service errors.
- `openclaw channels status --probe` → channels report `connected` or `ready`.
- `openclaw logs --follow` → steady activity, no repeating fatal errors.
## Decision tree
```mermaid
flowchart TD
A[OpenClaw is not working] --> B{What breaks first}
B --> C[No replies]
B --> D[Dashboard or Control UI will not connect]
B --> E[Gateway will not start or service not running]
B --> F[Channel connects but messages do not flow]
B --> G[Cron or heartbeat did not fire or did not deliver]
B --> H[Node is paired but camera canvas screen exec fails]
B --> I[Browser tool fails]
C --> C1[/No replies section/]
D --> D1[/Control UI section/]
E --> E1[/Gateway section/]
F --> F1[/Channel flow section/]
G --> G1[/Automation section/]
H --> H1[/Node tools section/]
I --> I1[/Browser section/]
```
## Common “it broke” cases
<AccordionGroup>
<Accordion title="No replies">
```bash
openclaw status
openclaw gateway status
openclaw channels status --probe
openclaw pairing list <channel>
openclaw logs --follow
```
### `openclaw: command not found`
Good output looks like:
Almost always a Node/npm PATH issue. Start here:
- `Runtime: running`
- `RPC probe: ok`
- Your channel shows connected/ready in `channels status --probe`
- Sender appears approved (or DM policy is open/allowlist)
- [Install (Node/npm PATH sanity)](/install#nodejs--npm-path-sanity)
Common log signatures:
### Installer fails (or you need full logs)
- `drop guild message (mention required` → mention gating blocked the message in Discord.
- `pairing request` → sender is unapproved and waiting for DM pairing approval.
- `blocked` / `allowlist` in channel logs → sender, room, or group is filtered.
Re-run the installer in verbose mode to see the full trace and npm output:
Deep pages:
```bash
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --verbose
```
- [/gateway/troubleshooting#no-replies](/gateway/troubleshooting#no-replies)
- [/channels/troubleshooting](/channels/troubleshooting)
- [/start/pairing](/start/pairing)
For beta installs:
</Accordion>
```bash
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --beta --verbose
```
<Accordion title="Dashboard or Control UI will not connect">
```bash
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
```
You can also set `OPENCLAW_VERBOSE=1` instead of the flag.
Good output looks like:
### Gateway “unauthorized”, cant connect, or keeps reconnecting
- `Dashboard: http://...` is shown in `openclaw gateway status`
- `RPC probe: ok`
- No auth loop in logs
- [Gateway troubleshooting](/gateway/troubleshooting)
- [Gateway authentication](/gateway/authentication)
Common log signatures:
### Control UI fails on HTTP (device identity required)
- `device identity required` → HTTP/non-secure context cannot complete device auth.
- `unauthorized` / reconnect loop → wrong token/password or auth mode mismatch.
- `gateway connect failed:` → UI is targeting the wrong URL/port or unreachable gateway.
- [Gateway troubleshooting](/gateway/troubleshooting)
- [Control UI](/web/control-ui#insecure-http)
Deep pages:
### `docs.openclaw.ai` shows an SSL error (Comcast/Xfinity)
- [/gateway/troubleshooting#dashboard-control-ui-connectivity](/gateway/troubleshooting#dashboard-control-ui-connectivity)
- [/web/control-ui](/web/control-ui)
- [/gateway/authentication](/gateway/authentication)
Some Comcast/Xfinity connections block `docs.openclaw.ai` via Xfinity Advanced Security.
Disable Advanced Security or add `docs.openclaw.ai` to the allowlist, then retry.
</Accordion>
- Xfinity Advanced Security help: https://www.xfinity.com/support/articles/using-xfinity-xfi-advanced-security
- Quick sanity checks: try a mobile hotspot or VPN to confirm its ISP-level filtering
<Accordion title="Gateway will not start or service installed but not running">
```bash
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
```
### Service says running, but RPC probe fails
Good output looks like:
- [Gateway troubleshooting](/gateway/troubleshooting)
- [Background process / service](/gateway/background-process)
- `Service: ... (loaded)`
- `Runtime: running`
- `RPC probe: ok`
### Model/auth failures (rate limit, billing, “all models failed”)
Common log signatures:
- [Models](/cli/models)
- [OAuth / auth concepts](/concepts/oauth)
- `Gateway start blocked: set gateway.mode=local` → gateway mode is unset/remote.
- `refusing to bind gateway ... without auth` → non-loopback bind without token/password.
- `another gateway instance is already listening` or `EADDRINUSE` → port already taken.
### `/model` says `model not allowed`
Deep pages:
This usually means `agents.defaults.models` is configured as an allowlist. When its non-empty,
only those provider/model keys can be selected.
- [/gateway/troubleshooting#gateway-service-not-running](/gateway/troubleshooting#gateway-service-not-running)
- [/gateway/background-process](/gateway/background-process)
- [/gateway/configuration](/gateway/configuration)
- Check the allowlist: `openclaw config get agents.defaults.models`
- Add the model you want (or clear the allowlist) and retry `/model`
- Use `/models` to browse the allowed providers/models
</Accordion>
### When filing an issue
<Accordion title="Channel connects but messages do not flow">
```bash
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
```
Paste a safe report:
Good output looks like:
```bash
openclaw status --all
```
- Channel transport is connected.
- Pairing/allowlist checks pass.
- Mentions are detected where required.
If you can, include the relevant log tail from `openclaw logs --follow`.
Common log signatures:
- `mention required` → group mention gating blocked processing.
- `pairing` / `pending` → DM sender is not approved yet.
- `not_in_channel`, `missing_scope`, `Forbidden`, `401/403` → channel permission token issue.
Deep pages:
- [/gateway/troubleshooting#channel-connected-messages-not-flowing](/gateway/troubleshooting#channel-connected-messages-not-flowing)
- [/channels/troubleshooting](/channels/troubleshooting)
</Accordion>
<Accordion title="Cron or heartbeat did not fire or did not deliver">
```bash
openclaw status
openclaw gateway status
openclaw cron status
openclaw cron list
openclaw cron runs --id <jobId> --limit 20
openclaw logs --follow
```
Good output looks like:
- `cron.status` shows enabled with a next wake.
- `cron runs` shows recent `ok` entries.
- Heartbeat is enabled and not outside active hours.
Common log signatures:
- `cron: scheduler disabled; jobs will not run automatically` → cron is disabled.
- `heartbeat skipped` with `reason=quiet-hours` → outside configured active hours.
- `requests-in-flight` → main lane busy; heartbeat wake was deferred.
- `unknown accountId` → heartbeat delivery target account does not exist.
Deep pages:
- [/gateway/troubleshooting#cron-and-heartbeat-delivery](/gateway/troubleshooting#cron-and-heartbeat-delivery)
- [/automation/troubleshooting](/automation/troubleshooting)
- [/gateway/heartbeat](/gateway/heartbeat)
</Accordion>
<Accordion title="Node is paired but tool fails camera canvas screen exec">
```bash
openclaw status
openclaw gateway status
openclaw nodes status
openclaw nodes describe --node <idOrNameOrIp>
openclaw logs --follow
```
Good output looks like:
- Node is listed as connected and paired for role `node`.
- Capability exists for the command you are invoking.
- Permission state is granted for the tool.
Common log signatures:
- `NODE_BACKGROUND_UNAVAILABLE` → bring node app to foreground.
- `*_PERMISSION_REQUIRED` → OS permission was denied/missing.
- `SYSTEM_RUN_DENIED: approval required` → exec approval is pending.
- `SYSTEM_RUN_DENIED: allowlist miss` → command not on exec allowlist.
Deep pages:
- [/gateway/troubleshooting#node-paired-tool-fails](/gateway/troubleshooting#node-paired-tool-fails)
- [/nodes/troubleshooting](/nodes/troubleshooting)
- [/tools/exec-approvals](/tools/exec-approvals)
</Accordion>
<Accordion title="Browser tool fails">
```bash
openclaw status
openclaw gateway status
openclaw browser status
openclaw logs --follow
openclaw doctor
```
Good output looks like:
- Browser status shows `running: true` and a chosen browser/profile.
- `openclaw` profile starts or `chrome` relay has an attached tab.
Common log signatures:
- `Failed to start Chrome CDP on port` → local browser launch failed.
- `browser.executablePath not found` → configured binary path is wrong.
- `Chrome extension relay is running, but no tab is connected` → extension not attached.
- `Browser attachOnly is enabled ... not reachable` → attach-only profile has no live CDP target.
Deep pages:
- [/gateway/troubleshooting#browser-tool-fails](/gateway/troubleshooting#browser-tool-fails)
- [/tools/browser-linux-troubleshooting](/tools/browser-linux-troubleshooting)
- [/tools/chrome-extension](/tools/chrome-extension)
</Accordion>
</AccordionGroup>

View File

@@ -444,7 +444,7 @@ openclaw hooks enable session-memory
openclaw hooks disable command-logger
```
## Bundled Hooks
## Bundled hook reference
### session-memory
@@ -787,6 +787,7 @@ Session reset
```
3. List all discovered hooks:
```bash
openclaw hooks list
```
@@ -818,6 +819,7 @@ Look for missing:
2. Restart your gateway process so hooks reload.
3. Check gateway logs for errors:
```bash
./scripts/clawlog.sh | grep hook
```
@@ -892,6 +894,7 @@ node -e "import('./path/to/handler.ts').then(console.log)"
```
4. Verify and restart your gateway process:
```bash
openclaw hooks list
# Should show: 🎯 my-hook ✓

View File

@@ -120,7 +120,7 @@ Need the full install and dev setup? See [Quick start](/start/quickstart).
Open the browser Control UI after the Gateway starts.
- Local default: http://127.0.0.1:18789/
- Local default: [http://127.0.0.1:18789/](http://127.0.0.1:18789/)
- Remote access: [Web surfaces](/web) and [Tailscale](/gateway/tailscale)
<p align="center">

View File

@@ -56,7 +56,7 @@ After it finishes:
- Open `http://127.0.0.1:18789/` in your browser.
- Paste the token into the Control UI (Settings → token).
- Need the tokenized URL again? Run `docker compose run --rm openclaw-cli dashboard --no-open`.
- Need the URL again? Run `docker compose run --rm openclaw-cli dashboard --no-open`.
It writes config/workspace on the host:

View File

@@ -103,9 +103,10 @@ server {
## 5) Access OpenClaw and grant privileges
Access `https://<vm-name>.exe.xyz/?token=YOUR-TOKEN-FROM-TERMINAL` (see the Control UI output from onboarding). Approve
devices with `openclaw devices list` and `openclaw devices approve <requestId>`. When in doubt,
use Shelley from your browser!
Access `https://<vm-name>.exe.xyz/` (see the Control UI output from onboarding). If it prompts for auth, paste the
token from `gateway.auth.token` on the VM (retrieve with `openclaw config get gateway.auth.token`, or generate one
with `openclaw doctor --generate-gateway-token`). Approve devices with `openclaw devices list` and
`openclaw devices approve <requestId>`. When in doubt, use Shelley from your browser!
## Remote Access

View File

@@ -69,7 +69,7 @@ For the generic Docker flow, see [Docker](/install/docker).
**Option A: gcloud CLI** (recommended for automation)
Install from https://cloud.google.com/sdk/docs/install
Install from [https://cloud.google.com/sdk/docs/install](https://cloud.google.com/sdk/docs/install)
Initialize and authenticate:
@@ -80,7 +80,7 @@ gcloud auth login
**Option B: Cloud Console**
All steps can be done via the web UI at https://console.cloud.google.com
All steps can be done via the web UI at [https://console.cloud.google.com](https://console.cloud.google.com)
---
@@ -93,7 +93,7 @@ gcloud projects create my-openclaw-project --name="OpenClaw Gateway"
gcloud config set project my-openclaw-project
```
Enable billing at https://console.cloud.google.com/billing (required for Compute Engine).
Enable billing at [https://console.cloud.google.com/billing](https://console.cloud.google.com/billing) (required for Compute Engine).
Enable the Compute Engine API:
@@ -484,6 +484,7 @@ For automation or CI/CD pipelines, create a dedicated service account with minim
```
2. Grant Compute Instance Admin role (or narrower custom role):
```bash
gcloud projects add-iam-policy-binding my-openclaw-project \
--member="serviceAccount:openclaw-deploy@my-openclaw-project.iam.gserviceaccount.com" \
@@ -492,7 +493,7 @@ For automation or CI/CD pipelines, create a dedicated service account with minim
Avoid using the Owner role for automation. Use the principle of least privilege.
See https://cloud.google.com/iam/docs/understanding-roles for IAM role details.
See [https://cloud.google.com/iam/docs/understanding-roles](https://cloud.google.com/iam/docs/understanding-roles) for IAM role details.
---

View File

@@ -1,164 +1,172 @@
---
summary: "Install OpenClaw (recommended installer, global install, or from source)"
summary: "Install OpenClaw — installer script, npm/pnpm, from source, Docker, and more"
read_when:
- Installing OpenClaw
- You want to install from GitHub
title: "Install Overview"
- You need an install method other than the Getting Started quickstart
- You want to deploy to a cloud platform
- You need to update, migrate, or uninstall
title: "Install"
---
# Install Overview
# Install
Use the installer unless you have a reason not to. It sets up the CLI and runs onboarding.
## Quick install (recommended)
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
```
Windows (PowerShell):
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex
```
Next step (if you skipped onboarding):
```bash
openclaw onboard --install-daemon
```
Already followed [Getting Started](/start/getting-started)? You're all set — this page is for alternative install methods, platform-specific instructions, and maintenance.
## System requirements
- **Node >=22**
- macOS, Linux, or Windows via WSL2
- **[Node 22+](/install/node)** (the [installer script](#install-methods) will install it if missing)
- macOS, Linux, or Windows
- `pnpm` only if you build from source
## Choose your install path
<Note>
On Windows, we strongly recommend running OpenClaw under [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install).
</Note>
### 1) Installer script (recommended)
## Install methods
Installs `openclaw` globally via npm and runs onboarding.
<Tip>
The **installer script** is the recommended way to install OpenClaw. It handles Node detection, installation, and onboarding in one step.
</Tip>
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
```
<AccordionGroup>
<Accordion title="Installer script" icon="rocket" defaultOpen>
Downloads the CLI, installs it globally via npm, and launches the onboarding wizard.
Installer flags:
<Tabs>
<Tab title="macOS / Linux / WSL2">
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
```
</Tab>
<Tab title="Windows (PowerShell)">
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex
```
</Tab>
</Tabs>
```bash
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --help
```
That's it — the script handles Node detection, installation, and onboarding.
Details: [Installer internals](/install/installer).
To skip onboarding and just install the binary:
Non-interactive (skip onboarding):
<Tabs>
<Tab title="macOS / Linux / WSL2">
```bash
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard
```
</Tab>
<Tab title="Windows (PowerShell)">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
```
</Tab>
</Tabs>
```bash
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard
```
For all flags, env vars, and CI/automation options, see [Installer internals](/install/installer).
### 2) Global install (manual)
</Accordion>
If you already have Node:
<Accordion title="npm / pnpm" icon="package">
If you already have Node 22+ and prefer to manage the install yourself:
```bash
npm install -g openclaw@latest
```
<Tabs>
<Tab title="npm">
```bash
npm install -g openclaw@latest
openclaw onboard --install-daemon
```
If you have libvips installed globally (common on macOS via Homebrew) and `sharp` fails to install, force prebuilt binaries:
<Accordion title="sharp build errors?">
If you have libvips installed globally (common on macOS via Homebrew) and `sharp` fails, force prebuilt binaries:
```bash
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install -g openclaw@latest
```
```bash
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install -g openclaw@latest
```
If you see `sharp: Please add node-gyp to your dependencies`, either install build tooling (macOS: Xcode CLT + `npm install -g node-gyp`) or use the `SHARP_IGNORE_GLOBAL_LIBVIPS=1` workaround above to skip the native build.
If you see `sharp: Please add node-gyp to your dependencies`, either install build tooling (macOS: Xcode CLT + `npm install -g node-gyp`) or use the env var above.
</Accordion>
</Tab>
<Tab title="pnpm">
```bash
pnpm add -g openclaw@latest
pnpm approve-builds -g # approve openclaw, node-llama-cpp, sharp, etc.
openclaw onboard --install-daemon
```
Or with pnpm:
<Note>
pnpm requires explicit approval for packages with build scripts. After the first install shows the "Ignored build scripts" warning, run `pnpm approve-builds -g` and select the listed packages.
</Note>
</Tab>
</Tabs>
```bash
pnpm add -g openclaw@latest
pnpm approve-builds -g # approve openclaw, node-llama-cpp, sharp, etc.
```
</Accordion>
pnpm requires explicit approval for packages with build scripts. After the first install shows the "Ignored build scripts" warning, run `pnpm approve-builds -g` and select the listed packages.
<Accordion title="From source" icon="github">
For contributors or anyone who wants to run from a local checkout.
Then:
<Steps>
<Step title="Clone and build">
Clone the [OpenClaw repo](https://github.com/openclaw/openclaw) and build:
```bash
openclaw onboard --install-daemon
```
```bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
pnpm ui:build
pnpm build
```
</Step>
<Step title="Link the CLI">
Make the `openclaw` command available globally:
### 3) From source (contributors/dev)
```bash
pnpm link --global
```
```bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
pnpm ui:build # auto-installs UI deps on first run
pnpm build
openclaw onboard --install-daemon
```
Alternatively, skip the link and run commands via `pnpm openclaw ...` from inside the repo.
</Step>
<Step title="Run onboarding">
```bash
openclaw onboard --install-daemon
```
</Step>
</Steps>
Tip: if you dont have a global install yet, run repo commands via `pnpm openclaw ...`.
For deeper development workflows, see [Setup](/start/setup).
For deeper development workflows, see [Setup](/start/setup).
</Accordion>
</AccordionGroup>
### 4) Other install options
## Other install methods
- Docker: [Docker](/install/docker)
- Nix: [Nix](/install/nix)
- Ansible: [Ansible](/install/ansible)
- Bun (CLI only): [Bun](/install/bun)
<CardGroup cols={2}>
<Card title="Docker" href="/install/docker" icon="container">
Containerized or headless deployments.
</Card>
<Card title="Nix" href="/install/nix" icon="snowflake">
Declarative install via Nix.
</Card>
<Card title="Ansible" href="/install/ansible" icon="server">
Automated fleet provisioning.
</Card>
<Card title="Bun" href="/install/bun" icon="zap">
CLI-only usage via the Bun runtime.
</Card>
</CardGroup>
## After install
- Run onboarding: `openclaw onboard --install-daemon`
- Quick check: `openclaw doctor`
- Check gateway health: `openclaw status` + `openclaw health`
- Open the dashboard: `openclaw dashboard`
## Install method: npm vs git (installer)
The installer supports two methods:
- `npm` (default): `npm install -g openclaw@latest`
- `git`: clone/build from GitHub and run from a source checkout
### CLI flags
Verify everything is working:
```bash
# Explicit npm
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method npm
# Install from GitHub (source checkout)
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git
openclaw doctor # check for config issues
openclaw status # gateway status
openclaw dashboard # open the browser UI
```
Common flags:
## Troubleshooting: `openclaw` not found
- `--install-method npm|git`
- `--git-dir <path>` (default: `~/openclaw`)
- `--no-git-update` (skip `git pull` when using an existing checkout)
- `--no-prompt` (disable prompts; required in CI/automation)
- `--dry-run` (print what would happen; make no changes)
- `--no-onboard` (skip onboarding)
### Environment variables
Equivalent env vars (useful for automation):
- `OPENCLAW_INSTALL_METHOD=git|npm`
- `OPENCLAW_GIT_DIR=...`
- `OPENCLAW_GIT_UPDATE=0|1`
- `OPENCLAW_NO_PROMPT=1`
- `OPENCLAW_DRY_RUN=1`
- `OPENCLAW_NO_ONBOARD=1`
- `SHARP_IGNORE_GLOBAL_LIBVIPS=0|1` (default: `1`; avoids `sharp` building against system libvips)
## Troubleshooting: `openclaw` not found (PATH)
Quick diagnosis:
<Accordion title="PATH diagnosis and fix">
Quick diagnosis:
```bash
node -v
@@ -167,21 +175,29 @@ npm prefix -g
echo "$PATH"
```
If `$(npm prefix -g)/bin` (macOS/Linux) or `$(npm prefix -g)` (Windows) is **not** present inside `echo "$PATH"`, your shell cant find global npm binaries (including `openclaw`).
If `$(npm prefix -g)/bin` (macOS/Linux) or `$(npm prefix -g)` (Windows) is **not** in your `$PATH`, your shell can't find global npm binaries (including `openclaw`).
Fix: add it to your shell startup file (zsh: `~/.zshrc`, bash: `~/.bashrc`):
Fix add it to your shell startup file (`~/.zshrc` or `~/.bashrc`):
```bash
# macOS / Linux
export PATH="$(npm prefix -g)/bin:$PATH"
```
On Windows, add the output of `npm prefix -g` to your PATH.
Then open a new terminal (or `rehash` in zsh / `hash -r` in bash).
</Accordion>
## Update / uninstall
- Updates: [Updating](/install/updating)
- Migrate to a new machine: [Migrating](/install/migrating)
- Uninstall: [Uninstall](/install/uninstall)
<CardGroup cols={3}>
<Card title="Updating" href="/install/updating" icon="refresh-cw">
Keep OpenClaw up to date.
</Card>
<Card title="Migrating" href="/install/migrating" icon="arrow-right">
Move to a new machine.
</Card>
<Card title="Uninstall" href="/install/uninstall" icon="trash-2">
Remove OpenClaw completely.
</Card>
</CardGroup>

View File

@@ -1,5 +1,5 @@
---
summary: "How the installer scripts work (install.sh + install-cli.sh), flags, and automation"
summary: "How the installer scripts work (install.sh, install-cli.sh, install.ps1), flags, and automation"
read_when:
- You want to understand `openclaw.ai/install.sh`
- You want to automate installs (CI / headless)
@@ -9,115 +9,377 @@ title: "Installer Internals"
# Installer internals
OpenClaw ships two installer scripts (served from `openclaw.ai`):
OpenClaw ships three installer scripts, served from `openclaw.ai`.
- `https://openclaw.ai/install.sh` — “recommended” installer (global npm install by default; can also install from a GitHub checkout)
- `https://openclaw.ai/install-cli.sh` — non-root-friendly CLI installer (installs into a prefix with its own Node)
- `https://openclaw.ai/install.ps1` — Windows PowerShell installer (npm by default; optional git install)
| Script | Platform | What it does |
| ---------------------------------- | -------------------- | -------------------------------------------------------------------------------------------- |
| [`install.sh`](#installsh) | macOS / Linux / WSL | Installs Node if needed, installs OpenClaw via npm (default) or git, and can run onboarding. |
| [`install-cli.sh`](#install-clish) | macOS / Linux / WSL | Installs Node + OpenClaw into a local prefix (`~/.openclaw`). No root required. |
| [`install.ps1`](#installps1) | Windows (PowerShell) | Installs Node if needed, installs OpenClaw via npm (default) or git, and can run onboarding. |
To see the current flags/behavior, run:
## Quick commands
```bash
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --help
```
<Tabs>
<Tab title="install.sh">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
```
Windows (PowerShell) help:
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --help
```
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -?
```
</Tab>
<Tab title="install-cli.sh">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash
```
If the installer completes but `openclaw` is not found in a new terminal, its usually a Node/npm PATH issue. See: [Install](/install#nodejs--npm-path-sanity).
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --help
```
## install.sh (recommended)
</Tab>
<Tab title="install.ps1">
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex
```
What it does (high level):
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -Tag beta -NoOnboard -DryRun
```
- Detect OS (macOS / Linux / WSL).
- Ensure Node.js **22+** (macOS via Homebrew; Linux via NodeSource).
- Choose install method:
- `npm` (default): `npm install -g openclaw@latest`
- `git`: clone/build a source checkout and install a wrapper script
- On Linux: avoid global npm permission errors by switching npm's prefix to `~/.npm-global` when needed.
- If upgrading an existing install: runs `openclaw doctor --non-interactive` (best effort).
- For git installs: runs `openclaw doctor --non-interactive` after install/update (best effort).
- Mitigates `sharp` native install gotchas by defaulting `SHARP_IGNORE_GLOBAL_LIBVIPS=1` (avoids building against system libvips).
</Tab>
</Tabs>
If you _want_ `sharp` to link against a globally-installed libvips (or youre debugging), set:
<Note>
If install succeeds but `openclaw` is not found in a new terminal, see [Node.js troubleshooting](/install/node#troubleshooting).
</Note>
```bash
SHARP_IGNORE_GLOBAL_LIBVIPS=0 curl -fsSL https://openclaw.ai/install.sh | bash
```
---
### Discoverability / “git install” prompt
## install.sh
If you run the installer while **already inside a OpenClaw source checkout** (detected via `package.json` + `pnpm-workspace.yaml`), it prompts:
<Tip>
Recommended for most interactive installs on macOS/Linux/WSL.
</Tip>
- update and use this checkout (`git`)
- or migrate to the global npm install (`npm`)
### Flow (install.sh)
In non-interactive contexts (no TTY / `--no-prompt`), you must pass `--install-method git|npm` (or set `OPENCLAW_INSTALL_METHOD`), otherwise the script exits with code `2`.
<Steps>
<Step title="Detect OS">
Supports macOS and Linux (including WSL). If macOS is detected, installs Homebrew if missing.
</Step>
<Step title="Ensure Node.js 22+">
Checks Node version and installs Node 22 if needed (Homebrew on macOS, NodeSource setup scripts on Linux apt/dnf/yum).
</Step>
<Step title="Ensure Git">
Installs Git if missing.
</Step>
<Step title="Install OpenClaw">
- `npm` method (default): global npm install
- `git` method: clone/update repo, install deps with pnpm, build, then install wrapper at `~/.local/bin/openclaw`
</Step>
<Step title="Post-install tasks">
- Runs `openclaw doctor --non-interactive` on upgrades and git installs (best effort)
- Attempts onboarding when appropriate (TTY available, onboarding not disabled, and bootstrap/config checks pass)
- Defaults `SHARP_IGNORE_GLOBAL_LIBVIPS=1`
</Step>
</Steps>
### Why Git is needed
### Source checkout detection
Git is required for the `--install-method git` path (clone / pull).
If run inside an OpenClaw checkout (`package.json` + `pnpm-workspace.yaml`), the script offers:
For `npm` installs, Git is _usually_ not required, but some environments still end up needing it (e.g. when a package or dependency is fetched via a git URL). The installer currently ensures Git is present to avoid `spawn git ENOENT` surprises on fresh distros.
- use checkout (`git`), or
- use global install (`npm`)
### Why npm hits `EACCES` on fresh Linux
If no TTY is available and no install method is set, it defaults to `npm` and warns.
On some Linux setups (especially after installing Node via the system package manager or NodeSource), npm's global prefix points at a root-owned location. Then `npm install -g ...` fails with `EACCES` / `mkdir` permission errors.
The script exits with code `2` for invalid method selection or invalid `--install-method` values.
`install.sh` mitigates this by switching the prefix to:
### Examples (install.sh)
- `~/.npm-global` (and adding it to `PATH` in `~/.bashrc` / `~/.zshrc` when present)
<Tabs>
<Tab title="Default">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
```
</Tab>
<Tab title="Skip onboarding">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --no-onboard
```
</Tab>
<Tab title="Git install">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --install-method git
```
</Tab>
<Tab title="Dry run">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --dry-run
```
</Tab>
</Tabs>
## install-cli.sh (non-root CLI installer)
<AccordionGroup>
<Accordion title="Flags reference">
This script installs `openclaw` into a prefix (default: `~/.openclaw`) and also installs a dedicated Node runtime under that prefix, so it can work on machines where you dont want to touch the system Node/npm.
| Flag | Description |
| ------------------------------- | ---------------------------------------------------------- |
| `--install-method npm\|git` | Choose install method (default: `npm`). Alias: `--method` |
| `--npm` | Shortcut for npm method |
| `--git` | Shortcut for git method. Alias: `--github` |
| `--version <version\|dist-tag>` | npm version or dist-tag (default: `latest`) |
| `--beta` | Use beta dist-tag if available, else fallback to `latest` |
| `--git-dir <path>` | Checkout directory (default: `~/openclaw`). Alias: `--dir` |
| `--no-git-update` | Skip `git pull` for existing checkout |
| `--no-prompt` | Disable prompts |
| `--no-onboard` | Skip onboarding |
| `--onboard` | Enable onboarding |
| `--dry-run` | Print actions without applying changes |
| `--verbose` | Enable debug output (`set -x`, npm notice-level logs) |
| `--help` | Show usage (`-h`) |
Help:
</Accordion>
```bash
curl -fsSL https://openclaw.ai/install-cli.sh | bash -s -- --help
```
<Accordion title="Environment variables reference">
## install.ps1 (Windows PowerShell)
| Variable | Description |
| ------------------------------------------- | --------------------------------------------- |
| `OPENCLAW_INSTALL_METHOD=git\|npm` | Install method |
| `OPENCLAW_VERSION=latest\|next\|<semver>` | npm version or dist-tag |
| `OPENCLAW_BETA=0\|1` | Use beta if available |
| `OPENCLAW_GIT_DIR=<path>` | Checkout directory |
| `OPENCLAW_GIT_UPDATE=0\|1` | Toggle git updates |
| `OPENCLAW_NO_PROMPT=1` | Disable prompts |
| `OPENCLAW_NO_ONBOARD=1` | Skip onboarding |
| `OPENCLAW_DRY_RUN=1` | Dry run mode |
| `OPENCLAW_VERBOSE=1` | Debug mode |
| `OPENCLAW_NPM_LOGLEVEL=error\|warn\|notice` | npm log level |
| `SHARP_IGNORE_GLOBAL_LIBVIPS=0\|1` | Control sharp/libvips behavior (default: `1`) |
What it does (high level):
</Accordion>
</AccordionGroup>
- Ensure Node.js **22+** (winget/Chocolatey/Scoop or manual).
- Choose install method:
- `npm` (default): `npm install -g openclaw@latest`
- `git`: clone/build a source checkout and install a wrapper script
- Runs `openclaw doctor --non-interactive` on upgrades and git installs (best effort).
---
Examples:
## install-cli.sh
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex
```
<Info>
Designed for environments where you want everything under a local prefix (default `~/.openclaw`) and no system Node dependency.
</Info>
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex -InstallMethod git
```
### Flow (install-cli.sh)
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex -InstallMethod git -GitDir "C:\\openclaw"
```
<Steps>
<Step title="Install local Node runtime">
Downloads Node tarball (default `22.22.0`) to `<prefix>/tools/node-v<version>` and verifies SHA-256.
</Step>
<Step title="Ensure Git">
If Git is missing, attempts install via apt/dnf/yum on Linux or Homebrew on macOS.
</Step>
<Step title="Install OpenClaw under prefix">
Installs with npm using `--prefix <prefix>`, then writes wrapper to `<prefix>/bin/openclaw`.
</Step>
</Steps>
Environment variables:
### Examples (install-cli.sh)
- `OPENCLAW_INSTALL_METHOD=git|npm`
- `OPENCLAW_GIT_DIR=...`
<Tabs>
<Tab title="Default">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash
```
</Tab>
<Tab title="Custom prefix + version">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --prefix /opt/openclaw --version latest
```
</Tab>
<Tab title="Automation JSON output">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --json --prefix /opt/openclaw
```
</Tab>
<Tab title="Run onboarding">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --onboard
```
</Tab>
</Tabs>
Git requirement:
<AccordionGroup>
<Accordion title="Flags reference">
If you choose `-InstallMethod git` and Git is missing, the installer will print the
Git for Windows link (`https://git-scm.com/download/win`) and exit.
| Flag | Description |
| ---------------------- | ------------------------------------------------------------------------------- |
| `--prefix <path>` | Install prefix (default: `~/.openclaw`) |
| `--version <ver>` | OpenClaw version or dist-tag (default: `latest`) |
| `--node-version <ver>` | Node version (default: `22.22.0`) |
| `--json` | Emit NDJSON events |
| `--onboard` | Run `openclaw onboard` after install |
| `--no-onboard` | Skip onboarding (default) |
| `--set-npm-prefix` | On Linux, force npm prefix to `~/.npm-global` if current prefix is not writable |
| `--help` | Show usage (`-h`) |
Common Windows issues:
</Accordion>
- **npm error spawn git / ENOENT**: install Git for Windows and reopen PowerShell, then rerun the installer.
- **"openclaw" is not recognized**: your npm global bin folder is not on PATH. Most systems use
`%AppData%\\npm`. You can also run `npm config get prefix` and add `\\bin` to PATH, then reopen PowerShell.
<Accordion title="Environment variables reference">
| Variable | Description |
| ------------------------------------------- | --------------------------------------------------------------------------------- |
| `OPENCLAW_PREFIX=<path>` | Install prefix |
| `OPENCLAW_VERSION=<ver>` | OpenClaw version or dist-tag |
| `OPENCLAW_NODE_VERSION=<ver>` | Node version |
| `OPENCLAW_NO_ONBOARD=1` | Skip onboarding |
| `OPENCLAW_NPM_LOGLEVEL=error\|warn\|notice` | npm log level |
| `OPENCLAW_GIT_DIR=<path>` | Legacy cleanup lookup path (used when removing old `Peekaboo` submodule checkout) |
| `SHARP_IGNORE_GLOBAL_LIBVIPS=0\|1` | Control sharp/libvips behavior (default: `1`) |
</Accordion>
</AccordionGroup>
---
## install.ps1
### Flow (install.ps1)
<Steps>
<Step title="Ensure PowerShell + Windows environment">
Requires PowerShell 5+.
</Step>
<Step title="Ensure Node.js 22+">
If missing, attempts install via winget, then Chocolatey, then Scoop.
</Step>
<Step title="Install OpenClaw">
- `npm` method (default): global npm install using selected `-Tag`
- `git` method: clone/update repo, install/build with pnpm, and install wrapper at `%USERPROFILE%\.local\bin\openclaw.cmd`
</Step>
<Step title="Post-install tasks">
Adds needed bin directory to user PATH when possible, then runs `openclaw doctor --non-interactive` on upgrades and git installs (best effort).
</Step>
</Steps>
### Examples (install.ps1)
<Tabs>
<Tab title="Default">
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex
```
</Tab>
<Tab title="Git install">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -InstallMethod git
```
</Tab>
<Tab title="Custom git directory">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -InstallMethod git -GitDir "C:\openclaw"
```
</Tab>
<Tab title="Dry run">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -DryRun
```
</Tab>
</Tabs>
<AccordionGroup>
<Accordion title="Flags reference">
| Flag | Description |
| ------------------------- | ------------------------------------------------------ |
| `-InstallMethod npm\|git` | Install method (default: `npm`) |
| `-Tag <tag>` | npm dist-tag (default: `latest`) |
| `-GitDir <path>` | Checkout directory (default: `%USERPROFILE%\openclaw`) |
| `-NoOnboard` | Skip onboarding |
| `-NoGitUpdate` | Skip `git pull` |
| `-DryRun` | Print actions only |
</Accordion>
<Accordion title="Environment variables reference">
| Variable | Description |
| ---------------------------------- | ------------------ |
| `OPENCLAW_INSTALL_METHOD=git\|npm` | Install method |
| `OPENCLAW_GIT_DIR=<path>` | Checkout directory |
| `OPENCLAW_NO_ONBOARD=1` | Skip onboarding |
| `OPENCLAW_GIT_UPDATE=0` | Disable git pull |
| `OPENCLAW_DRY_RUN=1` | Dry run mode |
</Accordion>
</AccordionGroup>
<Note>
If `-InstallMethod git` is used and Git is missing, the script exits and prints the Git for Windows link.
</Note>
---
## CI and automation
Use non-interactive flags/env vars for predictable runs.
<Tabs>
<Tab title="install.sh (non-interactive npm)">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --no-prompt --no-onboard
```
</Tab>
<Tab title="install.sh (non-interactive git)">
```bash
OPENCLAW_INSTALL_METHOD=git OPENCLAW_NO_PROMPT=1 \
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
```
</Tab>
<Tab title="install-cli.sh (JSON)">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --json --prefix /opt/openclaw
```
</Tab>
<Tab title="install.ps1 (skip onboarding)">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
```
</Tab>
</Tabs>
---
## Troubleshooting
<AccordionGroup>
<Accordion title="Why is Git required?">
Git is required for `git` install method. For `npm` installs, Git is still checked/installed to avoid `spawn git ENOENT` failures when dependencies use git URLs.
</Accordion>
<Accordion title="Why does npm hit EACCES on Linux?">
Some Linux setups point npm global prefix to root-owned paths. `install.sh` can switch prefix to `~/.npm-global` and append PATH exports to shell rc files (when those files exist).
</Accordion>
<Accordion title="sharp/libvips issues">
The scripts default `SHARP_IGNORE_GLOBAL_LIBVIPS=1` to avoid sharp building against system libvips. To override:
```bash
SHARP_IGNORE_GLOBAL_LIBVIPS=0 curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
```
</Accordion>
<Accordion title='Windows: "npm error spawn git / ENOENT"'>
Install Git for Windows, reopen PowerShell, rerun installer.
</Accordion>
<Accordion title='Windows: "openclaw is not recognized"'>
Run `npm config get prefix`, append `\bin`, add that directory to user PATH, then reopen PowerShell.
</Accordion>
<Accordion title="openclaw not found after install">
Usually a PATH issue. See [Node.js troubleshooting](/install/node#troubleshooting).
</Accordion>
</AccordionGroup>

View File

@@ -1,58 +1,133 @@
---
title: "Node.js + npm (PATH sanity)"
summary: "Node.js + npm install sanity: versions, PATH, and global installs"
title: "Node.js"
summary: "Install and configure Node.js for OpenClaw — version requirements, install options, and PATH troubleshooting"
read_when:
- "You installed OpenClaw but `openclaw` is “command not found”"
- "Youre setting up Node.js/npm on a new machine"
- "npm install -g ... fails with permissions or PATH issues"
- "You need to install Node.js before installing OpenClaw"
- "You installed OpenClaw but `openclaw` is command not found"
- "npm install -g fails with permissions or PATH issues"
---
# Node.js + npm (PATH sanity)
# Node.js
OpenClaws runtime baseline is **Node 22+**.
OpenClaw requires **Node 22 or newer**. The [installer script](/install#install-methods) will detect and install Node automatically — this page is for when you want to set up Node yourself and make sure everything is wired up correctly (versions, PATH, global installs).
If you can run `npm install -g openclaw@latest` but later see `openclaw: command not found`, its almost always a **PATH** issue: the directory where npm puts global binaries isnt on your shells PATH.
## Quick diagnosis
Run:
## Check your version
```bash
node -v
npm -v
npm prefix -g
echo "$PATH"
```
If `$(npm prefix -g)/bin` (macOS/Linux) or `$(npm prefix -g)` (Windows) is **not** present inside `echo "$PATH"`, your shell cant find global npm binaries (including `openclaw`).
If this prints `v22.x.x` or higher, you're good. If Node isn't installed or the version is too old, pick an install method below.
## Fix: put npms global bin dir on PATH
## Install Node
1. Find your global npm prefix:
<Tabs>
<Tab title="macOS">
**Homebrew** (recommended):
```bash
brew install node
```
Or download the macOS installer from [nodejs.org](https://nodejs.org/).
</Tab>
<Tab title="Linux">
**Ubuntu / Debian:**
```bash
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
```
**Fedora / RHEL:**
```bash
sudo dnf install nodejs
```
Or use a version manager (see below).
</Tab>
<Tab title="Windows">
**winget** (recommended):
```powershell
winget install OpenJS.NodeJS.LTS
```
**Chocolatey:**
```powershell
choco install nodejs-lts
```
Or download the Windows installer from [nodejs.org](https://nodejs.org/).
</Tab>
</Tabs>
<Accordion title="Using a version manager (nvm, fnm, mise, asdf)">
Version managers let you switch between Node versions easily. Popular options:
- [**fnm**](https://github.com/Schniz/fnm) — fast, cross-platform
- [**nvm**](https://github.com/nvm-sh/nvm) — widely used on macOS/Linux
- [**mise**](https://mise.jdx.dev/) — polyglot (Node, Python, Ruby, etc.)
Example with fnm:
```bash
npm prefix -g
fnm install 22
fnm use 22
```
2. Add the global npm bin directory to your shell startup file:
<Warning>
Make sure your version manager is initialized in your shell startup file (`~/.zshrc` or `~/.bashrc`). If it isn't, `openclaw` may not be found in new terminal sessions because the PATH won't include Node's bin directory.
</Warning>
</Accordion>
- zsh: `~/.zshrc`
- bash: `~/.bashrc`
## Troubleshooting
Example (replace the path with your `npm prefix -g` output):
### `openclaw: command not found`
```bash
# macOS / Linux
export PATH="/path/from/npm/prefix/bin:$PATH"
```
This almost always means npm's global bin directory isn't on your PATH.
Then open a **new terminal** (or run `rehash` in zsh / `hash -r` in bash).
<Steps>
<Step title="Find your global npm prefix">
```bash
npm prefix -g
```
</Step>
<Step title="Check if it's on your PATH">
```bash
echo "$PATH"
```
On Windows, add the output of `npm prefix -g` to your PATH.
Look for `<npm-prefix>/bin` (macOS/Linux) or `<npm-prefix>` (Windows) in the output.
## Fix: avoid `sudo npm install -g` / permission errors (Linux)
</Step>
<Step title="Add it to your shell startup file">
<Tabs>
<Tab title="macOS / Linux">
Add to `~/.zshrc` or `~/.bashrc`:
If `npm install -g ...` fails with `EACCES`, switch npms global prefix to a user-writable directory:
```bash
export PATH="$(npm prefix -g)/bin:$PATH"
```
Then open a new terminal (or run `rehash` in zsh / `hash -r` in bash).
</Tab>
<Tab title="Windows">
Add the output of `npm prefix -g` to your system PATH via Settings → System → Environment Variables.
</Tab>
</Tabs>
</Step>
</Steps>
### Permission errors on `npm install -g` (Linux)
If you see `EACCES` errors, switch npm's global prefix to a user-writable directory:
```bash
mkdir -p "$HOME/.npm-global"
@@ -60,19 +135,4 @@ npm config set prefix "$HOME/.npm-global"
export PATH="$HOME/.npm-global/bin:$PATH"
```
Persist the `export PATH=...` line in your shell startup file.
## Recommended Node install options
Youll have the fewest surprises if Node/npm are installed in a way that:
- keeps Node updated (22+)
- makes the global npm bin dir stable and on PATH in new shells
Common choices:
- macOS: Homebrew (`brew install node`) or a version manager
- Linux: your preferred version manager, or a distro-supported install that provides Node 22+
- Windows: official Node installer, `winget`, or a Windows Node version manager
If you use a version manager (nvm/fnm/asdf/etc), ensure its initialized in the shell you use day-to-day (zsh vs bash) so the PATH it sets is present when you run installers.
Add the `export PATH=...` line to your `~/.bashrc` or `~/.zshrc` to make it permanent.

View File

@@ -45,7 +45,7 @@ If Telegram DMs are set to pairing, the setup wizard can approve the pairing cod
### Discord bot token
1. Go to https://discord.com/developers/applications
1. Go to [https://discord.com/developers/applications](https://discord.com/developers/applications)
2. **New Application** → choose a name
3. **Bot** → **Add Bot**
4. **Enable MESSAGE CONTENT INTENT** under Bot → Privileged Gateway Intents (required or the bot will crash on startup)

View File

@@ -83,7 +83,7 @@ If Telegram DMs are set to pairing, the setup wizard can approve the pairing cod
### Discord bot token
1. Go to https://discord.com/developers/applications
1. Go to [https://discord.com/developers/applications](https://discord.com/developers/applications)
2. **New Application** → choose a name
3. **Bot** → **Add Bot**
4. **Enable MESSAGE CONTENT INTENT** under Bot → Privileged Gateway Intents (required or the bot will crash on startup)

View File

@@ -11,13 +11,7 @@ Deploy OpenClaw on Render using Infrastructure as Code. The included `render.yam
## Deploy with a Render Blueprint
<a
href="https://render.com/deploy?repo=https://github.com/openclaw/openclaw"
target="_blank"
rel="noreferrer"
>
Deploy to Render
</a>
[Deploy to Render](https://render.com/deploy?repo=https://github.com/openclaw/openclaw)
Clicking this link will:

View File

@@ -24,10 +24,13 @@ Notes:
- Add `--no-onboard` if you dont want the onboarding wizard to run again.
- For **source installs**, use:
```bash
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git --no-onboard
```
The installer will `git pull --rebase` **only** if the repo is clean.
- For **global installs**, the script uses `npm install -g openclaw@latest` under the hood.
- Legacy note: `clawdbot` remains available as a compatibility shim.
@@ -225,4 +228,4 @@ git pull
- Run `openclaw doctor` again and read the output carefully (it often tells you the fix).
- Check: [Troubleshooting](/gateway/troubleshooting)
- Ask in Discord: https://discord.gg/clawd
- Ask in Discord: [https://discord.gg/clawd](https://discord.gg/clawd)

View File

@@ -362,6 +362,7 @@ After configuring multi-agent sandbox and tools:
- Verify the agent cannot use denied tools
4. **Monitor logs:**
```exec
tail -f "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/logs/gateway.log" | grep -E "routing|sandbox|tools"
```

View File

@@ -81,7 +81,7 @@ Notes:
## Android node
### User setting (default on)
### Android user setting (default on)
- Android Settings sheet → **Camera****Allow Camera** (`camera.enabled`)
- Default: **on** (missing key is treated as enabled).
@@ -96,7 +96,7 @@ Notes:
If permissions are missing, the app will prompt when possible; if denied, `camera.*` requests fail with a
`*_PERMISSION_REQUIRED` error.
### Foreground requirement
### Android foreground requirement
Like `canvas.*`, the Android node only allows `camera.*` commands in the **foreground**. Background invocations return `NODE_BACKGROUND_UNAVAILABLE`.

View File

@@ -19,6 +19,7 @@ Notes:
- Nodes are **peripherals**, not gateways. They dont run the gateway service.
- Telegram/WhatsApp/etc. messages land on the **gateway**, not on nodes.
- Troubleshooting runbook: [/nodes/troubleshooting](/nodes/troubleshooting)
## Pairing + status

View File

@@ -0,0 +1,112 @@
---
summary: "Troubleshoot node pairing, foreground requirements, permissions, and tool failures"
read_when:
- Node is connected but camera/canvas/screen/exec tools fail
- You need the node pairing versus approvals mental model
title: "Node Troubleshooting"
---
# Node troubleshooting
Use this page when a node is visible in status but node tools fail.
## Command ladder
```bash
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
```
Then run node specific checks:
```bash
openclaw nodes status
openclaw nodes describe --node <idOrNameOrIp>
openclaw approvals get --node <idOrNameOrIp>
```
Healthy signals:
- Node is connected and paired for role `node`.
- `nodes describe` includes the capability you are calling.
- Exec approvals show expected mode/allowlist.
## Foreground requirements
`canvas.*`, `camera.*`, and `screen.*` are foreground only on iOS/Android nodes.
Quick check and fix:
```bash
openclaw nodes describe --node <idOrNameOrIp>
openclaw nodes canvas snapshot --node <idOrNameOrIp>
openclaw logs --follow
```
If you see `NODE_BACKGROUND_UNAVAILABLE`, bring the node app to the foreground and retry.
## Permissions matrix
| Capability | iOS | Android | macOS node app | Typical failure code |
| ---------------------------- | --------------------------------------- | -------------------------------------------- | ----------------------------- | ------------------------------ |
| `camera.snap`, `camera.clip` | Camera (+ mic for clip audio) | Camera (+ mic for clip audio) | Camera (+ mic for clip audio) | `*_PERMISSION_REQUIRED` |
| `screen.record` | Screen Recording (+ mic optional) | Screen capture prompt (+ mic optional) | Screen Recording | `*_PERMISSION_REQUIRED` |
| `location.get` | While Using or Always (depends on mode) | Foreground/Background location based on mode | Location permission | `LOCATION_PERMISSION_REQUIRED` |
| `system.run` | n/a (node host path) | n/a (node host path) | Exec approvals required | `SYSTEM_RUN_DENIED` |
## Pairing versus approvals
These are different gates:
1. **Device pairing**: can this node connect to the gateway?
2. **Exec approvals**: can this node run a specific shell command?
Quick checks:
```bash
openclaw devices list
openclaw nodes status
openclaw approvals get --node <idOrNameOrIp>
openclaw approvals allowlist add --node <idOrNameOrIp> "/usr/bin/uname"
```
If pairing is missing, approve the node device first.
If pairing is fine but `system.run` fails, fix exec approvals/allowlist.
## Common node error codes
- `NODE_BACKGROUND_UNAVAILABLE` → app is backgrounded; bring it foreground.
- `CAMERA_DISABLED` → camera toggle disabled in node settings.
- `*_PERMISSION_REQUIRED` → OS permission missing/denied.
- `LOCATION_DISABLED` → location mode is off.
- `LOCATION_PERMISSION_REQUIRED` → requested location mode not granted.
- `LOCATION_BACKGROUND_UNAVAILABLE` → app is backgrounded but only While Using permission exists.
- `SYSTEM_RUN_DENIED: approval required` → exec request needs explicit approval.
- `SYSTEM_RUN_DENIED: allowlist miss` → command blocked by allowlist mode.
## Fast recovery loop
```bash
openclaw nodes status
openclaw nodes describe --node <idOrNameOrIp>
openclaw approvals get --node <idOrNameOrIp>
openclaw logs --follow
```
If still stuck:
- Re-approve device pairing.
- Re-open node app (foreground).
- Re-grant OS permissions.
- Recreate/adjust exec approval policy.
Related:
- [/nodes/index](/nodes/index)
- [/nodes/camera](/nodes/camera)
- [/nodes/location-command](/nodes/location-command)
- [/tools/exec-approvals](/tools/exec-approvals)
- [/gateway/pairing](/gateway/pairing)

View File

@@ -15,12 +15,12 @@ through Perplexitys direct API or via OpenRouter.
### Perplexity (direct)
- Base URL: https://api.perplexity.ai
- Base URL: [https://api.perplexity.ai](https://api.perplexity.ai)
- Environment variable: `PERPLEXITY_API_KEY`
### OpenRouter (alternative)
- Base URL: https://openrouter.ai/api/v1
- Base URL: [https://openrouter.ai/api/v1](https://openrouter.ai/api/v1)
- Environment variable: `OPENROUTER_API_KEY`
- Supports prepaid/crypto credits.

View File

@@ -66,5 +66,5 @@ If you only want to reset sessions, delete `agents/<agentId>/sessions/` and `age
## References
- https://docs.openclaw.ai/testing
- https://docs.openclaw.ai/start/getting-started
- [https://docs.openclaw.ai/testing](https://docs.openclaw.ai/testing)
- [https://docs.openclaw.ai/start/getting-started](https://docs.openclaw.ai/start/getting-started)

View File

@@ -98,10 +98,13 @@ Pairing details: [Gateway pairing](/gateway/pairing).
### 5) Verify the node is connected
- Via nodes status:
```bash
openclaw nodes status
```
- Via Gateway:
```bash
openclaw gateway call node.list --params "{}"
```

View File

@@ -13,8 +13,8 @@ This guide covers the necessary steps to build and run the OpenClaw macOS applic
Before building the app, ensure you have the following installed:
1. **Xcode 26.2+**: Required for Swift development.
2. **Node.js 22+ & pnpm**: Required for the gateway, CLI, and packaging scripts.
1. **Xcode 26.2+**: Required for Swift development.
2. **Node.js 22+ & pnpm**: Required for the gateway, CLI, and packaging scripts.
## 1. Install Dependencies
@@ -35,7 +35,7 @@ To build the macOS app and package it into `dist/OpenClaw.app`, run:
If you don't have an Apple Developer ID certificate, the script will automatically use **ad-hoc signing** (`-`).
For dev run modes, signing flags, and Team ID troubleshooting, see the macOS app README:
https://github.com/openclaw/openclaw/blob/main/apps/macos/README.md
[https://github.com/openclaw/openclaw/blob/main/apps/macos/README.md](https://github.com/openclaw/openclaw/blob/main/apps/macos/README.md)
> **Note**: Ad-hoc signed apps may trigger security prompts. If the app crashes immediately with "Abort trap 6", see the [Troubleshooting](#troubleshooting) section.
@@ -45,9 +45,9 @@ The macOS app expects a global `openclaw` CLI install to manage background tasks
**To install it (recommended):**
1. Open the OpenClaw app.
2. Go to the **General** settings tab.
3. Click **"Install CLI"**.
1. Open the OpenClaw app.
2. Go to the **General** settings tab.
3. Click **"Install CLI"**.
Alternatively, install it manually:
@@ -82,9 +82,11 @@ If the app crashes when you try to allow **Speech Recognition** or **Microphone*
**Fix:**
1. Reset the TCC permissions:
```bash
tccutil reset All bot.molt.mac.debug
```
2. If that fails, change the `BUNDLE_ID` temporarily in [`scripts/package-mac-app.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/package-mac-app.sh) to force a "clean slate" from macOS.
### Gateway "Starting..." indefinitely

View File

@@ -40,5 +40,11 @@ sudo tccutil reset ScreenCapture bot.molt.mac
sudo tccutil reset AppleEvents
```
## Files and folders permissions (Desktop/Documents/Downloads)
macOS may also gate Desktop, Documents, and Downloads for terminal/background processes. If file reads or directory listings hang, grant access to the same process context that performs file operations (for example Terminal/iTerm, LaunchAgent-launched app, or SSH process).
Workaround: move files into the OpenClaw workspace (`~/.openclaw/workspace`) if you want to avoid per-folder grants.
If you are testing permissions, always sign with a real certificate. Ad-hoc
builds are only acceptable for quick local runs where permissions do not matter.

View File

@@ -34,17 +34,17 @@ Notes:
# From repo root; set release IDs so Sparkle feed is enabled.
# APP_BUILD must be numeric + monotonic for Sparkle compare.
BUNDLE_ID=bot.molt.mac \
APP_VERSION=2026.2.4 \
APP_VERSION=2026.2.6 \
APP_BUILD="$(git rev-list --count HEAD)" \
BUILD_CONFIG=release \
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
scripts/package-mac-app.sh
# Zip for distribution (includes resource forks for Sparkle delta support)
ditto -c -k --sequesterRsrc --keepParent dist/OpenClaw.app dist/OpenClaw-2026.2.4.zip
ditto -c -k --sequesterRsrc --keepParent dist/OpenClaw.app dist/OpenClaw-2026.2.6.zip
# Optional: also build a styled DMG for humans (drag to /Applications)
scripts/create-dmg.sh dist/OpenClaw.app dist/OpenClaw-2026.2.4.dmg
scripts/create-dmg.sh dist/OpenClaw.app dist/OpenClaw-2026.2.6.dmg
# Recommended: build + notarize/staple zip + DMG
# First, create a keychain profile once:
@@ -52,14 +52,14 @@ scripts/create-dmg.sh dist/OpenClaw.app dist/OpenClaw-2026.2.4.dmg
# --apple-id "<apple-id>" --team-id "<team-id>" --password "<app-specific-password>"
NOTARIZE=1 NOTARYTOOL_PROFILE=openclaw-notary \
BUNDLE_ID=bot.molt.mac \
APP_VERSION=2026.2.4 \
APP_VERSION=2026.2.6 \
APP_BUILD="$(git rev-list --count HEAD)" \
BUILD_CONFIG=release \
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
scripts/package-mac-dist.sh
# Optional: ship dSYM alongside the release
ditto -c -k --keepParent apps/macos/.build/release/OpenClaw.app.dSYM dist/OpenClaw-2026.2.4.dSYM.zip
ditto -c -k --keepParent apps/macos/.build/release/OpenClaw.app.dSYM dist/OpenClaw-2026.2.6.dSYM.zip
```
## Appcast entry
@@ -67,7 +67,7 @@ ditto -c -k --keepParent apps/macos/.build/release/OpenClaw.app.dSYM dist/OpenCl
Use the release note generator so Sparkle renders formatted HTML notes:
```bash
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/OpenClaw-2026.2.4.zip https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/OpenClaw-2026.2.6.zip https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml
```
Generates HTML release notes from `CHANGELOG.md` (via [`scripts/changelog-to-html.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/changelog-to-html.sh)) and embeds them in the appcast entry.
@@ -75,7 +75,7 @@ Commit the updated `appcast.xml` alongside the release assets (zip + dSYM) when
## Publish & verify
- Upload `OpenClaw-2026.2.4.zip` (and `OpenClaw-2026.2.4.dSYM.zip`) to the GitHub release for tag `v2026.2.4`.
- Upload `OpenClaw-2026.2.6.zip` (and `OpenClaw-2026.2.6.dSYM.zip`) to the GitHub release for tag `v2026.2.6`.
- Ensure the raw appcast URL matches the baked feed: `https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml`.
- Sanity checks:
- `curl -I https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml` returns 200.

View File

@@ -9,18 +9,18 @@ title: "Voice Overlay"
Audience: macOS app contributors. Goal: keep the voice overlay predictable when wake-word and push-to-talk overlap.
### Current intent
## Current intent
- If the overlay is already visible from wake-word and the user presses the hotkey, the hotkey session _adopts_ the existing text instead of resetting it. The overlay stays up while the hotkey is held. When the user releases: send if there is trimmed text, otherwise dismiss.
- Wake-word alone still auto-sends on silence; push-to-talk sends immediately on release.
### Implemented (Dec 9, 2025)
## Implemented (Dec 9, 2025)
- Overlay sessions now carry a token per capture (wake-word or push-to-talk). Partial/final/send/dismiss/level updates are dropped when the token doesnt match, avoiding stale callbacks.
- Push-to-talk adopts any visible overlay text as a prefix (so pressing the hotkey while the wake overlay is up keeps the text and appends new speech). It waits up to 1.5s for a final transcript before falling back to the current text.
- Chime/overlay logging is emitted at `info` in categories `voicewake.overlay`, `voicewake.ptt`, and `voicewake.chime` (session start, partial, final, send, dismiss, chime reason).
### Next steps
## Next steps
1. **VoiceSessionCoordinator (actor)**
- Owns exactly one `VoiceSession` at a time.
@@ -40,7 +40,7 @@ Audience: macOS app contributors. Goal: keep the voice overlay predictable when
- Coordinator emits `.info` logs in subsystem `bot.molt`, categories `voicewake.overlay` and `voicewake.chime`.
- Key events: `session_started`, `adopted_by_push_to_talk`, `partial`, `finalized`, `send`, `dismiss`, `cancel`, `cooldown`.
### Debugging checklist
## Debugging checklist
- Stream logs while reproducing a sticky overlay:
@@ -51,7 +51,7 @@ Audience: macOS app contributors. Goal: keep the voice overlay predictable when
- Verify only one active session token; stale callbacks should be dropped by the coordinator.
- Ensure push-to-talk release always calls `endCapture` with the active token; if text is empty, expect `dismiss` without chime or send.
### Migration steps (suggested)
## Migration steps (suggested)
1. Add `VoiceSessionCoordinator`, `VoiceSession`, and `VoiceSessionPublisher`.
2. Refactor `VoiceWakeRuntime` to create/update/end sessions instead of touching `VoiceWakeOverlayController` directly.

View File

@@ -19,9 +19,11 @@ agent (with a session switcher for other sessions).
- Manual: Lobster menu → “Open Chat”.
- Autoopen for testing:
```bash
dist/OpenClaw.app/Contents/MacOS/OpenClaw --webchat
```
- Logs: `./scripts/clawlog.sh` (subsystem `bot.molt`, category `WebChatSwiftUI`).
## How its wired

View File

@@ -20,7 +20,7 @@ Native Windows companion apps are planned.
- [Getting Started](/start/getting-started) (use inside WSL)
- [Install & updates](/install/updating)
- Official WSL2 guide (Microsoft): https://learn.microsoft.com/windows/wsl/install
- Official WSL2 guide (Microsoft): [https://learn.microsoft.com/windows/wsl/install](https://learn.microsoft.com/windows/wsl/install)
## Gateway

View File

@@ -11,7 +11,7 @@ title: "OpenProse"
OpenProse is a portable, markdown-first workflow format for orchestrating AI sessions. In OpenClaw it ships as a plugin that installs an OpenProse skill pack plus a `/prose` slash command. Programs live in `.prose` files and can spawn multiple sub-agents with explicit control flow.
Official site: https://www.prose.md
Official site: [https://www.prose.md](https://www.prose.md)
## What it can do

View File

@@ -103,14 +103,14 @@ If you generated the token on a different machine, paste it:
openclaw models auth paste-token --provider anthropic
```
### CLI setup
### CLI setup (setup-token)
```bash
# Paste a setup-token during onboarding
openclaw onboard --auth-choice setup-token
```
### Config snippet
### Config snippet (setup-token)
```json5
{

View File

@@ -131,9 +131,9 @@ launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.claude-max-api.plist
## Links
- **npm:** https://www.npmjs.com/package/claude-max-api-proxy
- **GitHub:** https://github.com/atalovesyou/claude-max-api-proxy
- **Issues:** https://github.com/atalovesyou/claude-max-api-proxy/issues
- **npm:** [https://www.npmjs.com/package/claude-max-api-proxy](https://www.npmjs.com/package/claude-max-api-proxy)
- **GitHub:** [https://github.com/atalovesyou/claude-max-api-proxy](https://github.com/atalovesyou/claude-max-api-proxy)
- **Issues:** [https://github.com/atalovesyou/claude-max-api-proxy/issues](https://github.com/atalovesyou/claude-max-api-proxy/issues)
## Notes

View File

@@ -15,8 +15,8 @@ When enabled, OpenClaw uploads the audio file to Deepgram and injects the transc
into the reply pipeline (`{{Transcript}}` + `[Audio]` block). This is **not streaming**;
it uses the pre-recorded transcription endpoint.
Website: https://deepgram.com
Docs: https://developers.deepgram.com
Website: [https://deepgram.com](https://deepgram.com)
Docs: [https://developers.deepgram.com](https://developers.deepgram.com)
## Quick start

Some files were not shown because too many files have changed in this diff Show More