Files
humanlayer/humanlayer-wui
Sundeep Malladi ad48d78d5d Automate Brew Cask Nightly Releases with Side-by-Side Support (#404)
* Phase 1: Build-Time Version Injection in Daemon

- Create internal/version package for build-time version management
- Update RPC server to use version.GetVersion() instead of hardcoded constant
- Update HTTP API handlers to use version package
- Configure workflow to inject version during build with -ldflags
- Update tests to use version package

This allows nightly builds to report version as "0.1.0-YYYYMMDD-nightly"
while dev builds show "0.1.0".

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Phase 2: Dynamic Tauri App Configuration

- Create nightly Tauri config with distinct productName and identifier
- Update workflow to use nightly config for scheduled builds
- Nightly builds will create CodeLayer-Nightly.app with separate identifier

This enables side-by-side installation of stable and nightly builds.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add pre-generated nightly icons with color rotation

* Phase 3: Update workflow to use nightly icons for scheduled builds

* Phase 4: Configure Daemon Paths and Ports via Build Flags

Configure the nightly daemon to use different default paths and ports by injecting them at build time using ldflags.

Changes:
- Make DefaultDatabasePath, DefaultSocketPath, and DefaultHTTPPort injectable via ldflags in hld/config/config.go
- Add setDefaults() function to handle string-to-int conversion for HTTP port
- Update release workflow to inject nightly configuration for scheduled builds:
  - Database: ~/.humanlayer/daemon-nightly.db
  - Socket: ~/.humanlayer/daemon-nightly.sock
  - HTTP Port: 7778
- Regular builds continue to use standard defaults

This allows nightly and stable daemons to run side-by-side without conflicts.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Phase 5: Update Homebrew Cask for Side-by-Side Support

- Add automated nightly cask updates to release workflow
  - Calculate SHA256 and construct release URLs
  - Checkout homebrew tap repository
  - Generate codelayer-nightly.rb with proper configuration
  - Commit and push updates automatically
- Update nightly cask to support side-by-side installation
  - Renamed binaries with -nightly suffix
  - Uses nightly-specific data paths
  - No conflicts declared with stable cask
- Add TODO for future stable release automation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add test_nightly mode to workflow for testing nightly build behavior

* Fix nightly icons: Convert 32x32.png and Square30x30Logo.png to RGBA format

* Use HUMANLAYER_HOMEBREW_CASK_WRITE_GITHUB_PAT for homebrew tap authentication

* change test_nightly to release_nightly

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-05 14:08:29 -05:00
..
2025-06-13 14:58:56 -05:00
2025-06-13 14:28:55 -05:00
2025-08-04 15:45:18 -07:00
2025-06-13 14:58:56 -05:00
2025-06-24 16:39:44 -05:00
2025-06-13 14:58:56 -05:00

humanlayer-wui

Web/desktop UI for the HumanLayer daemon (hld) built with Tauri and React.

Development

Running in Development Mode

  1. Build the daemon (required for auto-launch):

    make daemon-dev-build
    
  2. 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:

  1. Build the daemon for macOS ARM64
  2. Build the humanlayer CLI for macOS ARM64
  3. Copy both to the Tauri resources
  4. 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.db to daemon-{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 humanlayer installed 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 humanlayer should 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

Status

⚠️ Experimental - APIs may change