* feat(daemon): add dynamic port allocation support
- Always create HTTP server regardless of port configuration
- Support port 0 for dynamic allocation
- Output actual port to stdout when using dynamic allocation
- Enable WUI to start daemon on any available port
* feat(wui): add daemon process management infrastructure
- Add Tauri shell and store plugins for process and state management
- Implement Rust daemon manager with automatic startup on app launch
- Add branch-based daemon isolation for development environments
- Create TypeScript services and hooks for daemon lifecycle management
- Add debug panel UI for manual daemon control in dev mode
- Support automatic daemon connection with managed port discovery
- Handle graceful daemon shutdown on app close
- Implement retry logic for daemon connection during startup
* feat(wui): add daemon process management infrastructure
* chore(wui): update gitignore for daemon artifacts
* build(wui): update Tauri bundle configuration
* build: add homebrew formula and update CI for daemon bundling
* formatting
* makefile to build daemon too (when run wui on dev)
* refactor: improve daemon management in WUI with async/await and better error handling
- Convert daemon start/stop operations to async/await pattern
- Switch HTTP host from 127.0.0.1 to localhost for better compatibility
- Add debug URL override support for development
- Improve error handling and startup behavior
- Fix path resolution for development mode when running from src-tauri
* daemon no longer randomly crashes
Needed to do weird stdout things
* Parse daemon log levels to improve dev logging output
Previously all daemon stderr output was logged as ERROR level, causing confusion
and double timestamps. Now we parse slog format to extract actual log levels
(INFO, WARN, ERROR, etc.) and route them to appropriate tracing levels.
* Integrate debug panel into status bar with theme-aware colors
- Move debug panel button from floating bottom-left to status bar bottom-right
- Replace Settings icon with Bug icon and match styling of other status controls
- Update connection status colors to use CSS variables for theme consistency
- Refactor DebugPanel to accept open/onOpenChange props for controlled state
* Remove local homebrew tap files - moved to separate repository
The homebrew tap is now properly maintained in its own repository
at humanlayer/homebrew-humanlayer for public distribution.
* Migrate WUI backend from tracing to log crate with tauri-plugin-log
- Replace tracing with log crate for consistency
- Add tauri-plugin-log with file rotation (50MB) and proper formatting
- Configure LogDir, Stdout (dev), and Webview targets
- Add proper prefixes: [Tauri] for WUI logs, [Daemon] for daemon logs
- Add log:default permission to capabilities
* Add frontend logging infrastructure for WUI
- Install @tauri-apps/plugin-log and @tauri-apps/api dependencies
- Create logging service with JSON serialization for objects
- Add log location notification for production builds
- Initialize attachConsole to display Rust logs in browser console
- All frontend logs will use [Console] prefix
* Migrate all console calls to use logger throughout WUI
- Replace 94 console.* calls with logger.* across 24 files
- Ensures all frontend logs are captured in production log file
- Maintains browser console output in development mode
- High-traffic files: NotificationService (22), AppStore (21), useSubscriptions (10)
* git ignore of compiled things
* fix it to not be annoyed
* Implement branch-based logging for WUI
- Extract branch detection logic (get_git_branch, extract_ticket_id, get_branch_id)
into shared functions in lib.rs
- Configure tauri-plugin-log to use branch-based folders in development:
~/.humanlayer/logs/wui-{branch-id}/codelayer.log
- Update daemon.rs to use shared branch detection functions
- Add get_log_directory Tauri command to expose log paths to frontend
- Update log notification service to handle branch-based directories
- All log sources (WUI backend, daemon stderr, frontend console) now write
to a single rotated log file per branch with clear source prefixes
* Update documentation and simplify Makefile for new logging structure
- Remove tee command from wui-dev target in Makefile since logging is now
handled by tauri-plugin-log
- Update DEVELOPMENT.md to show new WUI log paths in environment overview
- Update CLAUDE.md files to document branch-based log locations:
- Dev: ~/.humanlayer/logs/wui-{branch}/codelayer.log
- Prod: Platform-specific directories
- Document that logs include all sources with prefixes: [Tauri], [Daemon], [Console]
* formatting
* add touch to bins
* ci: align GitHub Actions workflows with local development setup
- Simplify main.yml workflow to use unified setup process
- Add CI detection to setup_repo.sh for conditional tool installation
- Install CI-specific tools (Claude Code CLI, UV, golangci-lint) only in CI
- Add setup-ci and ci-tools targets to Makefile for explicit CI setup
- Parallelize npm and bun dependency installations for faster setup
- Add Go and Rust tool caching to improve CI performance
- Create platform-specific dependency script for future expansion
This change reduces workflow complexity from 75+ to ~50 lines per job while
maintaining all functionality. CI and local development now share the same
setup process, improving maintainability and consistency.
* sdk needs to build in order for wui to check
3.3 KiB
humanlayer-wui
Web/desktop UI for the HumanLayer daemon (hld) built with Tauri and React.
Development
Running in Development Mode
-
Build the daemon (required for auto-launch):
make daemon-dev-build -
Start CodeLayer in development mode:
make codelayer-dev
The daemon starts automatically and invisibly when the app launches. No manual daemon management needed.
Disabling Auto-Launch (Advanced Users)
If you prefer to manage the daemon manually:
export HUMANLAYER_WUI_AUTOLAUNCH_DAEMON=false
make codelayer-dev
Using an External Daemon
To connect to a daemon running on a specific port:
export HUMANLAYER_DAEMON_HTTP_PORT=7777
make codelayer-dev
Building for Production
To build CodeLayer with bundled daemon:
make codelayer-bundle
This will:
- Build the daemon for macOS ARM64
- Build the humanlayer CLI for macOS ARM64
- Copy both to the Tauri resources
- Build CodeLayer with the bundled binaries
The resulting DMG will include both binaries and automatically manage their lifecycle.
Daemon Management
The daemon lifecycle is completely automatic:
In development mode:
- Daemon starts invisibly when CodeLayer launches
- Each git branch gets its own daemon instance
- Database is copied from
daemon-dev.dbtodaemon-{branch}.db - Socket and port are isolated per branch
- Use debug panel (bottom-left settings icon) for manual control if needed
In production mode:
- Daemon starts invisibly when CodeLayer launches
- Uses default paths (
~/.humanlayer/daemon.db) - Stops automatically when the app exits
- No user interaction or awareness required
Error Handling:
- If daemon fails to start, app continues normally
- Connection can be established later via debug panel (dev) or automatically on retry
- All errors are logged but never interrupt the user experience
MCP Testing
To test MCP functionality:
In development:
- Ensure you have
humanlayerinstalled globally:npm install -g humanlayer - Start CodeLayer:
make codelayer-dev - Configure Claude Code to use
humanlayer mcp claude_approvals - The MCP server will connect to your running daemon
In production (after Homebrew installation):
- Claude Code can directly execute
humanlayer mcp claude_approvals - No npm or npx required - Homebrew automatically created symlinks in PATH
- The MCP server connects to the daemon started by CodeLayer
- Verify PATH setup is working:
which humanlayershould show/usr/local/bin/humanlayer
Troubleshooting MCP connection:
- If MCP can't find
humanlayer, restart Claude Code after installation - If launched from Dock, Claude Code may have limited PATH - launch from Terminal instead
- Check daemon is running:
ps aux | grep hld - Check MCP logs in Claude Code for connection errors
Quick Start for Frontend Development
Always use React hooks, never the daemon client directly:
import { useApprovals } from '@/hooks'
function MyComponent() {
const { approvals, loading, error, approve } = useApprovals()
// ... render UI
}
Documentation
- Architecture Overview - System design and data flow
- Developer Guide - Best practices and examples
- API Reference - Hook and type documentation
Status
⚠️ Experimental - APIs may change