Compare commits

..

8 Commits

Author SHA1 Message Date
ehu shubham shaw
1e6f0d1198
Merge branch 'master' into feat/hardware-rpi-aardvark-gpio 2026-03-20 16:02:38 -04:00
ehu shubham shaw
7e40186bd7
Merge branch 'master' into feat/hardware-rpi-aardvark-gpio 2026-03-20 15:16:35 -04:00
ehushubhamshaw
f94c10024b docs(scripts): add RPi deployment and interaction guide 2026-03-14 22:48:33 -04:00
ehushubhamshaw
46262136f6 Merge remote-tracking branch 'origin/master' into feat/hardware-rpi-aardvark-gpio-onto-master 2026-03-14 22:43:01 -04:00
ehushubhamshaw
bd08a1bc94 fix(hardware): apply rustfmt 1.92.0 formatting (matches CI toolchain) 2026-03-14 22:20:51 -04:00
ehushubhamshaw
2fbf4cd15c fix(hardware): add missing serial/uf2/pico modules declared in mod.rs
cargo fmt was exiting with code 1 because mod.rs declared pub mod serial,
uf2, pico_flash, pico_code but those files were missing from the branch.
Also apply auto-formatting to loader.rs.
2026-03-14 21:58:01 -04:00
ehushubhamshaw
eb518adb38 fix(hardware): resolve clippy and rustfmt CI failures
- struct_excessive_bools: allow on DeviceCapabilities (7 bool fields needed)
- unnecessary_debug_formatting: use .display() instead of {:?} for paths
- stable_sort_primitive: replace .sort() with .sort_unstable() on &str slices
2026-03-14 21:51:48 -04:00
ehushubhamshaw
83f1d474bd feat(hardware): add RPi GPIO, Aardvark I2C/SPI/GPIO, and hardware plugin system
Extends the hardware subsystem with three clusters of functionality,
all feature-gated (hardware / peripheral-rpi) with no impact on default builds.

Raspberry Pi native support:
- src/hardware/rpi.rs: board self-discovery (model, serial, revision),
  sysfs GPIO pin read/write, and ACT LED control
- scripts/99-act-led.rules: udev rule for non-root ACT LED access
- scripts/deploy-rpi.sh, scripts/rpi-config.toml, scripts/zeroclaw.service:
  one-shot deployment helper and systemd service template

Total Phase Aardvark USB adapter (I2C / SPI / GPIO):
- crates/aardvark-sys/: new workspace crate with FFI bindings loaded at
  runtime via libloading; graceful stub fallback when .so is absent or
  arch mismatches (Rosetta 2 detection)
- src/hardware/aardvark.rs: AardvarkTransport implementing Transport trait
- src/hardware/aardvark_tools.rs: agent tools i2c_scan, i2c_read,
  i2c_write, spi_transfer, gpio_aardvark
- src/hardware/datasheet.rs: datasheet search/download for detected devices
- docs/aardvark-integration.md, examples/hardware/aardvark/: guide + examples

Hardware plugin / ToolRegistry system:
- src/hardware/tool_registry.rs: ToolRegistry for hardware module tool sets
- src/hardware/loader.rs, src/hardware/manifest.rs: manifest-driven loader
- src/hardware/subprocess.rs: subprocess execution helper for board I/O
- src/gateway/hardware_context.rs: POST /api/hardware/reload endpoint
- src/hardware/mod.rs: exports all new modules; merge_hardware_tools and
  load_hardware_context_prompt helpers

Integration hooks (minimal surface):
- src/hardware/device.rs: DeviceKind::Aardvark, DeviceRuntime::Aardvark,
  has_aardvark / resolve_aardvark_device on DeviceRegistry
- src/hardware/transport.rs: TransportKind::Aardvark
- src/peripherals/mod.rs: gate create_board_info_tools behind hardware feature
- src/agent/loop_.rs: TOOL_CHOICE_OVERRIDE task-local for Anthropic provider
- src/providers/anthropic.rs: read TOOL_CHOICE_OVERRIDE; add tool_choice field
- Cargo.toml: add aardvark-sys to workspace and as dependency
- firmware/zeroclaw-nucleo/: update Cargo.toml and Cargo.lock

Non-goals:
- No changes to agent orchestration, channels, providers, or security policy
- No new config keys outside existing [hardware] / [peripherals] sections
- No CI workflow changes

Risk: Low. All new paths are feature-gated; aardvark.so loads at runtime
only when present. No schema migrations or persistent state introduced.

Rollback: revert this single commit.
2026-03-14 18:18:55 -04:00
323 changed files with 5039 additions and 46314 deletions

View File

@ -1,44 +1,3 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# All files
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
# Rust files - match rustfmt.toml
[*.rs]
indent_size = 4
max_line_length = 100
# Markdown files
[*.md]
trim_trailing_whitespace = false
max_line_length = 80
# TOML files
[*.toml]
indent_size = 2
# YAML files
[*.{yml,yaml}]
indent_size = 2
# Python files
[*.py]
indent_size = 4
max_line_length = 100
# Shell scripts
[*.{sh,bash}]
indent_size = 2
# JSON files
[*.json]
indent_size = 2

View File

@ -118,7 +118,3 @@ PROVIDER=openrouter
# Optional: Brave Search (requires API key from https://brave.com/search/api)
# WEB_SEARCH_PROVIDER=brave
# BRAVE_API_KEY=your-brave-search-api-key
#
# Optional: SearXNG (self-hosted, requires instance URL)
# WEB_SEARCH_PROVIDER=searxng
# SEARXNG_INSTANCE_URL=https://searx.example.com

301
.github/labeler.yml vendored
View File

@ -36,145 +36,6 @@
- any-glob-to-any-file:
- "src/channels/**"
"channel:bluesky":
- changed-files:
- any-glob-to-any-file:
- "src/channels/bluesky.rs"
"channel:clawdtalk":
- changed-files:
- any-glob-to-any-file:
- "src/channels/clawdtalk.rs"
"channel:cli":
- changed-files:
- any-glob-to-any-file:
- "src/channels/cli.rs"
"channel:dingtalk":
- changed-files:
- any-glob-to-any-file:
- "src/channels/dingtalk.rs"
"channel:discord":
- changed-files:
- any-glob-to-any-file:
- "src/channels/discord.rs"
- "src/channels/discord_history.rs"
"channel:email":
- changed-files:
- any-glob-to-any-file:
- "src/channels/email_channel.rs"
- "src/channels/gmail_push.rs"
"channel:imessage":
- changed-files:
- any-glob-to-any-file:
- "src/channels/imessage.rs"
"channel:irc":
- changed-files:
- any-glob-to-any-file:
- "src/channels/irc.rs"
"channel:lark":
- changed-files:
- any-glob-to-any-file:
- "src/channels/lark.rs"
"channel:linq":
- changed-files:
- any-glob-to-any-file:
- "src/channels/linq.rs"
"channel:matrix":
- changed-files:
- any-glob-to-any-file:
- "src/channels/matrix.rs"
"channel:mattermost":
- changed-files:
- any-glob-to-any-file:
- "src/channels/mattermost.rs"
"channel:mochat":
- changed-files:
- any-glob-to-any-file:
- "src/channels/mochat.rs"
"channel:mqtt":
- changed-files:
- any-glob-to-any-file:
- "src/channels/mqtt.rs"
"channel:nextcloud-talk":
- changed-files:
- any-glob-to-any-file:
- "src/channels/nextcloud_talk.rs"
"channel:nostr":
- changed-files:
- any-glob-to-any-file:
- "src/channels/nostr.rs"
"channel:notion":
- changed-files:
- any-glob-to-any-file:
- "src/channels/notion.rs"
"channel:qq":
- changed-files:
- any-glob-to-any-file:
- "src/channels/qq.rs"
"channel:reddit":
- changed-files:
- any-glob-to-any-file:
- "src/channels/reddit.rs"
"channel:signal":
- changed-files:
- any-glob-to-any-file:
- "src/channels/signal.rs"
"channel:slack":
- changed-files:
- any-glob-to-any-file:
- "src/channels/slack.rs"
"channel:telegram":
- changed-files:
- any-glob-to-any-file:
- "src/channels/telegram.rs"
"channel:twitter":
- changed-files:
- any-glob-to-any-file:
- "src/channels/twitter.rs"
"channel:wati":
- changed-files:
- any-glob-to-any-file:
- "src/channels/wati.rs"
"channel:webhook":
- changed-files:
- any-glob-to-any-file:
- "src/channels/webhook.rs"
"channel:wecom":
- changed-files:
- any-glob-to-any-file:
- "src/channels/wecom.rs"
"channel:whatsapp":
- changed-files:
- any-glob-to-any-file:
- "src/channels/whatsapp.rs"
- "src/channels/whatsapp_storage.rs"
- "src/channels/whatsapp_web.rs"
"gateway":
- changed-files:
- any-glob-to-any-file:
@ -240,73 +101,6 @@
- any-glob-to-any-file:
- "src/providers/**"
"provider:anthropic":
- changed-files:
- any-glob-to-any-file:
- "src/providers/anthropic.rs"
"provider:azure-openai":
- changed-files:
- any-glob-to-any-file:
- "src/providers/azure_openai.rs"
"provider:bedrock":
- changed-files:
- any-glob-to-any-file:
- "src/providers/bedrock.rs"
"provider:claude-code":
- changed-files:
- any-glob-to-any-file:
- "src/providers/claude_code.rs"
"provider:compatible":
- changed-files:
- any-glob-to-any-file:
- "src/providers/compatible.rs"
"provider:copilot":
- changed-files:
- any-glob-to-any-file:
- "src/providers/copilot.rs"
"provider:gemini":
- changed-files:
- any-glob-to-any-file:
- "src/providers/gemini.rs"
- "src/providers/gemini_cli.rs"
"provider:glm":
- changed-files:
- any-glob-to-any-file:
- "src/providers/glm.rs"
"provider:kilocli":
- changed-files:
- any-glob-to-any-file:
- "src/providers/kilocli.rs"
"provider:ollama":
- changed-files:
- any-glob-to-any-file:
- "src/providers/ollama.rs"
"provider:openai":
- changed-files:
- any-glob-to-any-file:
- "src/providers/openai.rs"
- "src/providers/openai_codex.rs"
"provider:openrouter":
- changed-files:
- any-glob-to-any-file:
- "src/providers/openrouter.rs"
"provider:telnyx":
- changed-files:
- any-glob-to-any-file:
- "src/providers/telnyx.rs"
"service":
- changed-files:
- any-glob-to-any-file:
@ -327,101 +121,6 @@
- any-glob-to-any-file:
- "src/tools/**"
"tool:browser":
- changed-files:
- any-glob-to-any-file:
- "src/tools/browser.rs"
- "src/tools/browser_delegate.rs"
- "src/tools/browser_open.rs"
- "src/tools/text_browser.rs"
- "src/tools/screenshot.rs"
"tool:composio":
- changed-files:
- any-glob-to-any-file:
- "src/tools/composio.rs"
"tool:cron":
- changed-files:
- any-glob-to-any-file:
- "src/tools/cron_add.rs"
- "src/tools/cron_list.rs"
- "src/tools/cron_remove.rs"
- "src/tools/cron_run.rs"
- "src/tools/cron_runs.rs"
- "src/tools/cron_update.rs"
"tool:file":
- changed-files:
- any-glob-to-any-file:
- "src/tools/file_edit.rs"
- "src/tools/file_read.rs"
- "src/tools/file_write.rs"
- "src/tools/glob_search.rs"
- "src/tools/content_search.rs"
"tool:google-workspace":
- changed-files:
- any-glob-to-any-file:
- "src/tools/google_workspace.rs"
"tool:mcp":
- changed-files:
- any-glob-to-any-file:
- "src/tools/mcp_client.rs"
- "src/tools/mcp_deferred.rs"
- "src/tools/mcp_protocol.rs"
- "src/tools/mcp_tool.rs"
- "src/tools/mcp_transport.rs"
"tool:memory":
- changed-files:
- any-glob-to-any-file:
- "src/tools/memory_forget.rs"
- "src/tools/memory_recall.rs"
- "src/tools/memory_store.rs"
"tool:microsoft365":
- changed-files:
- any-glob-to-any-file:
- "src/tools/microsoft365/**"
"tool:shell":
- changed-files:
- any-glob-to-any-file:
- "src/tools/shell.rs"
- "src/tools/node_tool.rs"
- "src/tools/cli_discovery.rs"
"tool:sop":
- changed-files:
- any-glob-to-any-file:
- "src/tools/sop_advance.rs"
- "src/tools/sop_approve.rs"
- "src/tools/sop_execute.rs"
- "src/tools/sop_list.rs"
- "src/tools/sop_status.rs"
"tool:web":
- changed-files:
- any-glob-to-any-file:
- "src/tools/web_fetch.rs"
- "src/tools/web_search_tool.rs"
- "src/tools/web_search_provider_routing.rs"
- "src/tools/http_request.rs"
"tool:security":
- changed-files:
- any-glob-to-any-file:
- "src/tools/security_ops.rs"
- "src/tools/verifiable_intent.rs"
"tool:cloud":
- changed-files:
- any-glob-to-any-file:
- "src/tools/cloud_ops.rs"
- "src/tools/cloud_patterns.rs"
"tunnel":
- changed-files:
- any-glob-to-any-file:

View File

@ -7,7 +7,7 @@ on:
branches: [master]
concurrency:
group: ci-${{ github.event.pull_request.number || 'push-master' }}
group: ci-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
permissions:
@ -154,7 +154,7 @@ jobs:
run: mkdir -p web/dist && touch web/dist/.gitkeep
- name: Check all features
run: cargo check --features ci-all --locked
run: cargo check --all-features --locked
docs-quality:
name: Docs Quality

View File

@ -1,19 +0,0 @@
name: PR Path Labeler
on:
pull_request_target:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
label:
name: Apply path labels
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5
with:
sync-labels: true

View File

@ -1,22 +1,6 @@
name: Pub Homebrew Core
on:
workflow_call:
inputs:
release_tag:
description: "Existing release tag to publish (vX.Y.Z)"
required: true
type: string
dry_run:
description: "Patch formula only (no push/PR)"
required: false
default: false
type: boolean
secrets:
HOMEBREW_UPSTREAM_PR_TOKEN:
required: false
HOMEBREW_CORE_BOT_TOKEN:
required: false
workflow_dispatch:
inputs:
release_tag:

View File

@ -19,7 +19,6 @@ env:
jobs:
detect-version-change:
name: Detect Version Bump
if: github.repository == 'zeroclaw-labs/zeroclaw'
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.check.outputs.changed }}
@ -41,14 +40,6 @@ jobs:
echo "Current version: ${current}"
echo "Previous version: ${previous}"
# Skip if stable release workflow will handle this version
# (indicated by an existing or imminent stable tag)
if git ls-remote --exit-code --tags origin "refs/tags/v${current}" >/dev/null 2>&1; then
echo "Stable tag v${current} exists — stable release workflow handles crates.io"
echo "changed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if [[ "$current" != "$previous" && -n "$current" ]]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "version=${current}" >> "$GITHUB_OUTPUT"
@ -111,22 +102,6 @@ jobs:
- name: Clean web build artifacts
run: rm -rf web/node_modules web/src web/package.json web/package-lock.json web/tsconfig*.json web/vite.config.ts web/index.html
- name: Publish aardvark-sys to crates.io
shell: bash
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
OUTPUT=$(cargo publish --locked --allow-dirty --no-verify -p aardvark-sys 2>&1) && exit 0
echo "$OUTPUT"
if echo "$OUTPUT" | grep -q 'already exists'; then
echo "::notice::aardvark-sys already on crates.io — skipping"
exit 0
fi
exit 1
- name: Wait for aardvark-sys to index
run: sleep 15
- name: Publish to crates.io
shell: bash
env:

View File

@ -67,24 +67,6 @@ jobs:
- name: Clean web build artifacts
run: rm -rf web/node_modules web/src web/package.json web/package-lock.json web/tsconfig*.json web/vite.config.ts web/index.html
- name: Publish aardvark-sys to crates.io
if: "!inputs.dry_run"
shell: bash
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
OUTPUT=$(cargo publish --locked --allow-dirty --no-verify -p aardvark-sys 2>&1) && exit 0
echo "$OUTPUT"
if echo "$OUTPUT" | grep -q 'already exists'; then
echo "::notice::aardvark-sys already on crates.io — skipping"
exit 0
fi
exit 1
- name: Wait for aardvark-sys to index
if: "!inputs.dry_run"
run: sleep 15
- name: Publish (dry run)
if: inputs.dry_run
run: cargo publish --dry-run --locked --allow-dirty --no-verify

View File

@ -21,48 +21,25 @@ env:
jobs:
version:
name: Resolve Version
if: github.repository == 'zeroclaw-labs/zeroclaw'
runs-on: ubuntu-latest
outputs:
version: ${{ steps.ver.outputs.version }}
tag: ${{ steps.ver.outputs.tag }}
skip: ${{ steps.ver.outputs.skip }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 2
- name: Compute beta version
id: ver
shell: bash
run: |
set -euo pipefail
base_version=$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -1)
# Skip beta if this is a version bump commit (stable release handles it)
commit_msg=$(git log -1 --pretty=format:"%s")
if [[ "$commit_msg" =~ ^chore:\ bump\ version ]]; then
echo "Version bump commit detected — skipping beta release"
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
# Skip beta if a stable tag already exists for this version
if git ls-remote --exit-code --tags origin "refs/tags/v${base_version}" >/dev/null 2>&1; then
echo "Stable tag v${base_version} exists — skipping beta release"
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
beta_tag="v${base_version}-beta.${GITHUB_RUN_NUMBER}"
echo "version=${base_version}" >> "$GITHUB_OUTPUT"
echo "tag=${beta_tag}" >> "$GITHUB_OUTPUT"
echo "skip=false" >> "$GITHUB_OUTPUT"
echo "Beta release: ${beta_tag}"
release-notes:
name: Generate Release Notes
needs: [version]
if: github.repository == 'zeroclaw-labs/zeroclaw' && needs.version.outputs.skip != 'true'
runs-on: ubuntu-latest
outputs:
notes: ${{ steps.notes.outputs.body }}
@ -153,8 +130,6 @@ jobs:
web:
name: Build Web Dashboard
needs: [version]
if: github.repository == 'zeroclaw-labs/zeroclaw' && needs.version.outputs.skip != 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
@ -266,65 +241,9 @@ jobs:
path: zeroclaw-${{ matrix.target }}.${{ matrix.ext }}
retention-days: 7
build-desktop:
name: Build Desktop App (macOS Universal)
needs: [version]
if: needs.version.outputs.skip != 'true'
runs-on: macos-14
timeout-minutes: 40
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
with:
toolchain: 1.92.0
targets: aarch64-apple-darwin,x86_64-apple-darwin
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
with:
prefix-key: macos-tauri
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install Tauri CLI
run: cargo install tauri-cli --locked
- name: Sync Tauri version with Cargo.toml
shell: bash
run: |
VERSION=$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -1)
cd apps/tauri
if command -v jq >/dev/null 2>&1; then
jq --arg v "$VERSION" '.version = $v' tauri.conf.json > tmp.json && mv tmp.json tauri.conf.json
else
sed -i '' "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" tauri.conf.json
fi
echo "Tauri version set to: $VERSION"
- name: Build Tauri app (universal binary)
working-directory: apps/tauri
run: cargo tauri build --target universal-apple-darwin
- name: Prepare desktop release assets
run: |
mkdir -p desktop-assets
find target -name '*.dmg' -exec cp {} desktop-assets/ZeroClaw.dmg \; 2>/dev/null || true
find target -name '*.app.tar.gz' -exec cp {} desktop-assets/ZeroClaw-macos.app.tar.gz \; 2>/dev/null || true
find target -name '*.app.tar.gz.sig' -exec cp {} desktop-assets/ZeroClaw-macos.app.tar.gz.sig \; 2>/dev/null || true
echo "--- Desktop assets ---"
ls -lh desktop-assets/
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: desktop-macos
path: desktop-assets/*
retention-days: 7
publish:
name: Publish Beta Release
needs: [version, release-notes, build, build-desktop]
needs: [version, release-notes, build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
@ -334,21 +253,16 @@ jobs:
pattern: zeroclaw-*
path: artifacts
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: desktop-macos
path: artifacts/desktop-macos
- name: Generate checksums
run: |
cd artifacts
find . -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.dmg' \) -exec sha256sum {} + | sed 's| \./[^/]*/| |' > SHA256SUMS
find . -type f \( -name '*.tar.gz' -o -name '*.zip' \) -exec sha256sum {} + | sed 's| \./[^/]*/| |' > SHA256SUMS
cat SHA256SUMS
- name: Collect release assets
run: |
mkdir -p release-assets
find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.dmg' -o -name 'SHA256SUMS' \) -exec cp {} release-assets/ \;
find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name 'SHA256SUMS' \) -exec cp {} release-assets/ \;
cp install.sh release-assets/
echo "--- Assets ---"
ls -lh release-assets/

View File

@ -1,9 +1,6 @@
name: Release Stable
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+" # stable tags only (no -beta suffix)
workflow_dispatch:
inputs:
version:
@ -36,22 +33,11 @@ jobs:
- name: Validate semver and Cargo.toml match
id: check
shell: bash
env:
INPUT_VERSION: ${{ inputs.version || '' }}
REF_NAME: ${{ github.ref_name }}
EVENT_NAME: ${{ github.event_name }}
run: |
set -euo pipefail
input_version="${{ inputs.version }}"
cargo_version=$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -1)
# Resolve version from tag push or manual input
if [[ "$EVENT_NAME" == "push" ]]; then
# Tag push: extract version from tag name (v0.5.9 -> 0.5.9)
input_version="${REF_NAME#v}"
else
input_version="$INPUT_VERSION"
fi
if [[ ! "$input_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Version must be semver (X.Y.Z). Got: ${input_version}"
exit 1
@ -63,13 +49,9 @@ jobs:
fi
tag="v${input_version}"
# Only check tag existence for manual dispatch (tag push means it already exists)
if [[ "$EVENT_NAME" != "push" ]]; then
if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then
echo "::error::Tag ${tag} already exists."
exit 1
fi
if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then
echo "::error::Tag ${tag} already exists."
exit 1
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
@ -273,64 +255,9 @@ jobs:
path: zeroclaw-${{ matrix.target }}.${{ matrix.ext }}
retention-days: 14
build-desktop:
name: Build Desktop App (macOS Universal)
needs: [validate]
runs-on: macos-14
timeout-minutes: 40
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
with:
toolchain: 1.92.0
targets: aarch64-apple-darwin,x86_64-apple-darwin
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
with:
prefix-key: macos-tauri
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install Tauri CLI
run: cargo install tauri-cli --locked
- name: Sync Tauri version with Cargo.toml
shell: bash
run: |
VERSION=$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -1)
cd apps/tauri
if command -v jq >/dev/null 2>&1; then
jq --arg v "$VERSION" '.version = $v' tauri.conf.json > tmp.json && mv tmp.json tauri.conf.json
else
sed -i '' "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" tauri.conf.json
fi
echo "Tauri version set to: $VERSION"
- name: Build Tauri app (universal binary)
working-directory: apps/tauri
run: cargo tauri build --target universal-apple-darwin
- name: Prepare desktop release assets
run: |
mkdir -p desktop-assets
find target -name '*.dmg' -exec cp {} desktop-assets/ZeroClaw.dmg \; 2>/dev/null || true
find target -name '*.app.tar.gz' -exec cp {} desktop-assets/ZeroClaw-macos.app.tar.gz \; 2>/dev/null || true
find target -name '*.app.tar.gz.sig' -exec cp {} desktop-assets/ZeroClaw-macos.app.tar.gz.sig \; 2>/dev/null || true
echo "--- Desktop assets ---"
ls -lh desktop-assets/
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: desktop-macos
path: desktop-assets/*
retention-days: 14
publish:
name: Publish Stable Release
needs: [validate, release-notes, build, build-desktop]
needs: [validate, release-notes, build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
@ -340,21 +267,16 @@ jobs:
pattern: zeroclaw-*
path: artifacts
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: desktop-macos
path: artifacts/desktop-macos
- name: Generate checksums
run: |
cd artifacts
find . -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.dmg' \) -exec sha256sum {} + | sed 's| \./[^/]*/| |' > SHA256SUMS
find . -type f \( -name '*.tar.gz' -o -name '*.zip' \) -exec sha256sum {} + | sed 's| \./[^/]*/| |' > SHA256SUMS
cat SHA256SUMS
- name: Collect release assets
run: |
mkdir -p release-assets
find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.dmg' -o -name 'SHA256SUMS' \) -exec cp {} release-assets/ \;
find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name 'SHA256SUMS' \) -exec cp {} release-assets/ \;
cp install.sh release-assets/
echo "--- Assets ---"
ls -lh release-assets/
@ -364,14 +286,6 @@ jobs:
NOTES: ${{ needs.release-notes.outputs.notes }}
run: printf '%s\n' "$NOTES" > release-notes.md
- name: Create tag if manual dispatch
if: github.event_name == 'workflow_dispatch'
env:
TAG: ${{ needs.validate.outputs.tag }}
run: |
git tag -a "$TAG" -m "zeroclaw $TAG"
git push origin "$TAG"
- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
@ -409,21 +323,6 @@ jobs:
- name: Clean web build artifacts
run: rm -rf web/node_modules web/src web/package.json web/package-lock.json web/tsconfig*.json web/vite.config.ts web/index.html
- name: Publish aardvark-sys to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
OUTPUT=$(cargo publish --locked --allow-dirty --no-verify -p aardvark-sys 2>&1) && exit 0
echo "$OUTPUT"
if echo "$OUTPUT" | grep -q 'already exists'; then
echo "::notice::aardvark-sys already on crates.io — skipping"
exit 0
fi
exit 1
- name: Wait for aardvark-sys to index
run: sleep 15
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
@ -547,16 +446,6 @@ jobs:
dry_run: false
secrets: inherit
homebrew:
name: Update Homebrew Core
needs: [validate, publish]
if: ${{ !cancelled() && needs.publish.result == 'success' }}
uses: ./.github/workflows/pub-homebrew-core.yml
with:
release_tag: ${{ needs.validate.outputs.tag }}
dry_run: false
secrets: inherit
# ── Post-publish: tweet after release + website are live ──────────────
# Docker push can be slow; don't let it block the tweet.
tweet:

View File

@ -1,92 +0,0 @@
# AGENTS.md — ZeroClaw
Cross-tool agent instructions for any AI coding assistant working on this repository.
## Commands
```bash
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo test
```
Full pre-PR validation (recommended):
```bash
./dev/ci.sh all
```
Docs-only changes: run markdown lint and link-integrity checks. If touching bootstrap scripts: `bash -n install.sh`.
## Project Snapshot
ZeroClaw is a Rust-first autonomous agent runtime optimized for performance, efficiency, stability, extensibility, sustainability, and security.
Core architecture is trait-driven and modular. Extend by implementing traits and registering in factory modules.
Key extension points:
- `src/providers/traits.rs` (`Provider`)
- `src/channels/traits.rs` (`Channel`)
- `src/tools/traits.rs` (`Tool`)
- `src/memory/traits.rs` (`Memory`)
- `src/observability/traits.rs` (`Observer`)
- `src/runtime/traits.rs` (`RuntimeAdapter`)
- `src/peripherals/traits.rs` (`Peripheral`) — hardware boards (STM32, RPi GPIO)
## Repository Map
- `src/main.rs` — CLI entrypoint and command routing
- `src/lib.rs` — module exports and shared command enums
- `src/config/` — schema + config loading/merging
- `src/agent/` — orchestration loop
- `src/gateway/` — webhook/gateway server
- `src/security/` — policy, pairing, secret store
- `src/memory/` — markdown/sqlite memory backends + embeddings/vector merge
- `src/providers/` — model providers and resilient wrapper
- `src/channels/` — Telegram/Discord/Slack/etc channels
- `src/tools/` — tool execution surface (shell, file, memory, browser)
- `src/peripherals/` — hardware peripherals (STM32, RPi GPIO)
- `src/runtime/` — runtime adapters (currently native)
- `docs/` — topic-based documentation (setup-guides, reference, ops, security, hardware, contributing, maintainers)
- `.github/` — CI, templates, automation workflows
## Risk Tiers
- **Low risk**: docs/chore/tests-only changes
- **Medium risk**: most `src/**` behavior changes without boundary/security impact
- **High risk**: `src/security/**`, `src/runtime/**`, `src/gateway/**`, `src/tools/**`, `.github/workflows/**`, access-control boundaries
When uncertain, classify as higher risk.
## Workflow
1. **Read before write** — inspect existing module, factory wiring, and adjacent tests before editing.
2. **One concern per PR** — avoid mixed feature+refactor+infra patches.
3. **Implement minimal patch** — no speculative abstractions, no config keys without a concrete use case.
4. **Validate by risk tier** — docs-only: lightweight checks. Code changes: full relevant checks.
5. **Document impact** — update PR notes for behavior, risk, side effects, and rollback.
6. **Queue hygiene** — stacked PR: declare `Depends on #...`. Replacing old PR: declare `Supersedes #...`.
Branch/commit/PR rules:
- Work from a non-`master` branch. Open a PR to `master`; do not push directly.
- Use conventional commit titles. Prefer small PRs (`size: XS/S/M`).
- Follow `.github/pull_request_template.md` fully.
- Never commit secrets, personal data, or real identity information (see `@docs/contributing/pr-discipline.md`).
## Anti-Patterns
- Do not add heavy dependencies for minor convenience.
- Do not silently weaken security policy or access constraints.
- Do not add speculative config/feature flags "just in case".
- Do not mix massive formatting-only changes with functional changes.
- Do not modify unrelated modules "while here".
- Do not bypass failing checks without explicit explanation.
- Do not hide behavior-changing side effects in refactor commits.
- Do not include personal identity or sensitive information in test data, examples, docs, or commits.
## Linked References
- `@docs/contributing/change-playbooks.md` — adding providers, channels, tools, peripherals; security/gateway changes; architecture boundaries
- `@docs/contributing/pr-discipline.md` — privacy rules, superseded-PR attribution/templates, handoff template
- `@docs/contributing/docs-contract.md` — docs system contract, i18n rules, locale parity

1
AGENTS.md Symbolic link
View File

@ -0,0 +1 @@
CLAUDE.md

View File

@ -1,16 +1,90 @@
# CLAUDE.md — ZeroClaw (Claude Code)
# CLAUDE.md — ZeroClaw
> **Shared instructions live in [`AGENTS.md`](./AGENTS.md).**
> This file contains only Claude Code-specific directives.
## Commands
## Claude Code Settings
```bash
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo test
```
Claude Code should read and follow all instructions in `AGENTS.md` at the repository root for project conventions, commands, risk tiers, workflow rules, and anti-patterns.
Full pre-PR validation (recommended):
## Hooks
```bash
./dev/ci.sh all
```
_No custom hooks defined yet._
Docs-only changes: run markdown lint and link-integrity checks. If touching bootstrap scripts: `bash -n install.sh`.
## Slash Commands
## Project Snapshot
_No custom slash commands defined yet._
ZeroClaw is a Rust-first autonomous agent runtime optimized for performance, efficiency, stability, extensibility, sustainability, and security.
Core architecture is trait-driven and modular. Extend by implementing traits and registering in factory modules.
Key extension points:
- `src/providers/traits.rs` (`Provider`)
- `src/channels/traits.rs` (`Channel`)
- `src/tools/traits.rs` (`Tool`)
- `src/memory/traits.rs` (`Memory`)
- `src/observability/traits.rs` (`Observer`)
- `src/runtime/traits.rs` (`RuntimeAdapter`)
- `src/peripherals/traits.rs` (`Peripheral`) — hardware boards (STM32, RPi GPIO)
## Repository Map
- `src/main.rs` — CLI entrypoint and command routing
- `src/lib.rs` — module exports and shared command enums
- `src/config/` — schema + config loading/merging
- `src/agent/` — orchestration loop
- `src/gateway/` — webhook/gateway server
- `src/security/` — policy, pairing, secret store
- `src/memory/` — markdown/sqlite memory backends + embeddings/vector merge
- `src/providers/` — model providers and resilient wrapper
- `src/channels/` — Telegram/Discord/Slack/etc channels
- `src/tools/` — tool execution surface (shell, file, memory, browser)
- `src/peripherals/` — hardware peripherals (STM32, RPi GPIO)
- `src/runtime/` — runtime adapters (currently native)
- `docs/` — topic-based documentation (setup-guides, reference, ops, security, hardware, contributing, maintainers)
- `.github/` — CI, templates, automation workflows
## Risk Tiers
- **Low risk**: docs/chore/tests-only changes
- **Medium risk**: most `src/**` behavior changes without boundary/security impact
- **High risk**: `src/security/**`, `src/runtime/**`, `src/gateway/**`, `src/tools/**`, `.github/workflows/**`, access-control boundaries
When uncertain, classify as higher risk.
## Workflow
1. **Read before write** — inspect existing module, factory wiring, and adjacent tests before editing.
2. **One concern per PR** — avoid mixed feature+refactor+infra patches.
3. **Implement minimal patch** — no speculative abstractions, no config keys without a concrete use case.
4. **Validate by risk tier** — docs-only: lightweight checks. Code changes: full relevant checks.
5. **Document impact** — update PR notes for behavior, risk, side effects, and rollback.
6. **Queue hygiene** — stacked PR: declare `Depends on #...`. Replacing old PR: declare `Supersedes #...`.
Branch/commit/PR rules:
- Work from a non-`master` branch. Open a PR to `master`; do not push directly.
- Use conventional commit titles. Prefer small PRs (`size: XS/S/M`).
- Follow `.github/pull_request_template.md` fully.
- Never commit secrets, personal data, or real identity information (see `@docs/contributing/pr-discipline.md`).
## Anti-Patterns
- Do not add heavy dependencies for minor convenience.
- Do not silently weaken security policy or access constraints.
- Do not add speculative config/feature flags "just in case".
- Do not mix massive formatting-only changes with functional changes.
- Do not modify unrelated modules "while here".
- Do not bypass failing checks without explicit explanation.
- Do not hide behavior-changing side effects in refactor commits.
- Do not include personal identity or sensitive information in test data, examples, docs, or commits.
## Linked References
- `@docs/contributing/change-playbooks.md` — adding providers, channels, tools, peripherals; security/gateway changes; architecture boundaries
- `@docs/contributing/pr-discipline.md` — privacy rules, superseded-PR attribution/templates, handoff template
- `@docs/contributing/docs-contract.md` — docs system contract, i18n rules, locale parity

3547
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
[workspace]
members = [".", "crates/robot-kit", "crates/aardvark-sys", "apps/tauri"]
members = [".", "crates/robot-kit", "crates/aardvark-sys"]
resolver = "2"
[package]
name = "zeroclawlabs"
version = "0.6.1"
version = "0.5.3"
edition = "2021"
authors = ["theonlyhennygod"]
license = "MIT OR Apache-2.0"
@ -97,7 +97,7 @@ anyhow = "1.0"
thiserror = "2.0"
# Aardvark I2C/SPI/GPIO USB adapter (Total Phase) — stub when SDK absent
aardvark-sys = { path = "crates/aardvark-sys", version = "0.1.0" }
aardvark-sys = { path = "crates/aardvark-sys" }
# UUID generation
uuid = { version = "1.22", default-features = false, features = ["v4", "std"] }
@ -150,7 +150,6 @@ which = "8.0"
# WebSocket client channels (Discord/Lark/DingTalk/Nostr)
tokio-tungstenite = { version = "0.29", features = ["rustls-tls-webpki-roots"] }
tokio-socks = "0.5"
futures-util = { version = "0.3", default-features = false, features = ["sink"] }
nostr-sdk = { version = "0.44", default-features = false, features = ["nip04", "nip59"], optional = true }
regex = "1.10"
@ -200,9 +199,6 @@ pdf-extract = { version = "0.10", optional = true }
# WASM plugin runtime (extism)
extism = { version = "1.20", optional = true }
# Cross-platform audio capture for voice wake word detection (optional, enable with --features voice-wake)
cpal = { version = "0.15", optional = true }
# Terminal QR rendering for WhatsApp Web pairing flow.
qrcode = { version = "0.14", optional = true }
@ -225,7 +221,7 @@ landlock = { version = "0.4", optional = true }
libc = "0.2"
[features]
default = ["observability-prometheus", "channel-nostr", "channel-lark", "skill-creation"]
default = ["observability-prometheus", "channel-nostr", "skill-creation"]
channel-nostr = ["dep:nostr-sdk"]
hardware = ["nusb", "tokio-serial"]
channel-matrix = ["dep:matrix-sdk"]
@ -254,30 +250,8 @@ rag-pdf = ["dep:pdf-extract"]
skill-creation = []
# whatsapp-web = Native WhatsApp Web client with custom rusqlite storage backend
whatsapp-web = ["dep:wa-rs", "dep:wa-rs-core", "dep:wa-rs-binary", "dep:wa-rs-proto", "dep:wa-rs-ureq-http", "dep:wa-rs-tokio-transport", "dep:serde-big-array", "dep:prost", "dep:qrcode"]
# voice-wake = Voice wake word detection via microphone (cpal)
voice-wake = ["dep:cpal"]
# WASM plugin system (extism-based)
plugins-wasm = ["dep:extism"]
# Meta-feature for CI: all features except those requiring system C libraries
# not available on standard CI runners (e.g., voice-wake needs libasound2-dev).
ci-all = [
"channel-nostr",
"hardware",
"channel-matrix",
"channel-lark",
"memory-postgres",
"observability-prometheus",
"observability-otel",
"peripheral-rpi",
"browser-native",
"sandbox-landlock",
"sandbox-bubblewrap",
"probe",
"rag-pdf",
"skill-creation",
"whatsapp-web",
"plugins-wasm",
]
[profile.release]
opt-level = "z" # Optimize for size

View File

@ -12,7 +12,7 @@ RUN npm run build
FROM rust:1.94-slim@sha256:da9dab7a6b8dd428e71718402e97207bb3e54167d37b5708616050b1e8f60ed6 AS builder
WORKDIR /app
ARG ZEROCLAW_CARGO_FEATURES="memory-postgres,channel-lark"
ARG ZEROCLAW_CARGO_FEATURES="memory-postgres"
# Install build dependencies
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
@ -23,11 +23,9 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
# 1. Copy manifests to cache dependencies
COPY Cargo.toml Cargo.lock ./
# Include every workspace member: Cargo.lock is generated for the full workspace.
# Previously we used sed to drop `crates/robot-kit`, which made the manifest disagree
# with the lockfile and caused `cargo --locked` to fail (Cargo refused to rewrite the lock).
COPY crates/robot-kit/ crates/robot-kit/
COPY crates/aardvark-sys/ crates/aardvark-sys/
# Remove robot-kit from workspace members — it is excluded by .dockerignore
# and is not needed for the Docker build (hardware-only crate).
RUN sed -i 's/members = \[".", "crates\/robot-kit"\]/members = ["."]/' Cargo.toml
# Create dummy targets declared in Cargo.toml so manifest parsing succeeds.
RUN mkdir -p src benches \
&& echo "fn main() {}" > src/main.rs \
@ -79,10 +77,6 @@ RUN mkdir -p /zeroclaw-data/.zeroclaw /zeroclaw-data/workspace && \
'port = 42617' \
'host = "[::]"' \
'allow_public_bind = true' \
'' \
'[autonomy]' \
'level = "supervised"' \
'auto_approve = ["file_read", "file_write", "file_edit", "memory_recall", "memory_store", "web_search_tool", "web_fetch", "calculator", "glob_search", "content_search", "image_info", "weather", "git_operations"]' \
> /zeroclaw-data/.zeroclaw/config.toml && \
chown -R 65534:65534 /zeroclaw-data

View File

@ -27,7 +27,7 @@ RUN npm run build
FROM rust:1.94-bookworm AS builder
WORKDIR /app
ARG ZEROCLAW_CARGO_FEATURES="memory-postgres,channel-lark"
ARG ZEROCLAW_CARGO_FEATURES="memory-postgres"
# Install build dependencies
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
@ -38,10 +38,9 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
# 1. Copy manifests to cache dependencies
COPY Cargo.toml Cargo.lock ./
# Include every workspace member: Cargo.lock is generated for the full workspace.
# Previously we used sed to drop `crates/robot-kit`, which made the manifest disagree
# with the lockfile and caused `cargo --locked` to fail (Cargo refused to rewrite the lock).
COPY crates/robot-kit/ crates/robot-kit/
# Remove robot-kit from workspace members — it is excluded by .dockerignore
# and is not needed for the Docker build (hardware-only crate).
RUN sed -i 's/members = \[".", "crates\/robot-kit"\]/members = ["."]/' Cargo.toml
# Create dummy targets declared in Cargo.toml so manifest parsing succeeds.
RUN mkdir -p src benches \
&& echo "fn main() {}" > src/main.rs \
@ -89,10 +88,6 @@ RUN mkdir -p /zeroclaw-data/.zeroclaw /zeroclaw-data/workspace && \
'port = 42617' \
'host = "[::]"' \
'allow_public_bind = true' \
'' \
'[autonomy]' \
'level = "supervised"' \
'auto_approve = ["file_read", "file_write", "file_edit", "memory_recall", "memory_store", "web_search_tool", "web_fetch", "calculator", "glob_search", "content_search", "image_info", "weather", "git_operations"]' \
> /zeroclaw-data/.zeroclaw/config.toml && \
chown -R 65534:65534 /zeroclaw-data

15
NOTICE
View File

@ -41,18 +41,3 @@ This project uses third-party libraries and components,
each licensed under their respective terms.
See Cargo.lock for a complete dependency list.
Verifiable Intent Specification
================================
The src/verifiable_intent/ module is a Rust-native reimplementation based on
the Verifiable Intent open specification and reference implementation:
Project: Verifiable Intent (VI)
Author: agent-intent
Source: https://github.com/agent-intent/verifiable-intent
License: Apache License, Version 2.0
This implementation follows the VI specification design (SD-JWT layered
credentials, constraint model, three-layer chain). No source code was copied
from the reference implementation.

View File

@ -324,6 +324,47 @@ ls -lh target/release/zeroclaw
- CI/CD: تجريبي (تلقائي عند الدفع) → مستقر (إرسال يدوي) → Docker، crates.io، Scoop، AUR، Homebrew، تغريدة.
- ملفات ثنائية مُعدة مسبقًا لـ Linux (x86_64، aarch64، armv7)، macOS (x86_64، aarch64)، Windows (x86_64).
## كيف يعمل (باختصار)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## التكوين

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 ওয়েব ড্যাশবোর্
- CI/CD: বেটা (পুশে অটো) → স্টেবল (ম্যানুয়াল ডিসপ্যাচ) → Docker, crates.io, Scoop, AUR, Homebrew, টুইট।
- Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64) এর জন্য প্রি-বিল্ট বাইনারি।
## এটি কিভাবে কাজ করে (সংক্ষিপ্ত)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## কনফিগারেশন

View File

@ -324,6 +324,47 @@ Webový panel React 19 + Vite 6 + Tailwind CSS 4 servírovaný přímo z Gateway
- CI/CD: beta (auto na push) → stable (ruční dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Předpřipravené binárky pro Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Jak to funguje (krátce)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Konfigurace

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 web-dashboard serveret direkte fra Gateway'en
- CI/CD: beta (auto on push) → stable (manual dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Forhaandsbyggede binaerer til Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Saadan virker det (kort)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Konfiguration

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 Web-Dashboard, direkt vom Gateway bereitgeste
- CI/CD: beta (automatisch bei Push) → stable (manueller Dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, Tweet.
- Vorgefertigte Binaries für Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Wie es funktioniert (kurz)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (Steuerungsebene) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web-Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Ratenbegrenzung │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Konfiguration

View File

@ -324,6 +324,47 @@ ls -lh target/release/zeroclaw
- CI/CD: beta (auto on push) → stable (manual dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Προκατασκευασμένα δυαδικά για Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Πώς λειτουργεί (σύντομα)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Ρύθμιση παραμέτρων

View File

@ -324,6 +324,47 @@ Panel web React 19 + Vite 6 + Tailwind CSS 4 servido directamente desde el Gatew
- CI/CD: beta (automático al hacer push) → stable (dispatch manual) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Binarios preconstruidos para Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Cómo funciona (resumen)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (plano de control) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Panel Web (React 19) │
│ REST API + WebSocket + SSE │
│ Emparejamiento + Limitación │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Configuración

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 web-hallintapaneeli, jota tarjoillaan suoraan
- CI/CD: beta (auto on push) → stable (manual dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Valmiit binaarit Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Miten se toimii (lyhyesti)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Maaritykset

View File

@ -324,6 +324,47 @@ Tableau de bord web React 19 + Vite 6 + Tailwind CSS 4 servi directement depuis
- CI/CD : beta (automatique au push) → stable (dispatch manuel) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Binaires précompilés pour Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Comment ça fonctionne (résumé)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (plan de contrôle) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Tableau de bord (React 19) │
│ REST API + WebSocket + SSE │
│ Appairage + Limitation │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Configuration

View File

@ -324,6 +324,47 @@ ls -lh target/release/zeroclaw
- CI/CD: בטא (אוטומטי בדחיפה) → יציב (שליחה ידנית) → Docker, crates.io, Scoop, AUR, Homebrew, ציוץ.
- בינאריים מוכנים מראש ל-Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## איך זה עובד (בקצרה)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## הגדרות

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 वेब डैशबोर्ड सीध
- CI/CD: बीटा (पुश पर ऑटो) → स्टेबल (मैनुअल डिस्पैच) → Docker, crates.io, Scoop, AUR, Homebrew, ट्वीट।
- Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64) के लिए प्री-बिल्ट बाइनरी।
## यह कैसे काम करता है (संक्षिप्त)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## कॉन्फ़िगरेशन

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 webes vezerlopult, amelyet kozvetlenul a Gate
- CI/CD: beta (auto on push) → stable (manual dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Elore elkeszitett binarisok Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64) rendszerekhez.
## Hogyan mukodik (roviden)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Konfiguracio

View File

@ -324,6 +324,47 @@ Dasbor web React 19 + Vite 6 + Tailwind CSS 4 yang disajikan langsung dari Gatew
- CI/CD: beta (otomatis saat push) → stable (dispatch manual) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Biner pre-built untuk Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Cara kerjanya (singkat)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Konfigurasi

View File

@ -324,6 +324,47 @@ Dashboard web React 19 + Vite 6 + Tailwind CSS 4 servita direttamente dal Gatewa
- CI/CD: beta (automatico al push) → stable (dispatch manuale) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Binari precompilati per Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Come funziona (sintesi)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (piano di controllo) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Dashboard Web (React 19) │
│ REST API + WebSocket + SSE │
│ Accoppiamento + Limitazione │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Configurazione

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 ウェブダッシュボード、Gatewayか
- CI/CDbetaプッシュ時自動→ stable手動ディスパッチ→ Docker、crates.io、Scoop、AUR、Homebrew、tweet。
- プリビルドバイナリLinuxx86_64、aarch64、armv7、macOSx86_64、aarch64、Windowsx86_64
## 仕組み(概要)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## 設定

View File

@ -324,6 +324,47 @@ Gateway에서 직접 제공하는 React 19 + Vite 6 + Tailwind CSS 4 웹 대시
- CI/CD: beta (push 시 자동) → stable (수동 디스패치) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64)용 사전 빌드 바이너리.
## 작동 방식 (요약)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## 구성

View File

@ -300,7 +300,7 @@ React 19 + Vite 6 + Tailwind CSS 4 web dashboard served directly from the Gatewa
- **Core:** shell, file read/write/edit, git operations, glob search, content search
- **Web:** browser control, web fetch, web search, screenshot, image info, PDF read
- **Integrations:** Jira, Notion, Google Workspace, Microsoft 365, LinkedIn, Composio, Pushover, Weather (wttr.in)
- **Integrations:** Jira, Notion, Google Workspace, Microsoft 365, LinkedIn, Composio, Pushover
- **MCP:** Model Context Protocol tool wrapper + deferred tool sets
- **Scheduling:** cron add/remove/update/run, schedule tool
- **Memory:** recall, store, forget, knowledge, project intel
@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 web dashboard served directly from the Gatewa
- CI/CD: beta (auto on push) → stable (manual dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Pre-built binaries for Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## How it works (short)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Configuration

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 nettbasert dashbord servert direkte fra Gatew
- CI/CD: beta (auto pa push) -> stabil (manuell utsendelse) -> Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Forhandsbygde binarfiler for Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Slik fungerer det (kort)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (kontrollplan) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Nettbasert dashbord (React 19)│
│ REST API + WebSocket + SSE │
│ Paring + Hastighetsbegrensning│
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Sloyfe │ │Planleg.│ │ Sverm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Leveran.│ │Verktoy │ │ Minne │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Sikker- │ │Periferiutst│
│ het │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Konfigurasjon

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 webdashboard geserveerd direct vanuit de Gate
- CI/CD: beta (auto bij push) → stable (handmatige dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Voorgebouwde binaries voor Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Hoe het werkt (kort)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Configuratie

View File

@ -324,6 +324,47 @@ Panel webowy React 19 + Vite 6 + Tailwind CSS 4 serwowany bezpośrednio z Gatewa
- CI/CD: beta (auto na push) → stable (ręczny dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Gotowe pliki binarne dla Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Jak to działa (w skrócie)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Konfiguracja

View File

@ -324,6 +324,47 @@ Painel web React 19 + Vite 6 + Tailwind CSS 4 servido diretamente pelo Gateway:
- CI/CD: beta (automático no push) → stable (dispatch manual) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Binários pré-construídos para Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Como funciona (resumo)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (plano de controle) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Painel Web (React 19) │
│ REST API + WebSocket + SSE │
│ Pareamento + Limitação │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Configuração

View File

@ -324,6 +324,47 @@ Panou web React 19 + Vite 6 + Tailwind CSS 4 servit direct din Gateway:
- CI/CD: beta (automat la push) → stable (dispatch manual) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Binare pre-construite pentru Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Cum funcționează (pe scurt)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Configurare

View File

@ -324,6 +324,47 @@ ls -lh target/release/zeroclaw
- CI/CD: бета (авто при push) → стабильный (ручной запуск) → Docker, crates.io, Scoop, AUR, Homebrew, твит.
- Предсобранные бинарные файлы для Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Как это работает (кратко)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Конфигурация

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 webbpanel serverad direkt från Gateway:
- CI/CD: beta (automatiskt vid push) → stable (manuell dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Förbyggda binärer för Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Hur det fungerar (kort)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (kontrollplan) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Webbpanel (React 19) │
│ REST API + WebSocket + SSE │
│ Parkoppling + Hastighetsbegränsning │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Konfiguration

View File

@ -324,6 +324,47 @@ Feature-gated: Matrix (`channel-matrix`), Lark (`channel-lark`), Nostr (`channel
- CI/CD: beta (อัตโนมัติเมื่อ push) → stable (dispatch แบบ manual) → Docker, crates.io, Scoop, AUR, Homebrew, tweet
- ไบนารี pre-built สำหรับ Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64)
## วิธีการทำงาน (สั้น)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## การกำหนดค่า

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 web dashboard na direktang inihahatid mula sa
- CI/CD: beta (auto sa push) → stable (manual dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Pre-built binaries para sa Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Paano gumagana (maikli)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Configuration

View File

@ -324,6 +324,47 @@ Gateway'den doğrudan sunulan React 19 + Vite 6 + Tailwind CSS 4 web paneli:
- CI/CD: beta (push'ta otomatik) → stable (manuel dispatch) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64) için önceden derlenmiş ikili dosyalar.
## Nasıl çalışır (kısaca)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Yapılandırma

View File

@ -324,6 +324,47 @@ ls -lh target/release/zeroclaw
- CI/CD: beta (автоматично при push) → stable (ручний запуск) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Попередньо зібрані бінарні файли для Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Як це працює (коротко)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Конфігурація

View File

@ -324,6 +324,47 @@ Gateway سے براہ راست فراہم کردہ React 19 + Vite 6 + Tailwind
- CI/CD: beta (push پر خودکار) → stable (دستی dispatch) → Docker، crates.io، Scoop، AUR، Homebrew، tweet۔
- Linux (x86_64، aarch64، armv7)، macOS (x86_64، aarch64)، Windows (x86_64) کے لیے پری بلٹ بائنریز۔
## یہ کیسے کام کرتا ہے (مختصر)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## کنفیگریشن

View File

@ -324,6 +324,47 @@ Bảng điều khiển web React 19 + Vite 6 + Tailwind CSS 4 được phục v
- CI/CD: beta (tự động khi push) → stable (dispatch thủ công) → Docker, crates.io, Scoop, AUR, Homebrew, tweet.
- Binary dựng sẵn cho Linux (x86_64, aarch64, armv7), macOS (x86_64, aarch64), Windows (x86_64).
## Cách hoạt động (tóm tắt)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## Cấu hình

View File

@ -324,6 +324,47 @@ React 19 + Vite 6 + Tailwind CSS 4 网页仪表板直接从 Gateway 提供:
- CI/CDbeta推送时自动→ stable手动触发→ Docker、crates.io、Scoop、AUR、Homebrew、tweet。
- 预构建二进制文件支持 Linuxx86_64、aarch64、armv7、macOSx86_64、aarch64、Windowsx86_64
## 工作原理(简述)
```
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Matrix / IRC / Email
Bluesky / Nostr / Mattermost / DingTalk / Lark / QQ / Reddit / MQTT / WebSocket
┌───────────────────────────────┐
│ Gateway │
│ (control plane) │
│ http://127.0.0.1:42617 │
├───────────────────────────────┤
│ Web Dashboard (React 19) │
│ REST API + WebSocket + SSE │
│ Pairing + Rate Limiting │
└──────────────┬────────────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Agent │ │ Cron │ │ Hands │
│ Loop │ │Scheduler│ │ Swarm │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└──────────┼──────────┘
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Provider│ │ Tools │ │ Memory │
│ (LLM) │ │ (70+) │ │(md/sql)│
└────────┘ └────────┘ └────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│Security│ │ Peripherals│
│ Policy │ │(ESP32/STM32)│
└────────┘ └────────────┘
```
## 配置

View File

@ -1,29 +0,0 @@
[package]
name = "zeroclaw-desktop"
version = "0.1.0"
edition = "2021"
description = "ZeroClaw Desktop — Tauri-powered system tray app"
publish = false
[build-dependencies]
tauri-build = { version = "2.0", features = [] }
[dependencies]
tauri = { version = "2.0", features = ["tray-icon", "image-png"] }
tauri-plugin-shell = "2.0"
tauri-plugin-store = "2.0"
tauri-plugin-single-instance = "2.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
tokio = { version = "1.50", features = ["rt-multi-thread", "macros", "sync", "time"] }
anyhow = "1.0"
[target.'cfg(target_os = "macos")'.dependencies]
objc2 = "0.6"
objc2-app-kit = { version = "0.3", features = ["NSApplication", "NSImage", "NSRunningApplication"] }
objc2-foundation = { version = "0.3", features = ["NSData"] }
[features]
default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]

View File

@ -1,3 +0,0 @@
fn main() {
tauri_build::build();
}

View File

@ -1,14 +0,0 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Default capability set for ZeroClaw Desktop",
"windows": ["main"],
"permissions": [
"core:default",
"shell:allow-open",
"store:allow-get",
"store:allow-set",
"store:allow-save",
"store:allow-load"
]
}

View File

@ -1,14 +0,0 @@
{
"identifier": "desktop",
"description": "Desktop-specific permissions for ZeroClaw",
"windows": ["main"],
"permissions": [
"core:default",
"shell:allow-open",
"shell:allow-execute",
"store:allow-get",
"store:allow-set",
"store:allow-save",
"store:allow-load"
]
}

View File

@ -1,8 +0,0 @@
{
"identifier": "mobile",
"description": "Mobile-specific permissions for ZeroClaw",
"windows": ["main"],
"permissions": [
"core:default"
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

View File

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
<rect width="128" height="128" rx="16" fill="#DC322F"/>
<text x="64" y="80" font-size="64" font-family="monospace" font-weight="bold" fill="white" text-anchor="middle">Z</text>
</svg>

Before

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

View File

@ -1,17 +0,0 @@
use crate::gateway_client::GatewayClient;
use crate::state::SharedState;
use tauri::State;
#[tauri::command]
pub async fn send_message(
state: State<'_, SharedState>,
message: String,
) -> Result<serde_json::Value, String> {
let s = state.read().await;
let client = GatewayClient::new(&s.gateway_url, s.token.as_deref());
drop(s);
client
.send_webhook_message(&message)
.await
.map_err(|e| e.to_string())
}

View File

@ -1,11 +0,0 @@
use crate::gateway_client::GatewayClient;
use crate::state::SharedState;
use tauri::State;
#[tauri::command]
pub async fn list_channels(state: State<'_, SharedState>) -> Result<serde_json::Value, String> {
let s = state.read().await;
let client = GatewayClient::new(&s.gateway_url, s.token.as_deref());
drop(s);
client.get_status().await.map_err(|e| e.to_string())
}

View File

@ -1,19 +0,0 @@
use crate::gateway_client::GatewayClient;
use crate::state::SharedState;
use tauri::State;
#[tauri::command]
pub async fn get_status(state: State<'_, SharedState>) -> Result<serde_json::Value, String> {
let s = state.read().await;
let client = GatewayClient::new(&s.gateway_url, s.token.as_deref());
drop(s);
client.get_status().await.map_err(|e| e.to_string())
}
#[tauri::command]
pub async fn get_health(state: State<'_, SharedState>) -> Result<bool, String> {
let s = state.read().await;
let client = GatewayClient::new(&s.gateway_url, s.token.as_deref());
drop(s);
client.get_health().await.map_err(|e| e.to_string())
}

View File

@ -1,4 +0,0 @@
pub mod agent;
pub mod channels;
pub mod gateway;
pub mod pairing;

View File

@ -1,19 +0,0 @@
use crate::gateway_client::GatewayClient;
use crate::state::SharedState;
use tauri::State;
#[tauri::command]
pub async fn initiate_pairing(state: State<'_, SharedState>) -> Result<serde_json::Value, String> {
let s = state.read().await;
let client = GatewayClient::new(&s.gateway_url, s.token.as_deref());
drop(s);
client.initiate_pairing().await.map_err(|e| e.to_string())
}
#[tauri::command]
pub async fn get_devices(state: State<'_, SharedState>) -> Result<serde_json::Value, String> {
let s = state.read().await;
let client = GatewayClient::new(&s.gateway_url, s.token.as_deref());
drop(s);
client.get_devices().await.map_err(|e| e.to_string())
}

View File

@ -1,213 +0,0 @@
//! HTTP client for communicating with the ZeroClaw gateway.
use anyhow::{Context, Result};
pub struct GatewayClient {
pub(crate) base_url: String,
pub(crate) token: Option<String>,
client: reqwest::Client,
}
impl GatewayClient {
pub fn new(base_url: &str, token: Option<&str>) -> Self {
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()
.unwrap_or_default();
Self {
base_url: base_url.to_string(),
token: token.map(String::from),
client,
}
}
pub(crate) fn auth_header(&self) -> Option<String> {
self.token.as_ref().map(|t| format!("Bearer {t}"))
}
pub async fn get_status(&self) -> Result<serde_json::Value> {
let mut req = self.client.get(format!("{}/api/status", self.base_url));
if let Some(auth) = self.auth_header() {
req = req.header("Authorization", auth);
}
let resp = req.send().await.context("status request failed")?;
Ok(resp.json().await?)
}
pub async fn get_health(&self) -> Result<bool> {
match self
.client
.get(format!("{}/health", self.base_url))
.send()
.await
{
Ok(resp) => Ok(resp.status().is_success()),
Err(_) => Ok(false),
}
}
pub async fn get_devices(&self) -> Result<serde_json::Value> {
let mut req = self.client.get(format!("{}/api/devices", self.base_url));
if let Some(auth) = self.auth_header() {
req = req.header("Authorization", auth);
}
let resp = req.send().await.context("devices request failed")?;
Ok(resp.json().await?)
}
pub async fn initiate_pairing(&self) -> Result<serde_json::Value> {
let mut req = self
.client
.post(format!("{}/api/pairing/initiate", self.base_url));
if let Some(auth) = self.auth_header() {
req = req.header("Authorization", auth);
}
let resp = req.send().await.context("pairing request failed")?;
Ok(resp.json().await?)
}
/// Check whether the gateway requires pairing.
pub async fn requires_pairing(&self) -> Result<bool> {
let resp = self
.client
.get(format!("{}/health", self.base_url))
.send()
.await
.context("health request failed")?;
let body: serde_json::Value = resp.json().await?;
Ok(body["require_pairing"].as_bool().unwrap_or(false))
}
/// Request a new pairing code from the gateway (localhost-only admin endpoint).
pub async fn request_new_paircode(&self) -> Result<String> {
let resp = self
.client
.post(format!("{}/admin/paircode/new", self.base_url))
.send()
.await
.context("paircode request failed")?;
let body: serde_json::Value = resp.json().await?;
body["pairing_code"]
.as_str()
.map(String::from)
.context("no pairing_code in response")
}
/// Exchange a pairing code for a bearer token.
pub async fn pair_with_code(&self, code: &str) -> Result<String> {
let resp = self
.client
.post(format!("{}/pair", self.base_url))
.header("X-Pairing-Code", code)
.send()
.await
.context("pair request failed")?;
if !resp.status().is_success() {
anyhow::bail!("pair request returned {}", resp.status());
}
let body: serde_json::Value = resp.json().await?;
body["token"]
.as_str()
.map(String::from)
.context("no token in pair response")
}
/// Validate an existing token by calling a protected endpoint.
pub async fn validate_token(&self) -> Result<bool> {
let mut req = self.client.get(format!("{}/api/status", self.base_url));
if let Some(auth) = self.auth_header() {
req = req.header("Authorization", auth);
}
match req.send().await {
Ok(resp) => Ok(resp.status().is_success()),
Err(_) => Ok(false),
}
}
/// Auto-pair with the gateway: request a new code and exchange it for a token.
pub async fn auto_pair(&self) -> Result<String> {
let code = self.request_new_paircode().await?;
self.pair_with_code(&code).await
}
pub async fn send_webhook_message(&self, message: &str) -> Result<serde_json::Value> {
let mut req = self
.client
.post(format!("{}/webhook", self.base_url))
.json(&serde_json::json!({ "message": message }));
if let Some(auth) = self.auth_header() {
req = req.header("Authorization", auth);
}
let resp = req.send().await.context("webhook request failed")?;
Ok(resp.json().await?)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn client_creation_no_token() {
let client = GatewayClient::new("http://127.0.0.1:42617", None);
assert_eq!(client.base_url, "http://127.0.0.1:42617");
assert!(client.token.is_none());
assert!(client.auth_header().is_none());
}
#[test]
fn client_creation_with_token() {
let client = GatewayClient::new("http://localhost:8080", Some("test-token"));
assert_eq!(client.base_url, "http://localhost:8080");
assert_eq!(client.token.as_deref(), Some("test-token"));
assert_eq!(client.auth_header().unwrap(), "Bearer test-token");
}
#[test]
fn client_custom_url() {
let client = GatewayClient::new("https://zeroclaw.example.com:9999", None);
assert_eq!(client.base_url, "https://zeroclaw.example.com:9999");
}
#[test]
fn auth_header_format() {
let client = GatewayClient::new("http://localhost", Some("zc_abc123"));
assert_eq!(client.auth_header().unwrap(), "Bearer zc_abc123");
}
#[tokio::test]
async fn health_returns_false_for_unreachable_host() {
// Connect to a port that should not be listening.
let client = GatewayClient::new("http://127.0.0.1:1", None);
let result = client.get_health().await.unwrap();
assert!(!result, "health should be false for unreachable host");
}
#[tokio::test]
async fn status_fails_for_unreachable_host() {
let client = GatewayClient::new("http://127.0.0.1:1", None);
let result = client.get_status().await;
assert!(result.is_err(), "status should fail for unreachable host");
}
#[tokio::test]
async fn devices_fails_for_unreachable_host() {
let client = GatewayClient::new("http://127.0.0.1:1", None);
let result = client.get_devices().await;
assert!(result.is_err(), "devices should fail for unreachable host");
}
#[tokio::test]
async fn pairing_fails_for_unreachable_host() {
let client = GatewayClient::new("http://127.0.0.1:1", None);
let result = client.initiate_pairing().await;
assert!(result.is_err(), "pairing should fail for unreachable host");
}
#[tokio::test]
async fn webhook_fails_for_unreachable_host() {
let client = GatewayClient::new("http://127.0.0.1:1", None);
let result = client.send_webhook_message("hello").await;
assert!(result.is_err(), "webhook should fail for unreachable host");
}
}

View File

@ -1,40 +0,0 @@
//! Background health polling for the ZeroClaw gateway.
use crate::gateway_client::GatewayClient;
use crate::state::SharedState;
use crate::tray::icon;
use std::time::Duration;
use tauri::{AppHandle, Emitter, Runtime};
const POLL_INTERVAL: Duration = Duration::from_secs(5);
/// Spawn a background task that polls gateway health and updates state + tray.
pub fn spawn_health_poller<R: Runtime>(app: AppHandle<R>, state: SharedState) {
tauri::async_runtime::spawn(async move {
loop {
let (url, token) = {
let s = state.read().await;
(s.gateway_url.clone(), s.token.clone())
};
let client = GatewayClient::new(&url, token.as_deref());
let healthy = client.get_health().await.unwrap_or(false);
let (connected, agent_status) = {
let mut s = state.write().await;
s.connected = healthy;
(s.connected, s.agent_status)
};
// Update the tray icon and tooltip to reflect current state.
if let Some(tray) = app.tray_by_id("main") {
let _ = tray.set_icon(Some(icon::icon_for_state(connected, agent_status)));
let _ = tray.set_tooltip(Some(icon::tooltip_for_state(connected, agent_status)));
}
let _ = app.emit("zeroclaw://status-changed", healthy);
tokio::time::sleep(POLL_INTERVAL).await;
}
});
}

View File

@ -1,136 +0,0 @@
//! ZeroClaw Desktop — Tauri application library.
pub mod commands;
pub mod gateway_client;
pub mod health;
pub mod state;
pub mod tray;
use gateway_client::GatewayClient;
use state::shared_state;
use tauri::{Manager, RunEvent};
/// Attempt to auto-pair with the gateway so the WebView has a valid token
/// before the React frontend mounts. Runs on localhost so the admin endpoints
/// are accessible without auth.
async fn auto_pair(state: &state::SharedState) -> Option<String> {
let url = {
let s = state.read().await;
s.gateway_url.clone()
};
let client = GatewayClient::new(&url, None);
// Check if gateway is reachable and requires pairing.
if !client.requires_pairing().await.unwrap_or(false) {
return None; // Pairing disabled — no token needed.
}
// Check if we already have a valid token in state.
{
let s = state.read().await;
if let Some(ref token) = s.token {
let authed = GatewayClient::new(&url, Some(token));
if authed.validate_token().await.unwrap_or(false) {
return Some(token.clone()); // Existing token is valid.
}
}
}
// No valid token — auto-pair by requesting a new code and exchanging it.
let client = GatewayClient::new(&url, None);
match client.auto_pair().await {
Ok(token) => {
let mut s = state.write().await;
s.token = Some(token.clone());
Some(token)
}
Err(_) => None, // Gateway may not be ready yet; health poller will retry.
}
}
/// Inject a bearer token into the WebView's localStorage so the React app
/// skips the pairing dialog. Uses Tauri's WebviewWindow scripting API.
fn inject_token_into_webview<R: tauri::Runtime>(window: &tauri::WebviewWindow<R>, token: &str) {
let escaped = token.replace('\\', "\\\\").replace('\'', "\\'");
let script = format!("localStorage.setItem('zeroclaw_token', '{escaped}')");
// WebviewWindow scripting is the standard Tauri API for running JS in the WebView.
let _ = window.eval(&script);
}
/// Set the macOS dock icon programmatically so it shows even in dev builds
/// (which don't have a proper .app bundle).
#[cfg(target_os = "macos")]
fn set_dock_icon() {
use objc2::{AnyThread, MainThreadMarker};
use objc2_app_kit::NSApplication;
use objc2_app_kit::NSImage;
use objc2_foundation::NSData;
let icon_bytes = include_bytes!("../icons/128x128.png");
// Safety: setup() runs on the main thread in Tauri.
let mtm = unsafe { MainThreadMarker::new_unchecked() };
let data = NSData::with_bytes(icon_bytes);
if let Some(image) = NSImage::initWithData(NSImage::alloc(), &data) {
let app = NSApplication::sharedApplication(mtm);
unsafe { app.setApplicationIconImage(Some(&image)) };
}
}
/// Configure and run the Tauri application.
pub fn run() {
let shared = shared_state();
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_store::Builder::default().build())
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
// When a second instance launches, focus the existing window.
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}))
.manage(shared.clone())
.invoke_handler(tauri::generate_handler![
commands::gateway::get_status,
commands::gateway::get_health,
commands::channels::list_channels,
commands::pairing::initiate_pairing,
commands::pairing::get_devices,
commands::agent::send_message,
])
.setup(move |app| {
// Set macOS dock icon (needed for dev builds without .app bundle).
#[cfg(target_os = "macos")]
set_dock_icon();
// Set up the system tray.
let _ = tray::setup_tray(app);
// Auto-pair with gateway and inject token into the WebView.
let app_handle = app.handle().clone();
let pair_state = shared.clone();
tauri::async_runtime::spawn(async move {
if let Some(token) = auto_pair(&pair_state).await {
if let Some(window) = app_handle.get_webview_window("main") {
inject_token_into_webview(&window, &token);
}
}
});
// Start background health polling.
health::spawn_health_poller(app.handle().clone(), shared.clone());
Ok(())
})
.build(tauri::generate_context!())
.expect("error while building tauri application")
.run(|_app, event| {
// Keep the app running in the background when all windows are closed.
// This is the standard pattern for menu bar / tray apps.
if let RunEvent::ExitRequested { api, .. } = event {
api.prevent_exit();
}
});
}

View File

@ -1,8 +0,0 @@
//! ZeroClaw Desktop — main entry point.
//!
//! Prevents an additional console window on Windows in release.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
zeroclaw_desktop::run();
}

View File

@ -1,6 +0,0 @@
//! Mobile entry point for ZeroClaw Desktop (iOS/Android).
#[tauri::mobile_entry_point]
fn main() {
zeroclaw_desktop::run();
}

View File

@ -1,99 +0,0 @@
//! Shared application state for Tauri.
use std::sync::Arc;
use tokio::sync::RwLock;
/// Agent status as reported by the gateway.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub enum AgentStatus {
Idle,
Working,
Error,
}
/// Shared application state behind an `Arc<RwLock<_>>`.
#[derive(Debug, Clone)]
pub struct AppState {
pub gateway_url: String,
pub token: Option<String>,
pub connected: bool,
pub agent_status: AgentStatus,
}
impl Default for AppState {
fn default() -> Self {
Self {
gateway_url: "http://127.0.0.1:42617".to_string(),
token: None,
connected: false,
agent_status: AgentStatus::Idle,
}
}
}
/// Thread-safe wrapper around `AppState`.
pub type SharedState = Arc<RwLock<AppState>>;
/// Create the default shared state.
pub fn shared_state() -> SharedState {
Arc::new(RwLock::new(AppState::default()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_state() {
let state = AppState::default();
assert_eq!(state.gateway_url, "http://127.0.0.1:42617");
assert!(state.token.is_none());
assert!(!state.connected);
assert_eq!(state.agent_status, AgentStatus::Idle);
}
#[test]
fn shared_state_is_cloneable() {
let s1 = shared_state();
let s2 = s1.clone();
// Both references point to the same allocation.
assert!(Arc::ptr_eq(&s1, &s2));
}
#[tokio::test]
async fn shared_state_concurrent_read_write() {
let state = shared_state();
// Write from one handle.
{
let mut s = state.write().await;
s.connected = true;
s.agent_status = AgentStatus::Working;
s.token = Some("zc_test".to_string());
}
// Read from cloned handle.
let state2 = state.clone();
let s = state2.read().await;
assert!(s.connected);
assert_eq!(s.agent_status, AgentStatus::Working);
assert_eq!(s.token.as_deref(), Some("zc_test"));
}
#[test]
fn agent_status_serialization() {
assert_eq!(
serde_json::to_string(&AgentStatus::Idle).unwrap(),
"\"idle\""
);
assert_eq!(
serde_json::to_string(&AgentStatus::Working).unwrap(),
"\"working\""
);
assert_eq!(
serde_json::to_string(&AgentStatus::Error).unwrap(),
"\"error\""
);
}
}

View File

@ -1,25 +0,0 @@
//! Tray menu event handling.
use tauri::{menu::MenuEvent, AppHandle, Manager, Runtime};
pub fn handle_menu_event<R: Runtime>(app: &AppHandle<R>, event: MenuEvent) {
match event.id().as_ref() {
"show" => show_main_window(app, None),
"chat" => show_main_window(app, Some("/agent")),
"quit" => {
app.exit(0);
}
_ => {}
}
}
fn show_main_window<R: Runtime>(app: &AppHandle<R>, navigate_to: Option<&str>) {
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
if let Some(path) = navigate_to {
let script = format!("window.location.hash = '{path}'");
let _ = window.eval(&script);
}
}
}

View File

@ -1,105 +0,0 @@
//! Tray icon management — swap icon based on connection/agent status.
use crate::state::AgentStatus;
use tauri::image::Image;
/// Embedded tray icon PNGs (22x22, RGBA).
const ICON_IDLE: &[u8] = include_bytes!("../../icons/tray-idle.png");
const ICON_WORKING: &[u8] = include_bytes!("../../icons/tray-working.png");
const ICON_ERROR: &[u8] = include_bytes!("../../icons/tray-error.png");
const ICON_DISCONNECTED: &[u8] = include_bytes!("../../icons/tray-disconnected.png");
/// Select the appropriate tray icon for the current state.
pub fn icon_for_state(connected: bool, status: AgentStatus) -> Image<'static> {
let bytes: &[u8] = if !connected {
ICON_DISCONNECTED
} else {
match status {
AgentStatus::Idle => ICON_IDLE,
AgentStatus::Working => ICON_WORKING,
AgentStatus::Error => ICON_ERROR,
}
};
Image::from_bytes(bytes).expect("embedded tray icon is a valid PNG")
}
/// Tooltip text for the current state.
pub fn tooltip_for_state(connected: bool, status: AgentStatus) -> &'static str {
if !connected {
return "ZeroClaw — Disconnected";
}
match status {
AgentStatus::Idle => "ZeroClaw — Idle",
AgentStatus::Working => "ZeroClaw — Working",
AgentStatus::Error => "ZeroClaw — Error",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn icon_disconnected_when_not_connected() {
// Should not panic — icon bytes are valid PNGs.
let _img = icon_for_state(false, AgentStatus::Idle);
let _img = icon_for_state(false, AgentStatus::Working);
let _img = icon_for_state(false, AgentStatus::Error);
}
#[test]
fn icon_connected_variants() {
let _idle = icon_for_state(true, AgentStatus::Idle);
let _working = icon_for_state(true, AgentStatus::Working);
let _error = icon_for_state(true, AgentStatus::Error);
}
#[test]
fn tooltip_disconnected() {
assert_eq!(
tooltip_for_state(false, AgentStatus::Idle),
"ZeroClaw — Disconnected"
);
// Agent status is irrelevant when disconnected.
assert_eq!(
tooltip_for_state(false, AgentStatus::Working),
"ZeroClaw — Disconnected"
);
assert_eq!(
tooltip_for_state(false, AgentStatus::Error),
"ZeroClaw — Disconnected"
);
}
#[test]
fn tooltip_connected_variants() {
assert_eq!(
tooltip_for_state(true, AgentStatus::Idle),
"ZeroClaw — Idle"
);
assert_eq!(
tooltip_for_state(true, AgentStatus::Working),
"ZeroClaw — Working"
);
assert_eq!(
tooltip_for_state(true, AgentStatus::Error),
"ZeroClaw — Error"
);
}
#[test]
fn embedded_icons_are_valid_png() {
// Verify the PNG signature (first 8 bytes) of each embedded icon.
let png_sig: &[u8] = &[0x89, b'P', b'N', b'G', 0x0D, 0x0A, 0x1A, 0x0A];
assert!(ICON_IDLE.starts_with(png_sig), "idle icon not valid PNG");
assert!(
ICON_WORKING.starts_with(png_sig),
"working icon not valid PNG"
);
assert!(ICON_ERROR.starts_with(png_sig), "error icon not valid PNG");
assert!(
ICON_DISCONNECTED.starts_with(png_sig),
"disconnected icon not valid PNG"
);
}
}

View File

@ -1,19 +0,0 @@
//! Tray menu construction.
use tauri::{
menu::{Menu, MenuItemBuilder, PredefinedMenuItem},
App, Runtime,
};
pub fn create_tray_menu<R: Runtime>(app: &App<R>) -> Result<Menu<R>, tauri::Error> {
let show = MenuItemBuilder::with_id("show", "Show Dashboard").build(app)?;
let chat = MenuItemBuilder::with_id("chat", "Agent Chat").build(app)?;
let sep1 = PredefinedMenuItem::separator(app)?;
let status = MenuItemBuilder::with_id("status", "Status: Checking...")
.enabled(false)
.build(app)?;
let sep2 = PredefinedMenuItem::separator(app)?;
let quit = MenuItemBuilder::with_id("quit", "Quit ZeroClaw").build(app)?;
Menu::with_items(app, &[&show, &chat, &sep1, &status, &sep2, &quit])
}

View File

@ -1,34 +0,0 @@
//! System tray integration for ZeroClaw Desktop.
pub mod events;
pub mod icon;
pub mod menu;
use tauri::{
tray::{TrayIcon, TrayIconBuilder, TrayIconEvent},
App, Manager, Runtime,
};
/// Set up the system tray icon and menu.
pub fn setup_tray<R: Runtime>(app: &App<R>) -> Result<TrayIcon<R>, tauri::Error> {
let menu = menu::create_tray_menu(app)?;
TrayIconBuilder::with_id("main")
.tooltip("ZeroClaw — Disconnected")
.icon(icon::icon_for_state(false, crate::state::AgentStatus::Idle))
.menu(&menu)
.show_menu_on_left_click(false)
.on_menu_event(events::handle_menu_event)
.on_tray_icon_event(|tray, event| {
if let TrayIconEvent::Click { button, .. } = event {
if button == tauri::tray::MouseButton::Left {
let app = tray.app_handle();
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}
}
})
.build(app)
}

View File

@ -1,35 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-cli/config.schema.json",
"productName": "ZeroClaw",
"version": "0.6.1",
"identifier": "ai.zeroclawlabs.desktop",
"build": {
"devUrl": "http://127.0.0.1:42617/_app/",
"frontendDist": "http://127.0.0.1:42617/_app/"
},
"app": {
"windows": [
{
"title": "ZeroClaw",
"width": 1200,
"height": 800,
"resizable": true,
"fullscreen": false,
"visible": false
}
],
"security": {
"csp": "default-src 'self' http://127.0.0.1:* ws://127.0.0.1:*; connect-src 'self' http://127.0.0.1:* ws://127.0.0.1:*; script-src 'self' 'unsafe-inline' http://127.0.0.1:*; style-src 'self' 'unsafe-inline' http://127.0.0.1:*; img-src 'self' http://127.0.0.1:* data:"
}
},
"bundle": {
"active": true,
"targets": "all",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}

View File

@ -263,7 +263,7 @@ fn bench_memory_operations(c: &mut Criterion) {
c.bench_function("memory_recall_top10", |b| {
b.iter(|| {
rt.block_on(async {
mem.recall(black_box("zeroclaw agent"), 10, None, None, None)
mem.recall(black_box("zeroclaw agent"), 10, None)
.await
.unwrap()
})

View File

@ -10,22 +10,3 @@ default_temperature = 0.7
port = 42617
host = "[::]"
allow_public_bind = true
# Cost tracking and budget enforcement configuration
# Enable to track API usage costs and enforce spending limits
[cost]
enabled = false
daily_limit_usd = 10.0
monthly_limit_usd = 100.0
warn_at_percent = 80
allow_override = false
# Per-model pricing (USD per 1M tokens)
# Uncomment and customize to override default pricing
# [cost.prices."anthropic/claude-sonnet-4-20250514"]
# input = 3.0
# output = 15.0
#
# [cost.prices."openai/gpt-4o"]
# input = 5.0
# output = 15.0

4
dist/aur/.SRCINFO vendored
View File

@ -1,6 +1,6 @@
pkgbase = zeroclaw
pkgdesc = Zero overhead. Zero compromise. 100% Rust. The fastest, smallest AI assistant.
pkgver = 0.5.9
pkgver = 0.5.3
pkgrel = 1
url = https://github.com/zeroclaw-labs/zeroclaw
arch = x86_64
@ -10,7 +10,7 @@ pkgbase = zeroclaw
makedepends = git
depends = gcc-libs
depends = openssl
source = zeroclaw-0.5.9.tar.gz::https://github.com/zeroclaw-labs/zeroclaw/archive/refs/tags/v0.5.9.tar.gz
source = zeroclaw-0.5.3.tar.gz::https://github.com/zeroclaw-labs/zeroclaw/archive/refs/tags/v0.5.3.tar.gz
sha256sums = SKIP
pkgname = zeroclaw

2
dist/aur/PKGBUILD vendored
View File

@ -1,6 +1,6 @@
# Maintainer: zeroclaw-labs <bot@zeroclaw.dev>
pkgname=zeroclaw
pkgver=0.5.9
pkgver=0.5.3
pkgrel=1
pkgdesc="Zero overhead. Zero compromise. 100% Rust. The fastest, smallest AI assistant."
arch=('x86_64')

View File

@ -1,11 +1,11 @@
{
"version": "0.5.9",
"version": "0.5.3",
"description": "Zero overhead. Zero compromise. 100% Rust. The fastest, smallest AI assistant.",
"homepage": "https://github.com/zeroclaw-labs/zeroclaw",
"license": "MIT|Apache-2.0",
"architecture": {
"64bit": {
"url": "https://github.com/zeroclaw-labs/zeroclaw/releases/download/v0.5.9/zeroclaw-x86_64-pc-windows-msvc.zip",
"url": "https://github.com/zeroclaw-labs/zeroclaw/releases/download/v0.5.3/zeroclaw-x86_64-pc-windows-msvc.zip",
"hash": "",
"bin": "zeroclaw.exe"
}

View File

@ -1,202 +0,0 @@
# ADR-004: Tool Shared State Ownership Contract
**Status:** Accepted
**Date:** 2026-03-22
**Issue:** [#4057](https://github.com/zeroclaw/zeroclaw/issues/4057)
## Context
ZeroClaw tools execute in a multi-client environment where a single daemon
process serves requests from multiple connected clients simultaneously. Several
tools already maintain long-lived shared state:
- **`DelegateParentToolsHandle`** (`src/tools/mod.rs`):
`Arc<RwLock<Vec<Arc<dyn Tool>>>>` — holds parent tools for delegate agents
with no per-client isolation.
- **`ChannelMapHandle`** (`src/tools/reaction.rs`):
`Arc<RwLock<HashMap<String, Arc<dyn Channel>>>>` — global channel map shared
across all clients.
- **`CanvasStore`** (`src/tools/canvas.rs`):
`Arc<RwLock<HashMap<String, CanvasEntry>>>` — canvas IDs are plain strings
with no client namespace.
These patterns emerged organically. As the tool surface grows and more clients
connect concurrently, we need a clear contract governing ownership, identity,
isolation, lifecycle, and reload behavior for tool-held shared state. Without
this contract, new tools risk introducing data leaks between clients, stale
state after config reloads, or inconsistent initialization timing.
Additional context:
- The tool registry is immutable after startup, built once in
`all_tools_with_runtime()`.
- Client identity is currently derived from IP address only
(`src/gateway/mod.rs`), which is insufficient for reliable namespacing.
- `SecurityPolicy` is scoped per agent, not per client.
- `WorkspaceManager` provides some isolation but workspace switching is global.
## Decision
### 1. Ownership: May tools own long-lived shared state?
**Yes.** Tools MAY own long-lived shared state, provided they follow the
established **handle pattern**: wrap the state in `Arc<RwLock<T>>` (or
`Arc<parking_lot::RwLock<T>>`) and expose a cloneable handle type.
This pattern is already proven by three independent implementations:
| Handle | Location | Inner type |
|--------|----------|-----------|
| `DelegateParentToolsHandle` | `src/tools/mod.rs` | `Vec<Arc<dyn Tool>>` |
| `ChannelMapHandle` | `src/tools/reaction.rs` | `HashMap<String, Arc<dyn Channel>>` |
| `CanvasStore` | `src/tools/canvas.rs` | `HashMap<String, CanvasEntry>` |
Tools that need shared state MUST:
- Define a named handle type alias (e.g., `pub type FooHandle = Arc<RwLock<T>>`).
- Accept the handle at construction time rather than creating global state.
- Document the concurrency contract in the handle type's doc comment.
Tools MUST NOT use static mutable state (`lazy_static!`, `OnceCell` with
interior mutability) for per-request or per-client data.
### 2. Identity assignment: Who constructs identity keys?
**The daemon SHOULD provide identity.** Tools MUST NOT construct their own
client identity keys.
A new `ClientId` type should be introduced (opaque, `Clone + Eq + Hash + Send + Sync`)
that the daemon assigns at connection time. This replaces the current approach
of using raw IP addresses (`src/gateway/mod.rs:259-306`), which breaks when
multiple clients share a NAT address or when proxied connections arrive.
`ClientId` is passed to tools that require per-client state namespacing as part
of the tool execution context. Tools that do not need per-client isolation
(e.g., the immutable tool registry) may ignore it.
The `ClientId` contract:
- Generated by the gateway layer at connection establishment.
- Opaque to tools — tools must not parse or derive meaning from the value.
- Stable for the lifetime of a single client session.
- Passed through the execution context, not stored globally.
### 3. Lifecycle: When may tools run startup-style validation?
**Validation runs once at first registration, and again when config changes
are detected.**
The lifecycle phases are:
1. **Construction** — tool is instantiated with handles and config. No I/O or
validation occurs here.
2. **Registration** — tool is registered in the tool registry via
`all_tools_with_runtime()`. At this point the tool MAY perform one-time
startup validation (e.g., checking that required credentials exist, verifying
external service connectivity).
3. **Execution** — tool handles individual requests. No re-validation unless
the config-change signal fires (see Reload Semantics below).
4. **Shutdown** — daemon is stopping. Tools with open resources SHOULD clean up
gracefully via `Drop` or an explicit shutdown method.
Tools MUST NOT perform blocking validation during execution-phase calls.
Validation results SHOULD be cached in the tool's handle state and checked
via a fast path during execution.
### 4. Isolation: What must be isolated per client?
State falls into two categories with different isolation requirements:
**MUST be isolated per client:**
- Security-sensitive state: credentials, API keys, quotas, rate-limit counters,
per-client authorization decisions.
- User-specific session data: conversation context, user preferences,
workspace-scoped file paths.
Isolation mechanism: tools holding per-client state MUST key their internal
maps by `ClientId`. The handle pattern naturally supports this by using
`HashMap<ClientId, T>` inside the `RwLock`.
**MAY be shared across clients (with namespace prefixing):**
- Broadcast/display state: canvas frames (`CanvasStore`), notification channels
(`ChannelMapHandle`).
- Read-only reference data: tool registry, static configuration, model
metadata.
When shared state uses string keys (e.g., canvas IDs, channel names), tools
SHOULD support optional namespace prefixing (e.g., `{client_id}:{canvas_name}`)
to allow per-client isolation when needed without mandating it for broadcast
use cases.
Tools MUST NOT store per-client secrets in shared (non-isolated) state
structures.
### 5. Reload semantics: What invalidates prior shared state on config change?
**Config changes detected via hash comparison MUST invalidate cached
validation state.**
The reload contract:
- The daemon computes a hash of the tool-relevant config section at startup and
after each config reload event.
- When the hash changes, the daemon signals affected tools to re-run their
registration-phase validation.
- Tools MUST treat their cached validation result as stale when signaled and
re-validate before the next execution.
Specific invalidation rules:
| Config change | Invalidation scope |
|--------------|-------------------|
| Credential/secret rotation | Per-tool validation cache; per-client credential state |
| Tool enable/disable | Full tool registry rebuild via `all_tools_with_runtime()` |
| Security policy change | `SecurityPolicy` re-derivation; per-agent policy state |
| Workspace directory change | `WorkspaceManager` state; file-path-dependent tool state |
| Provider config change | Provider-dependent tools re-validate connectivity |
Tools MAY retain non-security shared state (e.g., canvas content, channel
subscriptions) across config reloads unless the reload explicitly affects that
state's validity.
## Consequences
### Positive
- **Consistency:** All new tools follow the same handle pattern, making shared
state discoverable and auditable.
- **Safety:** Per-client isolation of security-sensitive state prevents data
leaks in multi-tenant scenarios.
- **Clarity:** Explicit lifecycle phases eliminate ambiguity about when
validation runs.
- **Evolvability:** The `ClientId` abstraction decouples tools from transport
details, supporting future identity mechanisms (tokens, certificates).
### Negative
- **Migration cost:** Existing tools (`CanvasStore`, `ReactionTool`) may need
refactoring to accept `ClientId` and namespace their state.
- **Complexity:** Tools that were simple singletons now need to consider
multi-client semantics even if they currently have one client.
- **Performance:** Per-client keying adds a hash lookup on each access, though
this is negligible compared to I/O costs.
### Neutral
- The tool registry remains immutable after startup; this ADR does not change
that invariant.
- `SecurityPolicy` remains per-agent; this ADR documents that client isolation
is orthogonal to agent-level policy.
## References
- `src/tools/mod.rs``DelegateParentToolsHandle`, `all_tools_with_runtime()`
- `src/tools/reaction.rs``ChannelMapHandle`, `ReactionTool`
- `src/tools/canvas.rs``CanvasStore`, `CanvasEntry`
- `src/tools/traits.rs``Tool` trait
- `src/gateway/mod.rs` — client IP extraction (`forwarded_client_ip`, `resolve_client_ip`)
- `src/security/``SecurityPolicy`

View File

@ -1,215 +0,0 @@
# Browser Automation Setup Guide
This guide covers setting up browser automation capabilities in ZeroClaw, including both headless automation and GUI access via VNC.
## Overview
ZeroClaw supports multiple browser access methods:
| Method | Use Case | Requirements |
|--------|----------|--------------|
| **agent-browser CLI** | Headless automation, AI agents | npm, Chrome |
| **VNC + noVNC** | GUI access, debugging | Xvfb, x11vnc, noVNC |
| **Chrome Remote Desktop** | Remote GUI via Google | XFCE, Google account |
## Quick Start: Headless Automation
### 1. Install agent-browser
```bash
# Install CLI
npm install -g agent-browser
# Download Chrome for Testing
agent-browser install --with-deps # Linux (includes system deps)
agent-browser install # macOS/Windows
```
### 2. Verify ZeroClaw Config
The browser tool is enabled by default. To verify or customize, edit
`~/.zeroclaw/config.toml`:
```toml
[browser]
enabled = true # default: true
allowed_domains = ["*"] # default: ["*"] (all public hosts)
backend = "agent_browser" # default: "agent_browser"
native_headless = true # default: true
```
To restrict domains or disable the browser tool:
```toml
[browser]
enabled = false # disable entirely
# or restrict to specific domains:
allowed_domains = ["example.com", "docs.example.com"]
```
### 3. Test
```bash
echo "Open https://example.com and tell me what it says" | zeroclaw agent
```
## VNC Setup (GUI Access)
For debugging or when you need visual browser access:
### Install Dependencies
```bash
# Ubuntu/Debian
apt-get install -y xvfb x11vnc fluxbox novnc websockify
# Optional: Desktop environment for Chrome Remote Desktop
apt-get install -y xfce4 xfce4-goodies
```
### Start VNC Server
```bash
#!/bin/bash
# Start virtual display with VNC access
DISPLAY_NUM=99
VNC_PORT=5900
NOVNC_PORT=6080
RESOLUTION=1920x1080x24
# Start Xvfb
Xvfb :$DISPLAY_NUM -screen 0 $RESOLUTION -ac &
sleep 1
# Start window manager
fluxbox -display :$DISPLAY_NUM &
sleep 1
# Start x11vnc
x11vnc -display :$DISPLAY_NUM -rfbport $VNC_PORT -forever -shared -nopw -bg
sleep 1
# Start noVNC (web-based VNC)
websockify --web=/usr/share/novnc $NOVNC_PORT localhost:$VNC_PORT &
echo "VNC available at:"
echo " VNC Client: localhost:$VNC_PORT"
echo " Web Browser: http://localhost:$NOVNC_PORT/vnc.html"
```
### VNC Access
- **VNC Client**: Connect to `localhost:5900`
- **Web Browser**: Open `http://localhost:6080/vnc.html`
### Start Browser on VNC Display
```bash
DISPLAY=:99 google-chrome --no-sandbox https://example.com &
```
## Chrome Remote Desktop
### Install
```bash
# Download and install
wget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb
apt-get install -y ./chrome-remote-desktop_current_amd64.deb
# Configure session
echo "xfce4-session" > ~/.chrome-remote-desktop-session
chmod +x ~/.chrome-remote-desktop-session
```
### Setup
1. Visit <https://remotedesktop.google.com/headless>
2. Copy the "Debian Linux" setup command
3. Run it on your server
4. Start the service: `systemctl --user start chrome-remote-desktop`
### Remote Access
Go to <https://remotedesktop.google.com/access> from any device.
## Testing
### CLI Tests
```bash
# Basic open and close
agent-browser open https://example.com
agent-browser get title
agent-browser close
# Snapshot with refs
agent-browser open https://example.com
agent-browser snapshot -i
agent-browser close
# Screenshot
agent-browser open https://example.com
agent-browser screenshot /tmp/test.png
agent-browser close
```
### ZeroClaw Integration Tests
```bash
# Content extraction
echo "Open https://example.com and summarize it" | zeroclaw agent
# Navigation
echo "Go to https://github.com/trending and list the top 3 repos" | zeroclaw agent
# Form interaction
echo "Go to Wikipedia, search for 'Rust programming language', and summarize" | zeroclaw agent
```
## Troubleshooting
### "Element not found"
The page may not be fully loaded. Add a wait:
```bash
agent-browser open https://slow-site.com
agent-browser wait --load networkidle
agent-browser snapshot -i
```
### Cookie dialogs blocking access
Handle cookie consent first:
```bash
agent-browser open https://site-with-cookies.com
agent-browser snapshot -i
agent-browser click @accept_cookies # Click the accept button
agent-browser snapshot -i # Now get the actual content
```
### Docker sandbox network restrictions
If `web_fetch` fails inside Docker sandbox, use agent-browser instead:
```bash
# Instead of web_fetch, use:
agent-browser open https://example.com
agent-browser get text body
```
## Security Notes
- `agent-browser` runs Chrome in headless mode with sandboxing
- For sensitive sites, use `--session-name` to persist auth state
- The `--allowed-domains` config restricts navigation to specific domains
- VNC ports (5900, 6080) should be behind a firewall or Tailscale
## Related
- [agent-browser Documentation](https://github.com/vercel-labs/agent-browser)
- [ZeroClaw Configuration Reference](./config-reference.md)
- [Skills Documentation](../skills/)

View File

@ -20,7 +20,6 @@ Selected allowlist (all actions currently used across Quality Gate, Release Beta
| `docker/setup-buildx-action@v3` | release, promote-release | Docker Buildx setup |
| `docker/login-action@v3` | release, promote-release | GHCR authentication |
| `docker/build-push-action@v6` | release, promote-release | Multi-platform Docker image build and push |
| `actions/labeler@v5` | pr-path-labeler | Apply path/scope labels from `labeler.yml` |
Equivalent allowlist patterns:
@ -37,7 +36,6 @@ Equivalent allowlist patterns:
| Quality Gate | `.github/workflows/checks-on-pr.yml` | Pull requests to `master` |
| Release Beta | `.github/workflows/release-beta-on-push.yml` | Push to `master` |
| Release Stable | `.github/workflows/release-stable-manual.yml` | Manual `workflow_dispatch` |
| PR Path Labeler | `.github/workflows/pr-path-labeler.yml` | `pull_request_target` (opened, synchronize, reopened) |
## Change Control
@ -64,7 +62,6 @@ gh api repos/zeroclaw-labs/zeroclaw/actions/permissions/selected-actions
## Change Log
- 2026-03-23: Added PR Path Labeler (`pr-path-labeler.yml`) using `actions/labeler@v5`. No allowlist change needed — covered by existing `actions/*` pattern.
- 2026-03-10: Renamed workflows — CI → Quality Gate (`checks-on-pr.yml`), Beta Release → Release Beta (`release-beta-on-push.yml`), Promote Release → Release Stable (`release-stable-manual.yml`). Added `lint` and `security` jobs to Quality Gate. Added Cross-Platform Build (`cross-platform-build-manual.yml`).
- 2026-03-05: Complete workflow overhaul — replaced 22 workflows with 3 (CI, Beta Release, Promote Release)
- Removed patterns no longer in use: `DavidAnson/markdownlint-cli2-action@*`, `lycheeverse/lychee-action@*`, `EmbarkStudios/cargo-deny-action@*`, `rustsec/audit-check@*`, `rhysd/actionlint@*`, `sigstore/cosign-installer@*`, `Checkmarx/vorpal-reviewdog-github-action@*`, `useblacksmith/*`

View File

@ -45,15 +45,6 @@ For complete code examples of each extension trait, see [extension-examples.md](
- Keep multilingual entry-point parity for all supported locales (`en`, `zh-CN`, `ja`, `ru`, `fr`, `vi`) when nav or key wording changes.
- When shared docs wording changes, sync corresponding localized docs in the same PR (or explicitly document deferral and follow-up PR).
## Tool Shared State
- Follow the `Arc<RwLock<T>>` handle pattern for any tool that owns long-lived shared state.
- Accept handles at construction; do not create global/static mutable state.
- Use `ClientId` (provided by the daemon) to namespace per-client state — never construct identity keys inside the tool.
- Isolate security-sensitive state (credentials, quotas) per client; broadcast/display state may be shared with optional namespace prefixing.
- Cached validation is invalidated on config change — tools must re-validate before the next execution when signaled.
- See [ADR-004: Tool Shared State Ownership](../architecture/adr-004-tool-shared-state-ownership.md) for the full contract.
## Architecture Boundary Rules
- Extend capabilities by adding trait implementations + factory wiring first; avoid cross-module rewrites for isolated features.

View File

@ -1,213 +0,0 @@
# Label Registry
Single reference for every label used on PRs and issues. Labels are grouped by category. Each entry lists the label name, definition, and how it is applied.
Sources consolidated here:
- `.github/labeler.yml` (path-label config for `actions/labeler`)
- `.github/label-policy.json` (contributor tier thresholds)
- `docs/contributing/pr-workflow.md` (size, risk, and triage label definitions)
- `docs/contributing/ci-map.md` (automation behavior and high-risk path heuristics)
Note: The CI was simplified to 4 workflows (`ci.yml`, `release.yml`, `ci-full.yml`, `promote-release.yml`). Workflows that previously automated size, risk, contributor tier, and triage labels (`pr-labeler.yml`, `pr-auto-response.yml`, `pr-check-stale.yml`, and supporting scripts) were removed. Only path labels via `pr-path-labeler.yml` are currently automated.
---
## Path labels
Applied automatically by `pr-path-labeler.yml` using `actions/labeler`. Matches changed files against glob patterns in `.github/labeler.yml`.
### Base scope labels
| Label | Matches |
|---|---|
| `docs` | `docs/**`, `**/*.md`, `**/*.mdx`, `LICENSE`, `.markdownlint-cli2.yaml` |
| `dependencies` | `Cargo.toml`, `Cargo.lock`, `deny.toml`, `.github/dependabot.yml` |
| `ci` | `.github/**`, `.githooks/**` |
| `core` | `src/*.rs` |
| `agent` | `src/agent/**` |
| `channel` | `src/channels/**` |
| `gateway` | `src/gateway/**` |
| `config` | `src/config/**` |
| `cron` | `src/cron/**` |
| `daemon` | `src/daemon/**` |
| `doctor` | `src/doctor/**` |
| `health` | `src/health/**` |
| `heartbeat` | `src/heartbeat/**` |
| `integration` | `src/integrations/**` |
| `memory` | `src/memory/**` |
| `security` | `src/security/**` |
| `runtime` | `src/runtime/**` |
| `onboard` | `src/onboard/**` |
| `provider` | `src/providers/**` |
| `service` | `src/service/**` |
| `skillforge` | `src/skillforge/**` |
| `skills` | `src/skills/**` |
| `tool` | `src/tools/**` |
| `tunnel` | `src/tunnel/**` |
| `observability` | `src/observability/**` |
| `tests` | `tests/**` |
| `scripts` | `scripts/**` |
| `dev` | `dev/**` |
### Per-component channel labels
Each channel gets a specific label in addition to the base `channel` label.
| Label | Matches |
|---|---|
| `channel:bluesky` | `bluesky.rs` |
| `channel:clawdtalk` | `clawdtalk.rs` |
| `channel:cli` | `cli.rs` |
| `channel:dingtalk` | `dingtalk.rs` |
| `channel:discord` | `discord.rs`, `discord_history.rs` |
| `channel:email` | `email_channel.rs`, `gmail_push.rs` |
| `channel:imessage` | `imessage.rs` |
| `channel:irc` | `irc.rs` |
| `channel:lark` | `lark.rs` |
| `channel:linq` | `linq.rs` |
| `channel:matrix` | `matrix.rs` |
| `channel:mattermost` | `mattermost.rs` |
| `channel:mochat` | `mochat.rs` |
| `channel:mqtt` | `mqtt.rs` |
| `channel:nextcloud-talk` | `nextcloud_talk.rs` |
| `channel:nostr` | `nostr.rs` |
| `channel:notion` | `notion.rs` |
| `channel:qq` | `qq.rs` |
| `channel:reddit` | `reddit.rs` |
| `channel:signal` | `signal.rs` |
| `channel:slack` | `slack.rs` |
| `channel:telegram` | `telegram.rs` |
| `channel:twitter` | `twitter.rs` |
| `channel:wati` | `wati.rs` |
| `channel:webhook` | `webhook.rs` |
| `channel:wecom` | `wecom.rs` |
| `channel:whatsapp` | `whatsapp.rs`, `whatsapp_storage.rs`, `whatsapp_web.rs` |
### Per-component provider labels
| Label | Matches |
|---|---|
| `provider:anthropic` | `anthropic.rs` |
| `provider:azure-openai` | `azure_openai.rs` |
| `provider:bedrock` | `bedrock.rs` |
| `provider:claude-code` | `claude_code.rs` |
| `provider:compatible` | `compatible.rs` |
| `provider:copilot` | `copilot.rs` |
| `provider:gemini` | `gemini.rs`, `gemini_cli.rs` |
| `provider:glm` | `glm.rs` |
| `provider:kilocli` | `kilocli.rs` |
| `provider:ollama` | `ollama.rs` |
| `provider:openai` | `openai.rs`, `openai_codex.rs` |
| `provider:openrouter` | `openrouter.rs` |
| `provider:telnyx` | `telnyx.rs` |
### Per-group tool labels
Tools are grouped by logical function rather than one label per file.
| Label | Matches |
|---|---|
| `tool:browser` | `browser.rs`, `browser_delegate.rs`, `browser_open.rs`, `text_browser.rs`, `screenshot.rs` |
| `tool:cloud` | `cloud_ops.rs`, `cloud_patterns.rs` |
| `tool:composio` | `composio.rs` |
| `tool:cron` | `cron_add.rs`, `cron_list.rs`, `cron_remove.rs`, `cron_run.rs`, `cron_runs.rs`, `cron_update.rs` |
| `tool:file` | `file_edit.rs`, `file_read.rs`, `file_write.rs`, `glob_search.rs`, `content_search.rs` |
| `tool:google-workspace` | `google_workspace.rs` |
| `tool:mcp` | `mcp_client.rs`, `mcp_deferred.rs`, `mcp_protocol.rs`, `mcp_tool.rs`, `mcp_transport.rs` |
| `tool:memory` | `memory_forget.rs`, `memory_recall.rs`, `memory_store.rs` |
| `tool:microsoft365` | `microsoft365/**` |
| `tool:security` | `security_ops.rs`, `verifiable_intent.rs` |
| `tool:shell` | `shell.rs`, `node_tool.rs`, `cli_discovery.rs` |
| `tool:sop` | `sop_advance.rs`, `sop_approve.rs`, `sop_execute.rs`, `sop_list.rs`, `sop_status.rs` |
| `tool:web` | `web_fetch.rs`, `web_search_tool.rs`, `web_search_provider_routing.rs`, `http_request.rs` |
---
## Size labels
Defined in `pr-workflow.md` §6.1. Based on effective changed line count, normalized for docs-only and lockfile-heavy PRs.
| Label | Threshold |
|---|---|
| `size: XS` | <= 80 lines |
| `size: S` | <= 250 lines |
| `size: M` | <= 500 lines |
| `size: L` | <= 1000 lines |
| `size: XL` | > 1000 lines |
**Applied by:** manual. The workflows that previously computed size labels (`pr-labeler.yml` and supporting scripts) were removed during CI simplification.
---
## Risk labels
Defined in `pr-workflow.md` §13.2 and `ci-map.md`. Based on a heuristic combining touched paths and change size.
| Label | Meaning |
|---|---|
| `risk: low` | No high-risk paths touched, small change |
| `risk: medium` | Behavioral `src/**` changes without boundary/security impact |
| `risk: high` | Touches high-risk paths (see below) or large security-adjacent change |
| `risk: manual` | Maintainer override that freezes automated risk recalculation |
High-risk paths: `src/security/**`, `src/runtime/**`, `src/gateway/**`, `src/tools/**`, `.github/workflows/**`.
The boundary between low and medium is not formally defined beyond "no high-risk paths."
**Applied by:** manual. Previously automated via `pr-labeler.yml`; removed during CI simplification.
---
## Contributor tier labels
Defined in `.github/label-policy.json`. Based on the author's merged PR count queried from the GitHub API.
| Label | Minimum merged PRs |
|---|---|
| `trusted contributor` | 5 |
| `experienced contributor` | 10 |
| `principal contributor` | 20 |
| `distinguished contributor` | 50 |
**Applied by:** manual. Previously automated via `pr-labeler.yml` and `pr-auto-response.yml`; removed during CI simplification.
---
## Response and triage labels
Defined in `pr-workflow.md` §8. Applied manually.
| Label | Purpose | Applied by |
|---|---|---|
| `r:needs-repro` | Incomplete bug report; request deterministic repro | Manual |
| `r:support` | Usage/help item better handled outside bug backlog | Manual |
| `invalid` | Not a valid bug/feature request | Manual |
| `duplicate` | Duplicate of existing issue | Manual |
| `stale-candidate` | Dormant PR/issue; candidate for closing | Manual |
| `superseded` | Replaced by a newer PR | Manual |
| `no-stale` | Exempt from stale automation; accepted but blocked work | Manual |
**Automation:** none currently. The workflows that handled label-driven issue closing (`pr-auto-response.yml`) and stale detection (`pr-check-stale.yml`) were removed during CI simplification.
---
## Implementation status
| Category | Count | Automated | Workflow |
|---|---|---|---|
| Path (base scope) | 27 | Yes | `pr-path-labeler.yml` |
| Path (per-component) | 52 | Yes | `pr-path-labeler.yml` |
| Size | 5 | No | Manual |
| Risk | 4 | No | Manual |
| Contributor tier | 4 | No | Manual |
| Response/triage | 7 | No | Manual |
| **Total** | **99** | | |
---
## Maintenance
- **Owner:** maintainers responsible for label policy and PR triage automation.
- **Update trigger:** new channels, providers, or tools added to the source tree; label policy changes; triage workflow changes.
- **Source of truth:** this document consolidates definitions from the four source files listed at the top. When definitions conflict, update the source file first, then sync this registry.

View File

@ -4,22 +4,8 @@ Localized documentation trees live here and under `docs/`.
## Locales
- العربية (Arabic): [ar/README.md](ar/README.md)
- বাংলা (Bengali): [bn/README.md](bn/README.md)
- Deutsch (German): [de/README.md](de/README.md)
- Ελληνικά (Greek): [el/README.md](el/README.md)
- Español (Spanish): [es/README.md](es/README.md)
- Français (French): [fr/README.md](fr/README.md)
- हिन्दी (Hindi): [hi/README.md](hi/README.md)
- Italiano (Italian): [it/README.md](it/README.md)
- 日本語 (Japanese): [ja/README.md](ja/README.md)
- 한국어 (Korean): [ko/README.md](ko/README.md)
- Português (Portuguese): [pt/README.md](pt/README.md)
- Русский (Russian): [ru/README.md](ru/README.md)
- Tagalog: [tl/README.md](tl/README.md)
- Tiếng Việt (Vietnamese): [vi/README.md](vi/README.md)
- Vietnamese (canonical): [`docs/vi/`](../vi/)
- 简体中文 (Chinese): [zh-CN/README.md](zh-CN/README.md)
- Chinese (Simplified): [`docs/i18n/zh-CN/`](zh-CN/)
## Structure

View File

@ -1,35 +0,0 @@
# ZeroClaw Documentation Hub (Arabic)
This locale hub is enabled for Arabic community support.
Last synchronized: **March 6, 2026**.
## Quick Links
- Arabic docs hub: [README.md](README.md)
- Arabic summary: [SUMMARY.md](SUMMARY.md)
- English docs hub: [../../README.md](../../README.md)
- English summary: [../../SUMMARY.md](../../SUMMARY.md)
## Coverage Status
Current status: **hub-level support enabled**. Full document translation is in progress.
## Other Languages
- English: [../../../README.md](../../../README.md)
- 简体中文: [../zh-CN/README.md](../zh-CN/README.md)
- 日本語: [../ja/README.md](../ja/README.md)
- 한국어: [../ko/README.md](../ko/README.md)
- Tiếng Việt: [../vi/README.md](../vi/README.md)
- Tagalog: [../tl/README.md](../tl/README.md)
- Español: [../es/README.md](../es/README.md)
- Português: [../pt/README.md](../pt/README.md)
- Italiano: [../it/README.md](../it/README.md)
- Deutsch: [../de/README.md](../de/README.md)
- Français: [../fr/README.md](../fr/README.md)
- العربية: [README.md](README.md)
- हिन्दी: [../hi/README.md](../hi/README.md)
- Русский: [../ru/README.md](../ru/README.md)
- বাংলা: [../bn/README.md](../bn/README.md)
- Ελληνικά: [../el/README.md](../el/README.md)

View File

@ -1,20 +0,0 @@
# ZeroClaw Docs Summary (Arabic)
This is the Arabic locale summary entry point.
Last synchronized: **March 6, 2026**.
## Entry Points
- Arabic docs hub: [README.md](README.md)
- English docs hub: [../../README.md](../../README.md)
- English unified summary: [../../SUMMARY.md](../../SUMMARY.md)
## Operator References (English Source)
- [../../commands-reference.md](../../commands-reference.md)
- [../../config-reference.md](../../config-reference.md)
- [../../providers-reference.md](../../providers-reference.md)
- [../../channels-reference.md](../../channels-reference.md)
- [../../operations-runbook.md](../../operations-runbook.md)
- [../../troubleshooting.md](../../troubleshooting.md)

View File

@ -1,35 +0,0 @@
# ZeroClaw Documentation Hub (Bengali)
This locale hub is enabled for Bengali community support.
Last synchronized: **March 6, 2026**.
## Quick Links
- Bengali docs hub: [README.md](README.md)
- Bengali summary: [SUMMARY.md](SUMMARY.md)
- English docs hub: [../../README.md](../../README.md)
- English summary: [../../SUMMARY.md](../../SUMMARY.md)
## Coverage Status
Current status: **hub-level support enabled**. Full document translation is in progress.
## Other Languages
- English: [../../../README.md](../../../README.md)
- 简体中文: [../zh-CN/README.md](../zh-CN/README.md)
- 日本語: [../ja/README.md](../ja/README.md)
- 한국어: [../ko/README.md](../ko/README.md)
- Tiếng Việt: [../vi/README.md](../vi/README.md)
- Tagalog: [../tl/README.md](../tl/README.md)
- Español: [../es/README.md](../es/README.md)
- Português: [../pt/README.md](../pt/README.md)
- Italiano: [../it/README.md](../it/README.md)
- Deutsch: [../de/README.md](../de/README.md)
- Français: [../fr/README.md](../fr/README.md)
- العربية: [../ar/README.md](../ar/README.md)
- हिन्दी: [../hi/README.md](../hi/README.md)
- Русский: [../ru/README.md](../ru/README.md)
- বাংলা: [README.md](README.md)
- Ελληνικά: [../el/README.md](../el/README.md)

View File

@ -1,20 +0,0 @@
# ZeroClaw Docs Summary (Bengali)
This is the Bengali locale summary entry point.
Last synchronized: **March 6, 2026**.
## Entry Points
- Bengali docs hub: [README.md](README.md)
- English docs hub: [../../README.md](../../README.md)
- English unified summary: [../../SUMMARY.md](../../SUMMARY.md)
## Operator References (English Source)
- [../../commands-reference.md](../../commands-reference.md)
- [../../config-reference.md](../../config-reference.md)
- [../../providers-reference.md](../../providers-reference.md)
- [../../channels-reference.md](../../channels-reference.md)
- [../../operations-runbook.md](../../operations-runbook.md)
- [../../troubleshooting.md](../../troubleshooting.md)

View File

@ -1,35 +0,0 @@
# ZeroClaw Documentation Hub (German)
This locale hub is enabled for German community support.
Last synchronized: **March 6, 2026**.
## Quick Links
- German docs hub: [README.md](README.md)
- German summary: [SUMMARY.md](SUMMARY.md)
- English docs hub: [../../README.md](../../README.md)
- English summary: [../../SUMMARY.md](../../SUMMARY.md)
## Coverage Status
Current status: **hub-level support enabled**. Full document translation is in progress.
## Other Languages
- English: [../../../README.md](../../../README.md)
- 简体中文: [../zh-CN/README.md](../zh-CN/README.md)
- 日本語: [../ja/README.md](../ja/README.md)
- 한국어: [../ko/README.md](../ko/README.md)
- Tiếng Việt: [../vi/README.md](../vi/README.md)
- Tagalog: [../tl/README.md](../tl/README.md)
- Español: [../es/README.md](../es/README.md)
- Português: [../pt/README.md](../pt/README.md)
- Italiano: [../it/README.md](../it/README.md)
- Deutsch: [README.md](README.md)
- Français: [../fr/README.md](../fr/README.md)
- العربية: [../ar/README.md](../ar/README.md)
- हिन्दी: [../hi/README.md](../hi/README.md)
- Русский: [../ru/README.md](../ru/README.md)
- বাংলা: [../bn/README.md](../bn/README.md)
- Ελληνικά: [../el/README.md](../el/README.md)

View File

@ -1,20 +0,0 @@
# ZeroClaw Docs Summary (German)
This is the German locale summary entry point.
Last synchronized: **March 6, 2026**.
## Entry Points
- German docs hub: [README.md](README.md)
- English docs hub: [../../README.md](../../README.md)
- English unified summary: [../../SUMMARY.md](../../SUMMARY.md)
## Operator References (English Source)
- [../../commands-reference.md](../../commands-reference.md)
- [../../config-reference.md](../../config-reference.md)
- [../../providers-reference.md](../../providers-reference.md)
- [../../channels-reference.md](../../channels-reference.md)
- [../../operations-runbook.md](../../operations-runbook.md)
- [../../troubleshooting.md](../../troubleshooting.md)

View File

@ -1,35 +0,0 @@
# ZeroClaw Documentation Hub (Hindi)
This locale hub is enabled for Hindi community support.
Last synchronized: **March 6, 2026**.
## Quick Links
- Hindi docs hub: [README.md](README.md)
- Hindi summary: [SUMMARY.md](SUMMARY.md)
- English docs hub: [../../README.md](../../README.md)
- English summary: [../../SUMMARY.md](../../SUMMARY.md)
## Coverage Status
Current status: **hub-level support enabled**. Full document translation is in progress.
## Other Languages
- English: [../../../README.md](../../../README.md)
- 简体中文: [../zh-CN/README.md](../zh-CN/README.md)
- 日本語: [../ja/README.md](../ja/README.md)
- 한국어: [../ko/README.md](../ko/README.md)
- Tiếng Việt: [../vi/README.md](../vi/README.md)
- Tagalog: [../tl/README.md](../tl/README.md)
- Español: [../es/README.md](../es/README.md)
- Português: [../pt/README.md](../pt/README.md)
- Italiano: [../it/README.md](../it/README.md)
- Deutsch: [../de/README.md](../de/README.md)
- Français: [../fr/README.md](../fr/README.md)
- العربية: [../ar/README.md](../ar/README.md)
- हिन्दी: [README.md](README.md)
- Русский: [../ru/README.md](../ru/README.md)
- বাংলা: [../bn/README.md](../bn/README.md)
- Ελληνικά: [../el/README.md](../el/README.md)

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