Relax the proxy frame limiter to allow normal startup traffic while preserving abuse protection, and slow reconnect retries after policy-violation disconnects so remote gateways can recover cleanly.
Made-with: Cursor
Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
* fix: include kanbanImmersive in immersiveOverlayActive calculation
When Kanban board is open, HUD elements (camera preset buttons, edit toolbar, overlays) should be suppressed. The kanbanImmersive flag was defined but not included in the immersiveOverlayActive condition, causing HUD elements to remain visible.
This fix adds kanbanImmersive to the immersiveOverlayActive calculation so HUD elements are properly hidden when the Kanban board is open.
Co-authored-by: Luke The Dev <iamlukethedev@users.noreply.github.com>
* Fix: Hide mini status bar when Kanban immersive overlay is open
Wraps the bottom-left mini status bar (showing agent stats, vibe score, and
control hints) with !immersiveOverlayActive check to match the behavior of
other HUD elements like camera controls and toolbar.
This ensures the status bar is properly hidden when the Kanban board or any
other immersive overlay is active, maintaining a clean immersive experience.
Co-authored-by: Luke The Dev <iamlukethedev@users.noreply.github.com>
* chore: drop unrelated package-lock line from branch
Co-authored-by: Luke The Dev <iamlukethedev@users.noreply.github.com>
* universal-backend-plan
* backend-neutral runtime seam
* package.json update
* feat: add Hermes gateway adapter as alternative to OpenClaw
Adds a WebSocket adapter that lets Claw3D connect to a Hermes AI agent
runtime without any changes to the frontend. The adapter implements the
full Claw3D gateway protocol and bridges it to the Hermes HTTP API.
Changes:
- server/hermes-gateway-adapter.js: WebSocket bridge implementing the
Claw3D gateway protocol against the Hermes HTTP API. Supports all
core methods (agents, sessions, chat streaming, cron, config, files,
approvals) and multi-agent orchestration via spawn_agent/delegate_task
tools. Persists conversation history to ~/.hermes/clawd3d-history.json.
- scripts/clawd3d-start.sh: All-in-one startup script that launches
Hermes, the adapter, and the Next.js dev server with auto port
conflict resolution. Alias as `claw3d` for convenience.
- src/features/office/hooks/useCronAgents.ts: Hook that polls the
gateway for cron-scheduled agents and surfaces them in the 3D office.
- package.json: adds `hermes-adapter` npm script
- .env.example: documents Hermes config vars
- docs/hermes-gateway.md: setup guide and protocol reference
Usage:
npm run hermes-adapter # start adapter (connect to http://localhost:8642)
npm run dev # start Claw3D, point browser at localhost:3000
# or: bash scripts/clawd3d-start.sh (starts everything automatically)
Both OpenClaw and Hermes are supported simultaneously — the gateway URL
in NEXT_PUBLIC_GATEWAY_URL determines which backend Claw3D connects to.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add read_agent_context tool for cross-agent coordination
Agents can now read each other's conversation history via the
read_agent_context tool, enabling the orchestrator to check what
a sub-agent has done before re-delegating work.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: wire Hermes office UX and role-aware runtime updates
* feature update - demomode & hermes adapter
* fix lint blockers
* lintfix #2
* fix: stabilize retro office camera preset callbacks
* Initial plan
* fix: stabilize retro office overview preset hooks
Agent-Logs-Url: https://github.com/gsknnft/Claw3D/sessions/9cc71555-591e-44cf-aec4-25affbdcb405
Co-authored-by: gsknnft <123185582+gsknnft@users.noreply.github.com>
* feat: add truthful backend selection, Hermes adapter hardening, and demo gateway mode
* fix: address bugbot review and finalize backend selection
* fixed - onboarding and hermes calls
* office systems roadmap
* feat specs in docs
* specs ready
* feat: continue custom runtime seam and gateway alignment
* custom lane wired
* feat: add custom runtime provider path and office runtime alignment
* runtime fixes
* fix lukes findings
* fix lukes findings #2
* stable UI & connect screen page -> overlay
* better baseline for connection
* stable providers & ui rendering
* best launch yet
* nearly no gateway on reconnect
* auto reconnect last state
* fix: preserve selected runtime across reconnects
Keep backend selection aligned with the operator's chosen runtime instead of reviving a mismatched last-known-good adapter, and keep custom runtimes prompting for reconnect when Studio cannot auto-connect them.
Made-with: Cursor
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Luke The Dev <iamlukethedev@users.noreply.github.com>
Co-authored-by: Elias Pfeffer <eliaspfeffer@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
* feat(kanban): add Kanban board with task-manager skill, modal UI, and desk clutter
Implement a full Kanban board system for tracking agent tasks:
- Add task-manager skill with shared JSON task store for persistence
- Render board as a floating modal over the live 3D office (not immersive)
- Auto-create tasks from actionable user messages with heuristic filtering
- Sync task status through OpenClaw agent lifecycle events
- Collapse task details panel by default, expand on card click
- Add dynamic desk clutter (papers, folders, etc.) reflecting active task count
- Exclude done tasks from desk clutter count
- Extract KANBAN_CLUTTER_OFFSET for easy positioning adjustment
- Add install flow with progress bar for the task-manager skill
- Include unit and e2e test coverage
Made-with: Cursor
* feat(kanban): production-harden task board with AI-free classification, resilient persistence, and modal UX
- Harden shared task store with atomic writes, payload size limits, and server-side enum validation
- Add client resilience: request timeouts (AbortController), exponential backoff retries, poll deduplication
- Implement optimistic UI with rollback on all card mutations (update, move, archive)
- Add modal accessibility: focus trap, Escape to close, aria-modal, keyboard card navigation
- Trust OpenClaw agent lifecycle phase=start as task classification signal instead of regex heuristics
- Keep regex heuristic only as lightweight filter for direct chat events (conversational noise)
- Expand verb recognition with typo tolerance and broader action vocabulary
- Create tasks from agent runs even when no chat event is received (external channel support)
- Merge dual header bars into single bar; reposition close button outside modal corner
- Exclude done tasks from desk clutter count; make clutter position configurable via KANBAN_CLUTTER_OFFSET
- Update default furniture layout to match user configuration
- Ensure kanban_board furniture persists in local storage across sessions
- Add comprehensive test coverage for store, API route, and controller logic
Made-with: Cursor
---------
Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
- desk_cubicle now has blocksNavigation: true with navPadding: 0
(tight blocking, no inflation — aisles stay clear)
- buildNavGrid reads per-item navPadding from ITEM_METADATA
- getDeskLocations targets y-5 (chair position, above desk blocked zone)
- Agents route AROUND desks instead of through them
- Chair stays passable so agents can reach their sitting position
Fixes object passthrough for desks. Other large passable items
(doors, lamps) unchanged — they remain non-blocking by design.
Co-authored-by: Neo (subagent) <neo@openclaw.local>
Co-authored-by: Luke The Dev <252071647+iamlukethedev@users.noreply.github.com>
Harden the SSH agent-state and skill-removal paths to match the local security model, and avoid rejecting valid local workspace skill removals.
Made-with: Cursor
Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
Fixes#57 — NEXT_PUBLIC_GATEWAY_URL is a build-time variable that gets
baked into the client bundle. Changing it in .env and restarting has no
effect without a rebuild.
- normalizeLocalGatewayDefaults now accepts the sanitized public form
({url, tokenConfigured}) from /api/studio
- When no saved gateway URL exists, prefer runtime localGatewayDefaults
(from openclaw.json or CLAW3D_GATEWAY_URL env var) over the
potentially stale build-time NEXT_PUBLIC_GATEWAY_URL
- loadLocalGatewayDefaults falls back to CLAW3D_GATEWAY_URL/TOKEN env
vars when openclaw.json is absent
- Added runtime env vars documentation to .env.example and README
Co-authored-by: robotica4us-collab <neo@openclaw.ai>
Made-with: Cursor
- Revert next.config.ts: remove hardcoded Cloudflare tunnel URL from
allowedDevOrigins (dev artifact, not part of the voice upload fix).
- Rewrite voice transcribe tests to use mock request objects instead of
real Request/FormData/Blob instances that cause formData() to hang
indefinitely in vitest's Node environment. All 9 tests now pass.
Made-with: Cursor
* fix(voice): enforce upload size limit before buffering (issue #7)
The previous implementation called request.formData() and audio.arrayBuffer()
before checking MAX_VOICE_UPLOAD_BYTES, meaning oversized uploads were fully
buffered into memory before rejection — a DoS/OOM risk.
Changes:
- Check Content-Length header early and return 413 if it exceeds the limit,
preventing any request body from being read into memory for oversized uploads
- Export MAX_VOICE_UPLOAD_BYTES for use in tests
- Switch from instanceof File to duck-typing (checking .arrayBuffer method)
to avoid cross-realm failures in jsdom test environments
- Return HTTP 413 Payload Too Large for oversized uploads (was 400 before)
- Retain a secondary post-buffer size check to catch missing/spoofed
Content-Length headers
Tests added (tests/unit/voiceTranscribe.test.ts):
- Content-Length exceeding limit → 413 before any buffering
- Content-Length at exactly the limit → proceeds normally
- No Content-Length header, small file → proceeds normally (200)
- No Content-Length header, oversized body → 413 after buffering
- Missing audio field → 400
- Empty audio file (0 bytes) → 400
- Malformed Content-Length header → falls through gracefully
Fixes: issue #7
* fix(issue-7): account for multipart overhead in Content-Length early check
The early Content-Length guard was comparing total multipart request size
against MAX_VOICE_UPLOAD_BYTES, but multipart/form-data includes boundary
and header overhead (~200-500 bytes). A valid file at exactly the 20 MB
limit was being rejected with 413.
Fix: add a 1 KB MULTIPART_OVERHEAD_ALLOWANCE to the early check threshold.
The post-buffer check remains the authoritative limit and measures actual
audio bytes. Updated tests to reflect the corrected early-check boundary.
---------
Co-authored-by: Neo (subagent) <neo@openclaw.local>
Co-authored-by: Neo <neo@openclaw.ai>
The test expected [] for same-cell targets, but the code correctly
returns [{ x: ex, y: ey }] so the movement layer can make the final
fine-grained adjustment to the exact pixel.
Made-with: Cursor
* fix(navigation): astar() returns [] on failure instead of raw destination
Issue #3: When A* could not find a route, it returned [{x: endX, y: endY}]
(the raw destination) as a one-element path. The movement layer treated
this as a valid waypoint and steered agents in a straight line toward the
target, letting them pass through walls and furniture.
Changes:
- navigation.ts: Both failure exits in astar() now return [] instead of
[{x: ex, y: ey}]. This applies to:
* findFree() returning null (start or end hopelessly blocked)
* start and end resolving to the same free cell (already arrived)
* open list exhausted with no route to the end
- RetroOffice3D.tsx: Movement-layer waypoint fallback changed from
agent.targetX/Y to agent.x/agent.y when path is empty. An agent with
no route now stays put rather than walking through obstacles.
Tests added (tests/unit/navigation.astarFallback.test.ts):
- astar returns [] for an unreachable destination (thick wall barrier)
- astar returns [] when the entire grid is blocked (findFree fails)
- astar returns a valid path for reachable destinations (regression)
- astar returns [] when start and end snap to the same grid cell
- movement-layer simulation: empty path keeps agent at current position
* fix(navigation): preserve final waypoint for same-cell reachable targets
astar() was returning [] for both true pathfinding failures and same-cell
reachable targets, causing the movement layer to treat both cases identically
(agent stays put). A destination within the same nav cell is still reachable
— the agent should take the final fine-grained step to the exact pixel.
Fix: return [{ x: ex, y: ey }] for same-cell case so the movement layer
can settle the agent onto the exact interaction point.
---------
Co-authored-by: Neo (subagent) <neo@openclaw.local>
Co-authored-by: Neo <neo@openclaw.ai>
* fix(issue-13): remove impossible TS2367 comparison in skillGymDirective guard
OfficeGymDirective is defined as the literal type 'gym' (deskDirectives.ts:9).
The condition at eventTriggers.ts:1136
if (skillGymDirective.directive !== 'release')
compared it against 'release', which TypeScript correctly flags as an
impossible comparison (TS2367), blocking the build.
The check was copy-pasted from the desk/github/qa patterns where 'release'
is a valid directive value. For the gym skill path there is no 'release'
directive — gym hold is released via the isAgentRunning guard in
reduceOfficeGymHoldState (deskDirectives.ts). Any non-null skillGymDirective
should therefore unconditionally set skillGymHoldByAgentId.
Fix: remove the dead guard and set the hold directly, with an explanatory
comment. Verified with npm run typecheck (exits 0).
* test(eventTriggers): add gym directive hold unit tests (issue #13)
Tests for the skillGymHold logic in reconcileOfficeAnimationTriggerState:
- Verify gym directive sets skillGymHoldByAgentId unconditionally (no release guard)
- Verify gym directive via transcript entry triggers hold
- Verify prior hold persists when no new directive is present
- Verify no hold entry when neither directive nor prior hold exists
- Verify multiple agents are handled independently
* fix(issue-13): handle release directive in skillGym hold reconciliation
OfficeGymDirective = 'gym' | 'release'. The previous unconditional
skillGymHoldByAgentId[agentId] = true would silently ignore a release
directive and keep the agent in gym-hold state indefinitely.
Fix: only set the hold when directive === 'gym'. A release directive
now skips the assignment, clearing the hold as intended.
Context: reconcileOfficeAnimationTriggerState tracks the skill-source
gym path (resolveOfficeGymDirective, source: 'skill'). The manual/command
release path (source: 'manual') is handled separately by buildOfficeAnimationState
→ reduceOfficeGymHoldState, which was already correct.
Tests updated: corrected the file-level doc comment, renamed the 'gym'
test for clarity, added a regression test confirming a release-pattern
message does not set the hold.
---------
Co-authored-by: Neo (subagent) <neo@openclaw.local>
Co-authored-by: Neo <neo@openclaw.ai>
Co-authored-by: Luke The Dev <252071647+iamlukethedev@users.noreply.github.com>
* feat: add company builder wizard with AI-powered org generation
Adds a new "Build Your Company" step to the onboarding wizard that lets
users describe their business and generates a full agent org structure
using OpenClaw's AI. Includes company plan generation, role deduplication,
agent bootstrap with main-agent reuse, org chart preview, confetti on
success, CSS voxel running-avatar loader, amber theme unification, and
best-effort SSH workspace cleanup.
Made-with: Cursor
* fix: resolve lint errors in CompanyBuilderModal
Replace setState-in-effect pattern with a direct callback, escape
apostrophes in JSX text, and derive org chart hover state without
side effects.
Made-with: Cursor
---------
Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
Add the office jukebox flow so Spotify can be controlled from the SOUNDCLAW skill, manual jukebox UI, and local browser auth bridge during development.
Made-with: Cursor
* Remote openclaw connection enabled and agent added
* 2 worlds connected
* Performance improvement
* Performance improvements
* Added documentation
* feat(office): add multi-agent beta remote office support
Add a second-office beta that can mirror remote Claw3D presence or derive remote gateway presence so teams can visualize and message agents across instances. Harden the new remote flows, document setup, and keep the branch green with full validation.
Made-with: Cursor
---------
Co-authored-by: iamlukethedev <iamlukethedev@users.noreply.github.com>
Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
* feat(issue-17): add onboarding wizard for new users
Adds a step-based onboarding wizard that guides new users through their
first Claw3D setup: welcome, prerequisites, gateway connection, agent
discovery, and a completion screen.
Architecture:
src/features/onboarding/ (new feature module):
- types.ts: Step definitions, navigation helpers (getNextStep/getPrevStep)
- useOnboardingState.ts: localStorage-backed persistence hook
- index.ts: Barrel exports for clean imports
- components/OnboardingWizard.tsx: Main wizard container with step
navigation, progress bar, and modal overlay
- components/WelcomeStep.tsx: Feature highlights grid
- components/PrerequisitesStep.tsx: Checklist with links/commands
- components/ConnectStep.tsx: Compact gateway connection form
- components/AgentsStep.tsx: Agent discovery feedback
- components/CompleteStep.tsx: Final screen with CTA
Design decisions:
- Modular step system: new steps can be added by extending
OnboardingStepId and registering a component in the switch
- localStorage persistence: wizard shows once per browser, resettable
from settings (future: wire into Studio settings API)
- Connect step gates forward navigation: users cannot skip connection
- Follows Claw3D conventions: feature-first module, no shared state
pollution, Tailwind utility classes, lucide-react icons
- Does NOT modify existing routes or components — zero-risk integration
(parent wiring left to maintainer preference)
Integration guide (for maintainer):
1. Import { OnboardingWizard, useOnboardingState } from the module
2. Add useOnboardingState() to the root layout or agents page
3. Render <OnboardingWizard /> when showOnboarding is true
4. Pass gateway connection props from existing store
tests/unit/onboardingTypes.test.ts (13 tests):
- Step structure validation, navigation helpers, ordering
tests/unit/onboardingState.test.ts (5 tests):
- localStorage persistence, show/hide/reset lifecycle
Addresses #17
* fix(onboarding): wire wizard launch into office UI
Mount the onboarding wizard in OfficeScreen and add a settings action that can re-open it so the new-user flow is reachable and testable.
Made-with: Cursor
---------
Co-authored-by: Neo <neo@openclaw.ai>
Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
* fix(issue-5): add collision-aware pathfinding to Phaser office viewer
Agents in the Phaser office viewer previously moved in straight lines toward
zone anchors, ignoring walls, furniture, and collision geometry. This made
agents walk through rendered map obstacles.
Changes:
src/lib/office/pathfinding.ts (new):
- Shared 2D A* pathfinding module for OfficeMap surfaces
- Builds a nav grid from map objects (walls/furniture layers) and
collision polygons with configurable cell size and padding
- Diagonal corner-cutting prevention (checks both orthogonal neighbors)
- Returns empty path on failure instead of raw destination fallback
- Point-in-polygon rasterisation for collision polygon support
- Intentionally placed in src/lib/office/ for reuse across office stacks
src/features/office/phaser/systems/AgentEffectsSystem.ts:
- Computes A* waypoint paths when agent targets change
- Follows waypoints sequentially instead of linear interpolation
- Caches nav grid and invalidates on map identity change
- Agents stay put when no valid path exists (no wall clipping)
tests/unit/officePathfinding.test.ts (new):
- 12 unit tests covering grid construction, A* routing, corner-cutting
prevention, collision polygon support, blocked-start recovery, and
starter map integration
Fixes#5
* fix(test): remove unused NavGrid2D type import
---------
Co-authored-by: Neo <neo@openclaw.ai>
* fix(issue-4): add missing solid floor props to BLOCKING_TYPES
Audited all furniture types defined in furnitureDefaults.ts and
geometry.ts (ITEM_FOOTPRINT) against BLOCKING_TYPES in navigation.ts.
Added five previously missing solid floor props:
- water_cooler: freestanding floor appliance, agents pathfound through it
- server_terminal: floor-standing terminal in the server room
- dishwasher: floor appliance in the kitchen area
- easel: floor-standing art-room prop
- beanbag: floor seat large enough to obstruct walking paths
Also adds a unit test asserting every newly-added type is correctly
blocked in the nav grid, and that non-solid desk decorations (keyboard)
remain free.
* refactor(nav): replace hardcoded BLOCKING_TYPES with metadata-driven ITEM_METADATA
Previously, buildNavGrid() maintained a hardcoded BLOCKING_TYPES set in
navigation.ts. The issue #4 fix added the five missing solid props directly
to that set, but this approach is brittle — every new furniture type requires
a separate PR touching navigation.ts to stay correct.
This rework introduces ITEM_METADATA in geometry.ts (alongside the existing
ITEM_FOOTPRINT record) as the single source of truth for per-type navigation
properties:
export const ITEM_METADATA: Record<string, { blocksNavigation: boolean }>
Each item type explicitly declares blocksNavigation: true/false. The five
props fixed in issue #4 (water_cooler, server_terminal, dishwasher, easel,
beanbag) retain their blocking status. Unknown types default to false, so
future decorative items never accidentally block navigation.
Changes:
- geometry.ts: add ITEM_METADATA export (64 type entries)
- navigation.ts: remove BLOCKING_TYPES set; add itemBlocksNavigation() helper
that reads ITEM_METADATA[type]?.blocksNavigation ?? false; update buildNavGrid()
to call it
- tests/unit/navigation.navBlockers.test.ts: retain original 5 solid-prop tests;
add metadata-driven test suite covering: all blocking types from metadata,
all non-blocking types from metadata, runtime-added type with blocksNavigation:true,
and unknown-type safe fallback
All 10 tests pass; lint clean; only pre-existing TS2367 (issue #13) remains.
* test(navigation): add extended nav blocker tests (issue #4)
Additional tests for buildNavGrid and astar pathfinding:
- Adjacent blocking items create a continuous impassable wall
- Blocking item near grid edge/boundary causes no out-of-bounds errors
- Full pathfinding integration: astar routes AROUND a cabinet placed between
start and end (not just that cells are blocked)
- desk_cubicle explicitly does NOT block — confirmed via ITEM_METADATA
- door explicitly does NOT block — agents must walk through doors
---------
Co-authored-by: Neo (subagent) <neo@openclaw.local>
* fix(issue-6): prevent A* diagonal corner-cutting through blocked cells
The A* neighbor loop previously checked only whether the destination cell
was free. For diagonal moves this allows agents to clip through the corner
of a blocked cell — the two orthogonal neighbours (e.g. N and E for a NE
move) were never validated.
Fix: after confirming the diagonal destination is free, additionally check
both orthogonal intermediary cells. If either is blocked, the diagonal
expansion is skipped and the agent must route around the obstacle.
Adds three unit tests covering:
- a path that would clip a single corner (rejected after fix)
- a path through open space (diagonals still used freely)
- a path around a multi-cell wall segment (no cells in the wall visited)
* chore: remove unused imports from diagonal corner test (lint cleanup)
* test(navigation): add expanded diagonal corner-cutting tests (issue #6)
Additional tests for astar diagonal corner-cutting prevention:
- All 4 diagonal directions (NE, NW, SE, SW): block orthogonal neighbour,
verify path avoids the blocked cell in each direction
- Both orthogonal sides blocked: verify no diagonal move is taken from start
- L-shaped wall: verify agent navigates around entire L without clipping any segment
- Dense grid stress test: maze-like layout verifying valid path found and no
waypoint lands on a blocked cell
---------
Co-authored-by: Neo (subagent) <neo@openclaw.local>