* wip(desktop): GPU-node connect (gpu.rs/useGpuConnect/hanzo-auth) + luxwallet start + brand assets * feat(desktop): native omnichain post-quantum Lux Wallet (node-independent) Mirror of the live fix in hanzoai/gui pkgs/ai (@hanzo/ai) applied to this repo's pre-convergence frontend tree. Replaces the hanzo-node-backed crypto wallet — which couldn't create/show a wallet without a connected node — with a self-contained stack under apps/hanzo-desktop/src/lib/lux-wallet: - luxfi/crypto WASM (real FIPS-204 ML-DSA-65 + secp256k1 + keccak); EVM keys via BIP-44 keys.deriveSecp256k1 (bit-identical to ethers/MetaMask), PQ identity via keys.serviceIdentity. Secrets sealed in OS keychain, never plaintext. - create / import / list / reveal / balance / send across the 11 ready EVM chains (@luxwallet/chains + /rpc); non-EVM X/P/Q/Z marked "coming soon". - Sign-In-With-Wallet: /v1/iam/web3/nonce -> CAIP-122 -> EIP-191 sign -> /v1/iam/web3/verify (@luxwallet/connect + @luxfi/crypto). - local-HD-PQ default; MPC / Safe selectable (coming soon). Wiring: rewrite pages/crypto-wallet.tsx onto the store; node-independent /wallet route + "Sign in with Wallet" on quick-connection; drop dead wallets-context. MIT/BSD deps vendored under apps/hanzo-desktop/vendor. NOTE: this app now renders @hanzo/ai (main.tsx), so the shipping wallet fix lands via hanzoai/gui; this mirror keeps the repo's own tree consistent. * feat(desktop): the ONE network/wallet standard — shared NetworkSwitcher + WalletMenu Aligns the desktop onto the shared hanzo.network model (@hanzo/ui/network + @hanzo/ui/wallet from @hanzo/[email protected] — same standard as the hanzo CLI and console): - lib/network.ts: ONE place composing the brand network list (hanzo → canonical mainnet/testnet/devnet/local envs; zoo/lux → brand mainnet) into the shared selected-network store. - Sidebar footer mounts <NetworkSwitcher/> + <WalletMenu/> (menuSide=top); wallet auto-provisions the PQ HD account via the lux-wallet adapter (keychain-sealed secrets; backup stays on the crypto-wallet page). - Selected network drives endpoints: lux-wallet brandRpcConfig gateway + rpc override, defaultChainId, and useChainBalance now follow the selection (switch env → every chain/cloud call repoints). - styles.css: semantic token aliases + @source for the shared components. - tsconfig: moduleResolution bundler (exports-aware; tsc clean). - package.json: declare @hanzo/ai (was undeclared — npm install pruned it and broke main.tsx) + @hanzo/ui alias. tsc 0 errors; vite build green; vitest 81/81. * docs(LLM.md): the network/wallet standard — seams + gotchas * chore(desktop): bump @hanzo/ui-shadcn 5.7.3 -> 5.7.4 (genesis-canonical chain IDs) Picks up the corrected network set (testnet 36962, devnet 36964, local 1337 @ :9630/v1/bc/C/rpc). tsc 0; vite build green. --------- Co-authored-by: hanzo-dev <[email protected]>
6.4 KiB
Hanzo Desktop
Project
Desktop AI agent app. React + Vite + Tauri (Rust backend).
Structure
apps/hanzo-desktop/
src/ # React frontend
src-tauri/ # Rust Tauri backend
public/ # Static assets
libs/
hanzo-ui/ # Shared UI components
hanzo-i18n/ # Internationalization
hanzo-message-ts/ # Message/job API types
Commands
npx nx serve hanzo-desktop # Dev (Tauri, uses tauri.conf.local.json)
npx nx build hanzo-desktop # Production build
npx nx test hanzo-desktop # Vitest
npx nx lint hanzo-desktop # ESLint
npx nx run hanzo-desktop:typecheck
npx nx run hanzo-desktop:cargo-check
Alternative: cd apps/hanzo-desktop && npm run dev|build|lint
Code Style
- 2 spaces, Prettier + Tailwind plugin, single quotes
- Files/dirs: kebab-case. Components/types: PascalCase. Vars/functions: camelCase
- Tests: Vitest + @testing-library/react, co-located in
__tests__/,*.test.ts(x) - Commits: Conventional (
feat:,fix:,chore:,docs:)
Tooling
- Node 20+, npm 10+, Rust toolchain for Tauri
postinstallrunspatch-package- Env: copy
.env.example, never commit secrets
Release Pipeline
Workflows
- Production:
.github/workflows/release-prod.ymlon tags[0-9]+.[0-9]+.[0-9]+ - Development:
.github/workflows/release-dev.ymlon tagsdev-v[0-9]+.[0-9]+.[0-9]+
Required Secrets
Apple (macOS signing): APPLE_CERTIFICATE, APPLE_CERTIFICATE_PASSWORD, APPLE_SIGNING_IDENTITY, APPLE_ID, APPLE_PASSWORD, APPLE_TEAM_ID, KEYCHAIN_PASSWORD
Tauri updates: TAURI_PRIVATE_KEY, TAURI_KEY_PASSWORD
Windows EV (Google Cloud KMS): EV_CODE_SIGNING_CERTIFICATE
Infrastructure: R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, SLACK_BOT_TOKEN
App: VITE_POSTHOG_API_KEY, SECRET_DESKTOP_INSTALLATION_PROOF_KEY
Build Artifacts
- Installers: .AppImage (Linux), .dmg (macOS), .exe (Windows)
- Update bundles: .tar.gz (macOS/Linux), .nsis.zip (Windows)
- Signature files: .sig for Tauri auto-updater
- Uploaded to: GitHub Releases + Cloudflare R2 (download.hanzo.ai)
- Rollout: rename
updates-next.jsontoupdates.json
Troubleshooting
- APPLE_CERTIFICATE must be base64 without newlines
- Use
base64 --decode > filenotbase64 --decode -o file - Ensure package.json version matches git tag
- Update check failures are handled gracefully (no user-facing errors)
Model Tools (hanzo-ml integration)
The Node Manager window has a Model Tools tab (components/hanzo-node-manager/model-tools.tsx)
that drives the hanzoai/ml features via the Tauri backend (src-tauri/src/model_tools):
- Model soups + BitDelta — fully wired. Shells out to the
hanzo-mlsoupCLI (hanzo_ml::model_delta):average(uniform/weighted soup),delta(base + mean fine-tune delta),bitdelta-encode/bitdelta-apply(1-bit delta compress/restore). Binary resolved viaHANZO_SOUP_BIN, a bundledsoup-<arch>next to the app, orsoupon PATH. The UI gates on availability. - Frontend:
lib/model-tools/model-tools-client.ts(invoke wrappers + React Query hooks). Tauri commands:model_tools_soup_*,model_tools_bitdelta_*.
Machines (Docker Desktop replacement)
Desktop UI for Linux VMs (vfkit) and the docker / k3s stack served by the
hanzod daemon in hanzoai/node/machine/. Hanzo Desktop is a drop-in
all-in-one Docker Desktop replacement: containers, Kubernetes, and Linux
machines from one app, one binary backend.
apps/hanzo-desktop/
src-tauri/src/machine/ # Tauri commands -> unix socket client
socket.rs # ~/.hanzo/run/machined.sock resolver
types.rs # mirrors machine/proto.go (Machine, ExecFrame, ...)
src/pages/machines/ # React UI (list, create dialog, exec stream)
- Tauri commands:
machine_health,machine_list,machine_create,machine_start,machine_stop,machine_delete,machine_exec(streaming). - Wire format is JSON over the daemon's UNIX socket - see
hanzoai/node/machine/proto.gofor the authoritative contract. - Brand gating: the Machines / Containers / K8s pages are Hanzo-only by
default. Other brands (zoo, liquidity) must set
VITE_ENABLE_MACHINES=true(or the equivalent runtime flag inlibs/brand-config) to reveal them. Seelibs/brand-config/src/index.ts::isMachinesEnabled.
e2e
e2e-tests/machine-flow.spec.ts runs against pnpm dev, mocks
window.__TAURI_INTERNALS__.invoke for the machine_* commands, and asserts
the create dialog round-trip. CI must pass VITE_BRAND=hanzo so the
Machines route renders.
GRPO Status
Trainer-free GRPO lives in hanzo_training::grpo (a Rust library + a runnable
grpo_toy example) — there is no GRPO server/daemon yet. The desktop exposes a
developer-preview entry (model_tools_grpo_run, surfaced in the Model Tools
tab) that runs cargo run -p hanzo-training --example grpo_toy from a local
checkout (HANZO_ML_DIR). This is plumbing/demo only.
Productizing GRPO in-app still needs: experience/trajectory storage, agent
versioning / A/B testing, a real training job pipeline (driving the Policy
trait on a packaged model), feedback→reward mapping, and ML metrics. Foundation
exists (agent CRUD, message history with tool metadata, Zustand, React Query).
Network + Wallet (the ONE standard)
Shared components from @hanzo/ui/network + @hanzo/ui/wallet
(npm alias @hanzo/ui -> @hanzo/ui-shadcn@^5.7.3, the 5.x line —
same standard as the hanzo CLI network.rs and the console):
- Model: Network = (env, label, networkID, evmChainID, rpcEndpoint, apiEndpoint). Sovereign L1 => networkID === evmChainID. Hanzo envs: mainnet 36963 / testnet 36964 / devnet 36965 / local 31337; public envs share api.hanzo.ai; RPC per env (rpc.hanzo[-test|-dev].network).
src/lib/network.tsis the ONE composition point (brand -> network list -> shared store). Endpoint consumers:lux-wallet/chains.ts(brandRpcConfig/defaultChainId) +hooks/useChainBalance.tsread the SELECTED network viagetNetwork()/useNetwork().- Wallet:
lux-wallet/ui-adapter.tsadapts the PQ HD keychain wallet to the shared<WalletMenu/>(auto-provisions on first connect; secrets never leave the store/keychain). - Mounted in the sidebar footer of
pages/layout/main-layout.tsx(menuSide="top"). Semantic token aliases live inlibs/hanzo-ui/src/styles/styles.css. @hanzo/aiis a REAL dependency of src/main.tsx — keep it declared in package.json (it was once undeclared and npm install pruned it).