Agent SkillsLanternOps/breeze › breeze-helper

breeze-helper

GitHub

Breeze Helper Tauri 桌面应用参考文档,涵盖架构、Rust后端命令、React前端、IPC通信及配置管理。用于开发、调试助手功能或理解其与API和Agent的交互机制。

.claude/skills/breeze-helper/SKILL.md LanternOps/breeze

触发场景

调试Breeze Helper相关代码问题 添加Breeze Helper新功能 了解Helper与API/Agent的通信逻辑

安装

npx skills add LanternOps/breeze --skill breeze-helper -g -y
更多选项

非标准路径

npx skills add https://github.com/LanternOps/breeze/tree/main/.claude/skills/breeze-helper -g -y

不安装直接使用

npx skills use LanternOps/breeze@breeze-helper

指定 Agent (Claude Code)

npx skills add LanternOps/breeze --skill breeze-helper -a claude-code -g -y

安装 repo 全部 skill

npx skills add LanternOps/breeze --all -g -y

预览 repo 内 skill

npx skills add LanternOps/breeze --list

SKILL.md

Frontmatter
{
    "name": "breeze-helper",
    "description": "Quick reference for the Breeze Helper Tauri desktop app — architecture, Rust backend commands, React frontend, config files, IPC with the Go agent, helper chat API routes, tool approval flow, and tray integration. Use when working on helper code, debugging helper issues, adding helper features, or understanding how the Helper communicates with the API and agent."
}

Breeze Helper Reference

Lightweight Tauri v2 desktop app providing an AI chat assistant, device info, and tool approval interface. Runs in the system tray, spawned by the Go agent on Windows as a SYSTEM process in the user's session.

Architecture Overview

apps/helper/
  src/
    App.tsx                    # Main UI (chat, device info, history, approval popup)
    main.tsx                   # React entry point
    stores/chatStore.ts        # Zustand state (auth, messages, SSE streaming, approvals)
    styles.css                 # Dark-theme styling
  src-tauri/
    src/lib.rs                 # Rust backend (~776 lines): config, HTTP client, tray, streaming
    tauri.conf.json            # App config (380×600 frameless, tray icon, CSP)
    Cargo.toml                 # Rust deps (tauri v2, reqwest, tokio, serde_yaml)
    build.rs                   # Tauri build script
  vite.config.ts               # Frontend build
  package.json                 # React + Zustand + react-markdown

Tauri Commands (Rust → Frontend)

Registered in lib.rs via generate_handler![]:

Command Returns Purpose
read_agent_config AgentConfig Load agent.yaml + secrets.yaml, init HTTP client
helper_fetch HelperFetchResponse Authenticated HTTP proxy with mTLS + SSRF protection
hide_window Hide window to tray
minimize_window Minimize window
get_os_username String OS username (falls back to USERNAME env for SYSTEM context)
get_helper_config HelperConfig Load helper_config.yaml (tray menu toggles)
update_chat_active Write helper_status.yaml (agent reads for idle detection)

helper_fetch — Key Design

The central HTTP proxy command. All frontend API calls go through this.

  • SSRF protection: Validates request URL starts with configured api_url
  • Auth injection: Always sets Authorization: Bearer <token>, prevents frontend override
  • mTLS: Builds reqwest::Client with Identity::from_pem if cert+key present in secrets.yaml
  • Streaming: When stream: true, spawns tokio task that emits helper-fetch-stream Tauri events as StreamChunkEvent { stream_id, chunk, done, error }
  • Non-stream: Returns full body inline in HelperFetchResponse

Config Files

All in the agent config directory (same as agent.yaml):

File Writer Reader Purpose
agent.yaml Go agent Helper server_url, agent_id
secrets.yaml Go agent Helper auth_token, mtls_cert_pem, mtls_key_pem (0640)
helper_config.yaml Go agent Helper Tray menu toggles, portal URL, device name/status
helper_status.yaml Helper Go agent version, chat_active, last_activity, pid

Config Paths

Platform Path
macOS /Library/Application Support/Breeze/
Windows %ProgramData%\Breeze\
Linux /etc/breeze/

HelperConfig Fields

show_tray_icon: true         # Draw the tray icon at all (#3202). Independent of
                             # the three menu-item flags below: with this false
                             # the helper still serves chat, remote-access
                             # consent and PAM dialogs, it just has no tray.
                             # Missing key => TRUE everywhere in the chain.
show_open_portal: true       # Show "Open Breeze Portal" in tray menu
show_device_info: true       # Show "Device Info" in tray menu
show_request_support: true   # Show "Request Support" in tray menu
portal_url: ""               # URL for portal (falls back to api_url)
device_name: ""              # Display name
device_status: ""            # Current status
last_checkin: ""             # Last check-in timestamp

Config reloads every 60s; tray menu rebuilds on change.

Frontend (React + Zustand)

Views (in App.tsx)

  1. Connection states — connecting, error, disconnected (with retry)
  2. UsernamePrompt — one-time name entry (persists to localStorage, falls back to OS username)
  3. SessionHistory — list past conversations, load by ID
  4. DeviceInfoView — hostname, OS, status, agent version (from GET /devices/by-agent/:agentId)
  5. Chat — messages, markdown rendering, tool indicators, thinking dots, approval popup

Chat Store (chatStore.ts)

State: connectionState, agentConfig, sessionId, messages, isStreaming, pendingApproval, sessions, username

Key methods:

  • initialize() — loads agent config via Tauri invoke (or VITE_* env vars for dev)
  • sendMessage(content) — creates session if needed, POSTs via SSE stream
  • loadSessions() / loadSession(id) — session history
  • approveExecution(executionId, approved) — tool approval
  • clearMessages() — closes session, resets state

HTTP Layer (Tauri vs Dev)

Two helper functions abstract Tauri invoke vs native fetch:

  • helperRequest(config, url, options) — non-streaming requests
  • helperStreamRequest(config, url, options, onChunk, onDone) — SSE streaming

In Tauri: calls helper_fetch (Rust mTLS client). In browser dev: uses native fetch() with VITE_API_URL / VITE_AGENT_TOKEN / VITE_AGENT_ID.

Stream listener race fix: Event listener registered BEFORE helper_fetch invoke to avoid missing chunks when proxy buffers the full response.

SSE Event Processing

processSSELines() handles: message_start, content_delta, tool_use_start, tool_result, message_end, approval_required, error, done. Plan events (plan_approval_required, etc.) are received but not yet rendered.

Helper Chat API Routes

apps/api/src/routes/helper/index.ts — mounted at /api/v1/helper/*

Auth: Agent bearer token (brz_ prefix) via helperAuth middleware (SHA-256 hash lookup against devices.agentTokenHash). Creates synthetic AuthContext scoped to device's org.

Method Path Purpose
POST /chat/sessions Create session (optional helperUser, permissionLevel)
POST /chat/sessions/:id/messages Send message + SSE response stream
GET /chat/sessions List device sessions (filterable by ?helperUser=)
GET /chat/sessions/:id/messages Load message history
DELETE /chat/sessions/:id Close session
POST /chat/sessions/:id/approve/:executionId Approve/reject tool execution
GET /config Return helper config (permission level, screen capture)
POST /screenshots Upload screenshot (base64, 24h retention)

Pre-flight Checks (per message)

  1. Session exists and belongs to device
  2. Session not expired (24h max age)
  3. Turn limit not exceeded
  4. Rate limit: 30 msg/60s per device (Redis)
  5. Org budget check (fail-closed)
  6. Input sanitization

Permission Levels

Level Description
basic Read-only tools
standard Default — read + some write tools
extended All tools including destructive operations

Configured via helperToolFilter.tsgetHelperAllowedMcpToolNames(level).

Tool Approval Flow

  1. AI invokes a restricted tool → approval_required SSE event
  2. ToolApprovalPopup renders with description, device badge, parameters
  3. 5-minute auto-deny countdown timer
  4. User clicks Allow/Deny → POST /chat/sessions/:id/approve/:executionId
  5. Hidden input keys filtered from display: deviceId, orgId, siteId, sessionId

Agent IPC Integration

The Go agent spawns Helper in user sessions. Key IPC types from agent/internal/ipc/message.go:

Type Direction Purpose
auth_request/response Helper → Agent Authentication on connect
capabilities Helper → Agent Report features (notify, tray, capture, clipboard)
desktop_start/stop Agent → Helper WebRTC session lifecycle
desktop_input Agent → Helper Keyboard/mouse relay
clipboard_get/set/data Bidirectional Clipboard sync
sas_request/response Helper → Agent Ctrl+Alt+Del (Windows)
launch_process Agent → Helper Execute as logged-in user

Helper roles: system (SYSTEM token, desktop capture) or user (logged-in user, script execution).

Windows SYSTEM Context

  • Agent service (Session 0) spawns Helper via CreateProcessAsUser with SYSTEM token + session ID override
  • Helper detects SYSTEM context in lib.rs setup: checks LOCALAPPDATA for "systemprofile"
  • Redirects WebView2 data dir to %ProgramData%\Breeze\helper-webview\ to avoid access issues
  • get_os_username() falls back to USERNAME env var when whoami returns "SYSTEM"

Tray Menu

Built dynamically from HelperConfig flags:

Menu Item Action
Request Support Show chat window
Open Breeze Portal Open portal URL in browser
Device Info Emit show-device-info event, show device info view
Exit app.exit(0)

Left-click on tray icon → show chat window. Right-click → context menu.

Security

  • SSRF prevention: helper_fetch validates URL starts with configured API URL
  • Auth header protection: Authorization always set by Rust, frontend can't override
  • mTLS: Client certificate from secrets.yaml (optional, for Cloudflare mTLS)
  • Token hashing: Agent token validated via SHA-256 hash comparison
  • Device scoping: All session queries include deviceId filter
  • Input sanitization: sanitizeUserMessage() applied to all chat input
  • Rate limiting: 30 msg/min per device via Redis sliding window
  • Budget enforcement: Org budget checked before every message (fail-closed)

Build & Development

# Dev mode (Vite hot-reload + Tauri)
cd apps/helper && pnpm tauri dev

# Build distributable
cd apps/helper && pnpm tauri build

# Frontend-only dev (without Tauri, needs VITE_* env vars)
cd apps/helper && pnpm dev

Dev env vars (for browser-only development without Tauri):

VITE_API_URL=http://localhost:3001
VITE_AGENT_TOKEN=brz_<token>
VITE_AGENT_ID=<device-uuid>

Bundle Targets

Platform Format
macOS DMG (/Applications/Breeze Helper.app)
Windows MSI via WiX (C:\Program Files\Breeze Helper\breeze-helper.exe)
Linux AppImage (/usr/local/bin/breeze-helper)

Key Dependencies

Rust: tauri v2, reqwest (mTLS), tokio, serde/serde_yaml, chrono, whoami TypeScript: React 18.3, Zustand 4.5, react-markdown 10, @tauri-apps/api 2.0

Data Flow: Chat Message

1. User types in chat input (App.tsx)
2. chatStore.sendMessage(content)
   → Creates session via POST /helper/chat/sessions (if needed)
   → Adds optimistic user message
   → helperStreamRequest() to POST /helper/chat/sessions/:id/messages
3. In Tauri: helper_fetch (Rust) → mTLS HTTP request → SSE response
   → Rust spawns tokio task → emits helper-fetch-stream events
   → Frontend listener → processSSELines() → Zustand state updates
4. API: helperAuth → runHelperPreFlight → streamingSessionManager
   → Claude API call with org-scoped tools
   → SSE events: message_start → content_delta → tool_use_start → tool_result → done
5. Tool approval (if Tier 3): approval_required event → ToolApprovalPopup
   → User Allow/Deny → POST /approve/:executionId → tool executes or rejects

Logging

Helper logs to helper.log in the config directory (alongside agent.yaml). In SYSTEM service context, stderr isn't connected to anything visible, so log_helper_error() appends timestamped lines to this file.

Gotchas

  • WebView2 data dir: On Windows SYSTEM, must redirect to %ProgramData%\Breeze\helper-webview\ or WebView2 init fails
  • Stream listener race: Must register Tauri event listener BEFORE invoking helper_fetch — reverse proxies (Caddy) can buffer entire SSE response and deliver at once
  • Tray click events: Only match Left + Up — matching all click variants steals focus from context menu on Windows
  • 409 on concurrent messages: streamingSessionManager.tryTransitionToProcessing prevents parallel processing; frontend removes optimistic message on 409
  • Plan events: plan_approval_required, plan_step_start, etc. received but not rendered yet

版本历史

  • 10bb1af 当前 2026-08-20 08:50

同 Skill 集合

.claude/skills/agent-info/SKILL.md
.claude/skills/agent-log-debugging/SKILL.md
.claude/skills/ai-agent/SKILL.md
.claude/skills/breeze-testing/SKILL.md
.claude/skills/e2e-coverage/SKILL.md
.claude/skills/feature-testing/SKILL.md
.claude/skills/issue-to-pr/SKILL.md
.claude/skills/security-review/SKILL.md
.claude/skills/worktree-stack/SKILL.md
.claude/skills/gh-queue/SKILL.md
.claude/skills/ui-qa-sweep/SKILL.md

元信息

文件数
0
版本
0ee1815
Hash
1803838b
收录时间
2026-08-20 08:50

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-17 00:36
浙ICP备14020137号-1