Doramagic Project Pack · Human Manual
humanlayer
The best way to get AI coding agents to solve hard problems in complex codebases.
System Overview and Architecture
Related topics: hld Daemon: Sessions, Approvals, MCP, and Storage, CodeLayer Desktop (humanlayer-wui), hlyr CLI, SDKs, Contracts, and Release Pipeline
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: hld Daemon: Sessions, Approvals, MCP, and Storage, CodeLayer Desktop (humanlayer-wui), hlyr CLI, SDKs, Contracts, and Release Pipeline
System Overview and Architecture
Purpose and Scope
HumanLayer is an open source platform that provides a unified surface for orchestrating AI coding agents. Its flagship product, CodeLayer, is described as "the best way to get Coding Agents to solve hard problems in complex codebases" — a keyboard-first IDE that wraps Claude Code and exposes "battle-tested workflows" for AI-first development (README.md).
The system is decomposed into several cooperating packages that together deliver:
- A desktop-class web UI for managing agent sessions, approvals, and conversations.
- A long-running daemon (
hld) that brokers sessions, MCP servers, and tool-call approvals. - A command-line tool (
hlyr) for direct human-in-the-loop contact, Claude Code configuration, and developer notes. - A generated TypeScript SDK that the UI uses to talk to the daemon over HTTP and Server-Sent Events.
- A curated set of
hack/utilities (e.g. a Linear CLI) that extend the platform.
High-Level Component Map
graph TD
User[Developer / Team]
CodeLayerUI[CodeLayer Desktop UI<br/>(humanlayer-wui)]
TauriShell[Tauri Shell]
CLI[hlyr CLI]
Daemon[hld Daemon<br/>Sessions, Approvals, MCP]
Claude[Claude Code<br/>SDK / CLI]
MCP[(MCP Servers)]
Slack[Slack / Email / Web]
PostHog[(PostHog Telemetry)]
Linear[Linear API]
User -->|interacts| CodeLayerUI
User -->|scripts & CI| CLI
CodeLayerUI --> TauriShell
TauriShell -->|HTTP + SSE| Daemon
CLI -->|contact_human| Slack
CLI -->|claude init| User
Daemon -->|spawns| Claude
Daemon -->|manages| MCP
Daemon -->|events| CodeLayerUI
CodeLayerUI -->|sanitized events| PostHog
CLI -->|thoughts sync| User
Linear -.->|via hack/linear| UserThe diagram reflects three deployment surfaces (UI, CLI, and a third-party Linear CLI in hack/linear/) that all converge on the daemon and on external contact channels (hlyr/README.md, hack/linear/README.md).
Repository Layout
The repository is a monorepo containing several distinct workspaces. Each top-level folder corresponds to one deployable artifact or shared library.
| Path | Type | Responsibility |
|---|---|---|
humanlayer-wui/ | Vite + React 19 + Tauri app | Desktop-class UI for CodeLayer (humanlayer-wui/package.json). |
hld/ | Daemon (Go) | Hosts sessions, approvals, files, MCP and emits SSE events. |
hld/sdk/typescript/ | Generated SDK | Typed HTTP + SSE client used by the UI (hld/sdk/typescript/src/client.ts). |
hlyr/ | Node CLI | contact_human, claude init, thoughts subcommands (hlyr/README.md). |
apps/react/ | Standalone React app | Generic Vite/React entry point (apps/react/src/frontend.tsx). |
hack/linear/ | Utility CLI | Linear issue tracker integration (hack/linear/README.md). |
humanlayer-wui/src/lib/daemon/types.ts | Shared types | UI-side mirrors of daemon types (humanlayer-wui/src/lib/daemon/types.ts). |
The Daemon (`hld`)
The hld daemon is the central control plane. It exposes REST APIs grouped by resource family and pushes live updates through Server-Sent Events.
API Surface
The generated TypeScript SDK is grouped into resource APIs. The class HLDClient instantiates each one with a single base URL:
| API | Purpose | Notes |
|---|---|---|
SessionsApi | Create, list, continue, archive sessions | Primary interaction surface for CodeLayer. |
ApprovalsApi | List, fetch, respond to pending approvals | Drives the human-in-the-loop flow. |
SystemApi | Health and capability discovery | Used by the UI on startup. |
SettingsApi | User and daemon configuration | Includes UserSettingsResponse and UpdateUserSettingsRequest. |
FilesApi | Create directories, fuzzy-search files | Powers command palette and @-mentions (hld/sdk/typescript/src/generated/apis/FilesApi.ts). |
AgentsApi | Discover Claude Code agents and sub-agents | Includes DiscoverAgents200Response. |
Source: hld/sdk/typescript/src/client.ts.
Real-Time Event Stream
The daemon emits a continuous stream of events that the UI consumes. The client manages a per-channel EventSourceLike connection per SSE channel, with explicit onMessage, onError, onConnect, and onDisconnect handlers — important for reconnecting after laptop sleep or daemon restarts (hld/sdk/typescript/src/client.ts).
Key event shapes include:
- Session lifecycle:
SessionStatusChangedEventDatacarriesold_statusandnew_statusso the UI can animate transitions deterministically. - Approvals:
NewApprovalEventData(and its older aliasApprovalRequestedEventData) signals that a tool call is awaiting human input, andApprovalResolvedEventDatacarries theDecisionback to the daemon. - Settings changes:
SessionSettingsChangedEventDatareports mutations toauto_accept_edits,dangerously_skip_permissions, and the timeout. ASessionSettingsChangeReason.EXPIREDvalue indicates the "dangerous skip permissions" window elapsed (humanlayer-wui/src/lib/daemon/types.ts).
Core Data Models
The daemon's contract is encoded in TypeScript types. The most important ones are summarized below.
| Model | Key Fields | Notes |
|---|---|---|
ConversationEvent | eventType, role, toolName, toolResultContent, isCompleted, approvalStatus, approvalId | eventType is one of message, tool_call, tool_result, system, thinking (hld/sdk/typescript/src/generated/models/ConversationEvent.ts). |
Approval | id, runId, sessionId, status, createdAt, respondedAt, toolName, toolInput, comment | status transitions through pending, approved, denied, resolved (hld/sdk/typescript/src/generated/models/Approval.ts). |
MCPServer | type, command, args, env, url, headers | Covers both stdio (command/args/env) and HTTP (url/headers) transports (hld/sdk/typescript/src/generated/models/MCPServer.ts). |
CodeLayer UI (`humanlayer-wui`)
The UI is a Vite-powered React 19 application wrapped in Tauri for desktop distribution. The package manifest declares both the desktop and the Storybook toolchains (humanlayer-wui/package.json).
Tech Stack
| Concern | Library / Tool |
|---|---|
| Framework | React 19 (^19.1.0) with React Router 7. |
| Build | Vite + Tauri 2. |
| Styling | Tailwind CSS 4, tailwind-merge, class-variance-authority. |
| State | Zustand 5 (with documented slice patterns). |
| Editor | TipTap 3 (with lowlight for code highlighting, react-syntax-highlighter). |
| UX primitives | Radix UI (checkbox, dialog, dropdown, popover, scroll-area, select, slot, collapsible, label). |
| Telemetry | posthog-js with a custom sanitizer. |
| Notifications | sonner. |
| Command palette | cmdk. |
| Hotkeys | react-hotkeys-hook. |
| Testing | Bun test, Testing Library, Storybook 9. |
Source: humanlayer-wui/package.json.
Daemon Integration
The UI consumes @humanlayer/hld-sdk directly from the sibling workspace at file:../hld/sdk/typescript. The client is constructed with an explicit baseUrl or port, optional headers, and an onFetchError hook that is invoked with the URL and HTTP method whenever a request fails — making it the natural place to surface network errors to the user (hld/sdk/typescript/src/client.ts).
On the UI side, humanlayer-wui/src/lib/daemon/types.ts mirrors the same shapes (Approval, SessionStatus, ConversationEvent, ContinueSessionRequest, etc.) so React components can use locally typed helpers without going through the SDK. The ApprovalRequestedEventData alias is explicitly marked "to be removed", signaling an ongoing cleanup of the type surface (humanlayer-wui/src/lib/daemon/types.ts).
State Management
State is composed of focused Zustand slices. The documented patterns include:
- Conditional updates that propagate changes to a "focused" entity when it is the same one being mutated.
- Workflow actions that coordinate across slices (e.g. removing an approval and updating the related session's status to
Running). - Slice composition in
src/stores/demo/README.md, which serves as a worked example for contributors writing new stores (humanlayer-wui/src/stores/demo/README.md).
Telemetry and Privacy
PostHog is the product analytics provider, but every event is filtered through a sanitizer that whitelists only safe keys. The whitelist explicitly includes PostHog-standard fields ($current_url, $browser, $os, $screen_height, distinct_id, etc.) plus a small set of UX-meaningful names (theme, theme_source, menu_opened, dialog_shown). Recursion is bounded at depth 10, and any filtered key emits a console.warn for developer visibility (humanlayer-wui/src/lib/telemetry/posthog-sanitizer.ts). This is consistent with the project's emphasis on not leaking session or code content.
UX Surfaces the Community Cares About
Several GitHub discussions are directly relevant to the UI's architecture:
- Issue #956 requests a way to *disallow* the "Disable bypass permissions" toggle entirely for security-conscious teams. The daemon already models
dangerously_skip_permissionsand adangerously_skip_permissions_timeout_msper session, and emits aSessionSettingsChangeReason.EXPIREDevent when that window closes — so the policy hook should attach to the settings pipeline rather than the UI (humanlayer-wui/src/lib/daemon/types.ts). - Issue #944 complains about the auto-scroll behavior when hovering a conversation step. Auto-scroll in CodeLayer is a UI-level concern driven by the
ConversationEventstream; it lives in the renderer that mapseventTypeto the rendered block. - Issue #905 asks for a
CMD+Cshortcut to archive and recreate a session. The session lifecycle types (SessionStatus,ListSessionsRequest) are already in place to support such a flow, and any new shortcut would simply orchestrate the existingarchive+createAPI calls.
The CLI (`hlyr`)
hlyr is the developer-facing surface for non-UI workflows. It bundles several subcommands around a shared configuration system (hlyr/README.md).
Subcommand Inventory
| Subcommand | Description |
|---|---|
contact_human | Sends a message to a human via Slack, email, or the web UI. Reads HUMANLAYER_API_KEY, HUMANLAYER_SLACK_CHANNEL, or HUMANLAYER_EMAIL_ADDRESS; falls back to --config-file (e.g. .hlyr.json). |
claude init | Copies Claude Code commands, agents, and settings into a project's .claude/ directory. Supports --all (non-interactive) and --force. |
thoughts | Manages a developer-notes repository (per-project and global), with profile support: thoughts profile create / list / show / delete. |
| MCP server mode | Runs the MCP server so external tools (e.g. Claude Code) can talk back to HumanLayer for approvals. |
Profile-Based Thoughts
The thoughts subsystem is the most configuration-heavy part of the CLI. hlyr/src/thoughtsConfig.ts defines a ResolvedProfileConfig with thoughtsRepo and reposDir fields, and the file exposes overloaded updateSymlinksForNewUsers signatures so the same code path supports both the legacy four-string call and the newer profile-aware call (hlyr/src/thoughtsConfig.ts). This back-compat design is what allows "per-repository profiles, even worktrees of the same repo" to coexist with the original single-repo mode (hlyr/README.md).
Cross-Component Data Flow
The diagram below traces a single approval lifecycle end to end. This is the canonical interaction in HumanLayer and ties together the UI, daemon, Claude Code, and a human approver.
graph TD
A[User types in CodeLayer] --> B[hld creates Session]
B --> C[Session invokes Claude Code]
C --> D{Tool call needs approval?}
D -- No --> E[Tool executes]
D -- Yes --> F[Approval status: pending]
F --> G[SSE push to CodeLayer UI]
G --> H[UI shows approval card]
H --> I[User clicks Approve/Deny]
I --> J[ApprovalsApi responds]
J --> K[SSE: ApprovalResolvedEvent]
K --> L[Session continues]
L --> C
E --> LSource: hld/sdk/typescript/src/client.ts, hld/sdk/typescript/src/generated/models/Approval.ts, hld/sdk/typescript/src/generated/models/ConversationEvent.ts.
Configuration Surfaces
Configuration is layered: each tool reads from a mix of environment variables, JSON config files, and CLI flags. The hlyr config file shape (.hlyr.json) is the canonical example, defining channels for slack with a channel_or_user_id:
{
"channel": {
"slack": {
"channel_or_user_id": "C08G5C3V552"
}
}
}
For the daemon, the relevant axes are:
auto_accept_editsanddangerously_skip_permissionstoggles, surfaced throughSessionSettingsChangedEventData.dangerously_skip_permissions_timeout_ms— a server-side timeout that drives theEXPIREDreason event (humanlayer-wui/src/lib/daemon/types.ts).MCPserver descriptors with per-servercommand,args,env,url, andheaders(hld/sdk/typescript/src/generated/models/MCPServer.ts).HUMANLAYER_API_KEYand the channel-specificHUMANLAYER_SLACK_CHANNEL/HUMANLAYER_EMAIL_ADDRESSenv vars (hlyr/README.md).
Build and Tooling
The repository's package.json for the UI exposes a familiar set of scripts: dev, build (which runs tsc && vite build), lint, format, typecheck, a combined check that runs all three, test (Bun), and Storybook (storybook, build-storybook). Tauri is invoked through tauri (humanlayer-wui/package.json). The CLI exposes the equivalent lifecycle in its own README: npm install, npm run build, npm test, and npm run dev for watch mode (hlyr/README.md).
The generic React entry point at apps/react/src/frontend.tsx is intentionally minimal — it renders an <App /> into #root inside StrictMode, with HMR-aware re-rendering — confirming that the heavier orchestration lives in humanlayer-wui rather than apps/react (apps/react/src/frontend.tsx).
Extending the System
Two extension points stand out for new contributors:
- New
hlyrsubcommands follow the pattern of grouping under a top-level verb (e.g.thoughts,claude,contact_human). New thoughts features land alongsidethoughtsConfig.ts, which already models theResolvedProfileConfigand symlink-update logic for multi-profile setups (hlyr/src/thoughtsConfig.ts). - New SDK API groups should be added as both a generated
apis/*Api.tsand a corresponding*Apifield on theHLDClientclass inhld/sdk/typescript/src/client.ts. The existing six groups (Sessions, Approvals, System, Settings, Files, Agents) set the convention for argument shapes, method prefixes (*Rawforruntime.ApiResponse<T>), and JS doc summaries.
Common Failure Modes and Troubleshooting
| Symptom | Likely Cause | Where to Look |
|---|---|---|
| SSE stream stalls after the laptop sleeps | The EventSourceLike needs a manual reconnect; UI depends on the SDK's onDisconnect handler firing | hld/sdk/typescript/src/client.ts |
| Tool call "hangs" without surfacing in the UI | An Approval is still in pending state; check ApprovalsApi.listApprovals | hld/sdk/typescript/src/generated/models/Approval.ts |
| "Dangerous skip permissions" toggle stops working mid-session | Daemon emitted SessionSettingsChangeReason.EXPIRED | humanlayer-wui/src/lib/daemon/types.ts |
humanlayer thoughts writes to the wrong repo | Profile resolution; verify thoughts profile list and thoughts config | hlyr/README.md |
humanlayer claude init errors in CI | The command requires a TTY unless --all is passed | hlyr/README.md |
| PostHog events appear empty in dashboards | Sanitizer stripped the keys; check console.warn output from sanitizeEventProperties | humanlayer-wui/src/lib/telemetry/posthog-sanitizer.ts |
linear CLI returns "command not found" | PATH not set up; rerun npm install -g . inside hack/linear/ | hack/linear/README.md |
See Also
- hlyr CLI Reference — Detailed subcommand docs for
contact_human,claude init, andthoughts. - humanlayer-wui Stores Guide — Patterns for composing Zustand slices in the UI.
- hack/linear CLI — Companion utility for pulling Linear tickets into a
thoughts/shared/tickets/directory.
Source: https://github.com/humanlayer/humanlayer / Human Manual
hld Daemon: Sessions, Approvals, MCP, and Storage
Related topics: System Overview and Architecture, CodeLayer Desktop (humanlayer-wui), hlyr CLI, SDKs, Contracts, and Release Pipeline
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: System Overview and Architecture, CodeLayer Desktop (humanlayer-wui), hlyr CLI, SDKs, Contracts, and Release Pipeline
hld Daemon: Sessions, Approvals, MCP, and Storage
Overview
The HumanLayer Daemon (hld) is the long-running backend service that orchestrates Claude Code sessions, mediates human-in-the-loop approval workflows, exposes a Model Context Protocol (MCP) server to the underlying agent, and persists session/approval state in a local SQLite database. It is the authoritative control plane that the WUI (humanlayer-wui) and the CLI (hlyr) speak to, and the bridge that connects a Claude Code subprocess to channels such as Slack, email, and the web UI for human contact.
Per the daemon's own README, hld provides "a REST API and JSON-RPC interface for managing Claude Code sessions, approvals, and real-time event streaming" — three concerns that map almost one-to-one to the three primary subsystems documented on this page.
Source: hld/README.md
High-Level Architecture
The daemon is composed of loosely coupled managers that communicate through an in-process event bus. The HTTP server (REST + SSE) and the JSON-RPC server are both thin front doors onto the same internal managers.
graph TD
CLI[hlyr CLI]
WUI[humanlayer-wui / CodeLayer]
Ext[External Integrations / SDKs]
subgraph HLD[hld Daemon]
HTTP[REST API + SSE<br/>port 7777]
RPC[JSON-RPC Server]
SM[Session Manager]
AM[Approval Manager]
MCP[MCP Server]
BUS[(Event Bus)]
STORE[(SQLite Store)]
CCW[Claude Code Wrapper]
PM[Permission Monitor]
end
CC[Claude Code Subprocess]
SLACK[Slack / Email / Web UI]
CLI --> HTTP
WUI --> HTTP
Ext --> HTTP
CLI --> RPC
Ext --> RPC
HTTP --> SM
HTTP --> AM
RPC --> SM
RPC --> AM
RPC --> MCP
SM --> CCW
SM --> PM
SM --> BUS
SM --> STORE
AM --> BUS
AM --> STORE
MCP --> AM
BUS --> HTTP
CCW <--> CC
AM --> SLACK
SLACK --> AMKey responsibilities of each subsystem
| Subsystem | File | Responsibility |
|---|---|---|
| Entrypoint | hld/cmd/hld/main.go | Parse flags, load config, wire the daemon together, signal handling |
| Daemon lifecycle | hld/daemon/daemon.go | Long-running supervisor that owns all managers and graceful shutdown |
| Session management | hld/session/manager.go | Create / continue / interrupt / archive Claude Code sessions |
| Claude Code integration | hld/session/claudecode_wrapper.go | Spawns and tracks the claude subprocess, streams output back |
| Permission monitor | hld/session/permission_monitor.go | Watches tool calls and decides when human approval is required |
| Approvals | hld/approval/manager.go | Lifecycle of approval requests: pending → approved/denied, with retries |
| MCP | hld/mcp/server.go | Exposes request_approval and friends to the agent via MCP |
| Storage | hld/store/sqlite.go | Persistent store for sessions, approvals, file snapshots, settings |
| Event bus | hld/bus/events.go | Pub/sub channel that all managers publish to and that SSE consumers subscribe from |
| RPC transport | hld/rpc/server.go | JSON-RPC endpoint used by the CLI and SDK |
| REST transport | hld/api/handlers/server.go | HTTP handlers generated from the OpenAPI spec |
| API contract | hld/api/openapi.yaml | Source of truth for the public REST surface |
Source: hld/cmd/hld/main.go, hld/daemon/daemon.go, hld/bus/events.go
Configuration
The daemon reads a small set of environment variables, all prefixed with HUMANLAYER_DAEMON_. The HTTP transport can be disabled entirely when only Unix sockets / JSON-RPC are required.
| Variable | Default | Purpose |
|---|---|---|
HUMANLAYER_DAEMON_HTTP_PORT | 7777 | TCP port for the REST + SSE server. Set to 0 to disable HTTP. |
HUMANLAYER_DAEMON_HTTP_HOST | 127.0.0.1 | Bind address for the HTTP server. Loopback by default for security. |
To run a Unix-socket-only daemon (no REST listener):
export HUMANLAYER_DAEMON_HTTP_PORT=0
hld start
Source: hld/README.md
Sessions
Session Lifecycle
A session is a single Claude Code conversation tracked by the daemon. Sessions can be created fresh, continued from a prior point, interrupted, or archived. Each session is identified by both a daemon-side sessionId/runId and the upstream claudeSessionId that the underlying claude subprocess returns.
stateDiagram-v2
[*] --> Drafting
Drafting --> Running: launch
Running --> WaitingInput: tool call requires approval
WaitingInput --> Running: approval granted
WaitingInput --> Running: deny + retry policy
WaitingInput --> Completed: deny + abort
Running --> Completed: agent finishes
Running --> Failed: subprocess error
Running --> Archived: user archives
Completed --> Archived: user archives
Failed --> [*]
Archived --> [*]The WUI extends the SDK session type with a couple of UI-specific fields but otherwise consumes the wire format directly:
export interface Session extends SDKSession {
additionalDirectories?: string[]
}
Source: humanlayer-wui/src/lib/daemon/types.ts
Session Manager
hld/session/manager.go owns:
- Persisting session metadata in SQLite (title, working directory, model, parent session, timestamps).
- Driving the Claude Code wrapper to start a new run or continue an existing one.
- Subscribing to the event bus to react to approval outcomes and tool events.
- Emitting
SessionStatustransitions to subscribers.
Claude Code Wrapper
hld/session/claudecode_wrapper.go is a thin adapter around the claude CLI. It is responsible for:
- Spawning the subprocess with the right model, working dir, allowed tools, and permission-prompt tool.
- Streaming the subprocess's output (text, JSON, or stream-JSON modes) into the event bus.
- Forwarding approval responses back into the subprocess.
The Go SDK (claudecode-go) mirrors this surface for embedders that want to drive Claude Code directly without the daemon.
Source: claudecode-go/README.md
Continuing a Session
Continuing an existing session produces a new run that retains the original conversation context. The REST contract for this operation is generated from the OpenAPI spec:
export interface ContinueSessionResponseData {
sessionId: string
runId: string
claudeSessionId: string
parentSessionId: string
}
The four IDs let the WUI distinguish between the daemon run, the upstream Claude conversation, and the logical session tree.
Source: hld/sdk/typescript/src/generated/models/ContinueSessionResponseData.ts
Community feedback: archiving sessions
A long-standing request from the community is to make session archival a single keystroke. Currently the WUI flow is roughly: press E → press C → type a name → change directory. A CMD+C shortcut for "archive current session and start a fresh one" is a requested UX improvement, which would map to a bulk-archive + new-draft operation against the REST API.
The REST surface already supports bulk archive (the generated BulkArchiveResponse model is part of the SDK), so a one-keystroke command is a thin UI feature on top of existing daemon capabilities.
Source: hld/sdk/typescript/src/generated/models/BulkArchiveResponse.ts
Approvals
Approval Workflow
Approvals are the human-in-the-loop gate. When the permission monitor detects a tool call that is not in the auto-allow set, it asks the approval manager to suspend the agent and surface a request to a human.
graph TD
A[Claude Code emits tool call] --> B{Permission Monitor}
B -- Auto-allow --> C[Tool executes]
B -- Requires human --> D[Approval Manager creates pending approval]
D --> E[Event Bus: approval.pending]
E --> F[SSE: pushes to WUI]
E --> G[Routing engine: Slack / Email / Web]
F --> H{User decides}
G --> H
H -- Approve --> I[Status = approved]
H -- Deny --> J[Status = denied]
H -- Deny + retry --> K[Status = denied, retry policy applied]
I --> L[Tool execution continues]
J --> M[Session aborted or continues without tool]
K --> N[Agent is re-prompted]
L --> E2[Event Bus: approval.resolved]
J --> E2
K --> E2
E2 --> F2[SSE: pushes resolution to WUI]Approval Data Model
The canonical approval object, as exposed to TypeScript clients, is:
| Field | Type | Description |
|---|---|---|
id | string | Daemon-internal approval identifier |
runId | string | Run the approval belongs to |
sessionId | string | Session the approval belongs to |
status | ApprovalStatus enum | pending, approved, denied, etc. |
createdAt | Date (ISO 8601) | When the request was created |
respondedAt | Date? | When the human responded |
toolName | string | Tool the agent is calling |
toolInput | object | JSON input parameters to the tool |
comment | string? | Free-text comment from the approver |
A guard instanceOfApproval is generated alongside the type so SDK consumers can validate untyped JSON before trusting it.
Source: hld/sdk/typescript/src/generated/models/Approval.ts
Approval Manager
hld/approval/manager.go owns the approval queue and the state transitions shown above. It is also the integration point with external contact channels (Slack, email) configured via the CLI:
export HUMANLAYER_API_KEY=...
export HUMANLAYER_SLACK_CHANNEL=C08G5C3V552
humanlayer contact_human --message "Review this PR"
Source: hlyr/README.md
Bypass-permissions policy (community concern)
Enterprise users have asked for a way to *disallow* the "Disable bypass permissions" toggle so that no agent run can opt out of the permission system. The toggle maps directly to the dangerouslySkipPermissions field on LaunchSessionParams:
export interface LaunchSessionParams {
query: string
title?: string
provider?: 'anthropic' | 'openrouter' | 'baseten'
model?: string
workingDir?: string
mcpConfig?: any
permissionPromptTool?: string
maxTurns?: number
autoAcceptEdits?: boolean
dangerouslySkipPermissions?: boolean // <-- community concern
proxyApiKey?: string
additionalDirectories?: string[]
draft?: boolean
}
A deployment-level hard-disable would be a configuration knob read by the daemon (or a WUI feature flag) that rejects any createSession request with dangerouslySkipPermissions: true, rather than a per-user toggle. Tracking that policy is the responsibility of the launch path in hld/session/manager.go and the launch UI in the WUI.
Source: humanlayer-wui/src/lib/daemon/types.ts
MCP Server
hld/mcp/server.go exposes a Model Context Protocol server that the agent (Claude Code) talks to during a run. The MCP surface typically includes tools such as request_approval and get_approval_response, but the daemon treats MCP as just another consumer of the approval manager: every tool call routed through MCP is translated into a normal approval lifecycle event, which the event bus fans out to the WUI and external channels.
This indirection means that:
- The WUI does not need to know which transport the agent used.
- External integrations (Slack bots, email responders) implement the same
pending → resolvedcontract regardless of whether the call originated from MCP, REST, or RPC. - Replacing the agent runtime (e.g., switching to a different MCP-capable model) does not require touching the approval manager.
Source: hld/mcp/server.go, hld/approval/manager.go
Storage
SQLite Store
hld/store/sqlite.go is the only persistent store in the system. It is intentionally simple (single file, no external service) so the daemon can be installed and run locally with no infrastructure dependencies.
Tables (inferred from the API surface and generated models):
| Table | Purpose | Key columns |
|---|---|---|
sessions | One row per session + versioned run | id, run_id, claude_session_id, parent_session_id, status, working_dir, model, created_at, archived_at |
approvals | Pending and historical approvals | id, run_id, session_id, status, tool_name, tool_input (JSON), comment, created_at, responded_at |
file_snapshots | Per-tool pre-edit snapshots used for diff/undo | tool_id, file_path, content, created_at |
settings | User config and per-deployment policy | key/value |
events (optional cache) | Optional durable event log feeding SSE replay | derived from bus |
File Snapshots
When the agent edits a file, the wrapper (or the approval manager) records the pre-edit contents so the WUI can render a diff and offer one-click revert. The shape of each snapshot row is:
export interface FileSnapshot {
toolId: string // Tool invocation that created the snapshot
filePath: string
content: string // Full file content at snapshot time
createdAt: Date
}
Source: hld/sdk/typescript/src/generated/models/FileSnapshot.ts
Migration policy
Because schema changes are inevitable, the store implementation is expected to be paired with a sequential migration runner. Production deployments rely on additive migrations (new tables, new nullable columns) and never destructive ones, so archived approvals and historical sessions remain readable across upgrades.
Source: hld/store/sqlite.go
Event Bus and Real-Time Streaming
hld/bus/events.go is an in-process pub/sub channel. Every state change in the daemon — session created, approval pending, approval resolved, file snapshot taken, agent message streamed — is published exactly once on the bus.
The HTTP server subscribes to the bus and fans events out over Server-Sent Events (SSE) to every connected WUI client. The TypeScript SDK uses the eventsource polyfill for Node and the native EventSource in the browser:
const unsubscribe = await client.subscribeToEvents(
{ sessionId: session.sessionId },
{
onMessage: (event) => console.log('Event:', event),
onError: (error) => console.error('Error:', error),
onConnect: () => console.log('connected'),
onDisconnect: () => console.log('disconnected'),
}
)
A community-reported UX issue is that the WUI's auto-scroll on hover currently feels "jumpy" — when a user is reading a long session transcript and hovers over a different step, the view jumps to the top of that block. The fix is purely in the WUI's hover behavior, but the underlying SSE stream provides the events the WUI uses to render steps, so any change in step render boundaries should be validated against live event ordering from the bus.
Source: hld/sdk/typescript/README.md, hld/sdk/typescript/src/client.ts
REST API Surface
The REST API is the canonical, generated integration point. hld/api/openapi.yaml is the single source of truth; both the HTTP handlers in hld/api/handlers/server.go and the TypeScript SDK in hld/sdk/typescript/ are generated from it.
graph LR
SPEC[openapi.yaml] --> GEN[OpenAPI Generator]
GEN --> HND[Go HTTP handlers<br/>api/handlers/server.go]
GEN --> SDK[TypeScript SDK<br/>@humanlayer/hld-sdk]
HND --> HTTP[HTTP server :7777]
SDK --> WUI[humanlayer-wui]
SDK --> CLI[hlyr]
SDK --> EXT[Third-party integrations]The TypeScript SDK exposes a typed client with sub-APIs for the major resource groups:
| Sub-API | Responsibility |
|---|---|
SessionsApi | Create, continue, list, archive, interrupt sessions |
ApprovalsApi | List, fetch, and decide approvals |
SystemApi | Health, version, daemon info |
SettingsApi | Read and update user/deployment settings |
FilesApi | Recent paths, fuzzy file search, directory validation/creation |
AgentsApi | Discover and introspect available agents |
const client = new HLDClient({ port: 7777 })
const session = await client.createSession({
query: "Help me fix a bug",
model: "claude-3.5-sonnet",
workingDir: "/path/to/project",
})
const sessions = await client.listSessions({ leafOnly: true })
Source: hld/sdk/typescript/src/client.ts, hld/api/handlers/server.go
End-to-End Testing
The HLD includes comprehensive e2e tests for the REST API. They run an isolated daemon instance against a throwaway SQLite database and exercise every endpoint.
make e2e-test # Run all 6 phases
make e2e-test-verbose # Extra logging
make e2e-test-manual # Pause for human-in-the-loop approval interaction
KEEP_TEST_ARTIFACTS=true make e2e-test # Preserve artifacts for debugging
The suite covers:
- All 16 REST API endpoints
- SSE event stream validation
- Approval workflows (deny → retry → approve)
- Session lifecycle operations
- Error handling
The tests live under hld/e2e/ and are split into test-rest-api.ts (six test phases) and test-utils.ts (test environment plumbing).
Source: hld/README.md
Common Failure Modes and Debugging
| Symptom | Likely cause | Where to look |
|---|---|---|
HLDClient cannot connect | Daemon not running, wrong port, or HTTP disabled | Check HUMANLAYER_DAEMON_HTTP_PORT and hld start |
| SSE stream keeps dropping | Reverse proxy buffering, or eventsource polyfill missing | Verify Content-Type: text/event-stream and no Content-Encoding rewrite |
Approval stuck in pending | External channel (Slack/email) not delivering, or wrong channel ID | Inspect approval.pending events on the bus and the CLI's contact_human config |
dangerouslySkipPermissions accepted when policy says it shouldn't | WUI does not yet respect deployment-level policy | Track issue #956; needs a launch-time policy check in session/manager.go |
| File diff looks wrong | Snapshot taken too late or toolId mismatch | Inspect file_snapshots table; ensure snapshot is recorded before the edit |
| WUI auto-scrolls on hover | UI hover handler in WUI is re-anchoring to block top | Track issue #944; pure UI fix, no daemon change needed |
| Archive flow takes 4 keystrokes | No CMD+C shortcut implemented in WUI | Track issue #905; one-keystroke archive is a thin wrapper over BulkArchive |
See Also
- HumanLayer CLI (
hlyr) — terminal companion, MCP, thoughts, andclaude init - TypeScript SDK (
@humanlayer/hld-sdk) — generated client for the REST + SSE surface - Go SDK for Claude Code (
claudecode-go) — embedded Claude Code driver used by the wrapper - WUI daemon types — typed surface the WUI consumes
- Community issues referenced on this page: #956 (bypass-permissions policy), #944 (auto-scroll on hover), #905 (one-keystroke archive)
Source: https://github.com/humanlayer/humanlayer / Human Manual
CodeLayer Desktop (humanlayer-wui)
Related topics: System Overview and Architecture, hld Daemon: Sessions, Approvals, MCP, and Storage, hlyr CLI, SDKs, Contracts, and Release Pipeline
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: System Overview and Architecture, hld Daemon: Sessions, Approvals, MCP, and Storage, hlyr CLI, SDKs, Contracts, and Release Pipeline
CodeLayer Desktop (humanlayer-wui)
Overview
CodeLayer Desktop is the open-source Tauri + React front-end for the HumanLayer daemon (hld). It is positioned in the README.md as a "Superhuman for Claude Code" — a keyboard-first IDE that orchestrates AI coding agents against complex codebases. The application wraps the Claude Code agent runtime, exposes session-level workflows, and pairs every UI with a locally-running daemon that brokers approvals, sessions, and events.
The desktop app lives under the humanlayer-wui/ directory in the monorepo. Per the humanlayer-wui/README.md, the WUI is built with Tauri (Rust shell) and React (renderer), and is intentionally designed to auto-launch its own daemon in development so the user "starts CodeLayer in development mode" without separate process management.
Goals
| Goal | Description | Source |
|---|---|---|
| Orchestrate coding agents | Drive one or more Claude Code sessions from a unified UI | README.md |
| Keyboard-first workflows | Replace mouse-heavy flows with hotkeys and command palettes | README.md |
| Multi-Claude parallel work | Run multiple Claude Code sessions in parallel, including across worktrees | README.md |
| Advanced context engineering | Apply battle-tested patterns when scaling agents to large repos | README.md |
| Auto-managed daemon | Start/stop the hld daemon transparently per git branch | humanlayer-wui/README.md |
Scope Boundaries
CodeLayer Desktop is the presentation and orchestration layer. It does not embed the LLM runtime itself; that responsibility is delegated to the Claude Code CLI invoked by the daemon. The WUI is responsible for:
- Rendering the session list, conversation stream, approval dialogs, and settings.
- Subscribing to Server-Sent Events (SSE) from the daemon for real-time updates.
- Providing a debug panel and lifecycle controls for the underlying daemon.
- Bundling and shipping the daemon and the
hlyrCLI as resources.
Source: https://github.com/humanlayer/humanlayer / Human Manual
hlyr CLI, SDKs, Contracts, and Release Pipeline
Related topics: System Overview and Architecture, hld Daemon: Sessions, Approvals, MCP, and Storage, CodeLayer Desktop (humanlayer-wui)
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: System Overview and Architecture, hld Daemon: Sessions, Approvals, MCP, and Storage, CodeLayer Desktop (humanlayer-wui)
hlyr CLI, SDKs, Contracts, and Release Pipeline
The HumanLayer project is composed of several interconnected surfaces: a Node-based command-line interface (hlyr), a Go SDK for Claude Code, an auto-generated TypeScript SDK, a desktop/web UI ("CodeLayer") built on Tauri + React, and a release pipeline that produces nightly, dev, and production builds. This page documents the public contracts, subcommands, configuration surfaces, and release mechanics that hold those surfaces together.
1. Repository Surface Map
The monorepo is organized into a small number of high-level components. The CLI (hlyr) is the connective tissue; the SDKs (TypeScript and Go) consume the same API surface; and the WUI (CodeLayer) is the desktop client.
graph TD
A[hlyr CLI<br/>Node/TypeScript] --> B[hld Daemon<br/>HTTP + SSE]
A --> C[Claude Code SDK<br/>Approval flow]
B --> D[TypeScript SDK<br/>@humanlayer/hld-sdk]
B --> E[Go SDK<br/>claudecode-go]
F[CodeLayer WUI<br/>Tauri + React] --> B
F --> G[claudecode-go<br/>embedded process]
H[Thoughts system<br/>hlyr thoughts *] --> I[Per-repo + Global notes]
A --> H
J[hack/linear CLI] --> K[Linear API]
L[Release Pipeline] --> A
L --> F| Component | Path | Purpose |
|---|---|---|
hlyr CLI | hlyr/ | Terminal entry point, MCP servers, thoughts management |
| TypeScript SDK | hld/sdk/typescript/ | Generated client for the hld daemon |
| Go SDK | claudecode-go/ | Programmatic Claude Code subprocess control |
| CodeLayer WUI | humanlayer-wui/ | Desktop client (Tauri + React + Zustand) |
| Linear CLI helper | hack/linear/ | Linear issue tracking from terminal |
| Thoughts system | hlyr/src/commands/thoughts/, hlyr/src/thoughtsConfig.ts | Per-repo + global notes with symlinks |
Source: hlyr/README.md, claudecode-go/README.md, hack/linear/README.md.
2. The `hlyr` CLI
hlyr is the developer-facing CLI. It is documented in hlyr/README.md and is designed to be runnable directly via npx humanlayer .... It exposes four top-level command groups: contact_human, mcp, thoughts, and claude.
2.1 Command Groups
| Command | Subcommands | Notes |
|---|---|---|
contact_human | -m, --message, --slack-channel, --email, --config-file | One-shot human-in-the-loop ping |
mcp | serve, claude_approvals, inspector serve, inspector claude_approvals | Model Context Protocol servers |
thoughts | init, sync, status, config, profile {create,list,show,delete} | Multi-profile notes system |
claude | init, init --all, init --force | Scaffolds .claude/ directory with commands/agents/settings |
Source: hlyr/README.md.
2.2 Contact Channel Resolution
The CLI resolves the contact destination through a layered configuration system. The order of precedence (most explicit wins) is:
- CLI flags (e.g.
--slack-channel C08G5C3V552) - Environment variables (
HUMANLAYER_SLACK_CHANNEL,HUMANLAYER_EMAIL_ADDRESS) - Config file passed via
--config-file(default schema:.hlyr.json) - Implicit fallback to the web UI
Example config-file shape:
{
"channel": {
"slack": {
"channel_or_user_id": "C08G5C3V552"
}
}
}
humanlayer contact_human --message "Review this pull request" --config-file .hlyr.json
Source: hlyr/README.md.
Note from the community: Customers running in regulated environments (see issue #956) have asked for a way to disallow the "Disable bypass permissions" option. The CLI/MCP approval surface is the integration point where such a policy would be enforced, since the claude_approvals MCP server is what consults humans before dangerous actions are taken. As of this writing, the README does not describe a hard-deny policy mode; teams that need it must either run the daemon in an isolated environment or filter inbound approval requests upstream.
2.3 MCP Server Surface
hlyr mcp exposes the daemon's human-in-the-loop and Claude Code approval capabilities to MCP-compatible clients (Claude Desktop, Claude Code SDK, etc.).
# Contact-human MCP server
humanlayer mcp serve
# Claude Code SDK approval integration
humanlayer mcp claude_approvals
# Debug with the MCP inspector
humanlayer mcp inspector serve
humanlayer mcp inspector claude_approvals
A typical mcp-config.json for Claude Code:
{
"mcpServers": {
"approvals": {
"command": "npx",
"args": ["-y", "humanlayer", "mcp", "claude_approvals"],
"env": {
"HUMANLAYER_API_KEY": "<YOUR_API_KEY>"
}
}
}
}
Source: hlyr/README.md.
3. The Thoughts System
The hlyr thoughts command group implements a per-repository + global notes system that is automatically synced via git hooks. It is the CLI's "second brain" surface, and it is the most configuration-heavy subsystem.
3.1 Profile Model
The thoughts system supports named profiles, each pointing at its own thoughts repository. This lets a single user maintain separate notes trees for personal projects, multiple clients, or different worktrees of the same repo.
graph TD
A[hlyr thoughts] --> B[Default profile]
A --> C[Profile: personal]
A --> D[Profile: client-acme]
B --> E[~/thoughts-default]
C --> F[~/thoughts-personal]
D --> G[~/thoughts-acme]
H[Repo: project-x] --> C
I[Repo: project-y] --> D| Command | Purpose |
|---|---|
thoughts init | Initialize thoughts for the current repo (default profile) |
thoughts init --profile <name> | Initialize using a specific profile |
thoughts profile create <name> | Create a new profile with optional --repo, --repos-dir, --global-dir |
thoughts profile list [--json] | List all profiles |
thoughts profile show <name> | Show one profile |
thoughts profile delete <name> [--force] | Delete a profile |
thoughts sync -m "msg" | Commit and push notes |
thoughts status | Show active profile + sync status |
thoughts config | Show full resolved configuration |
Source: hlyr/README.md, hlyr/src/commands/thoughts/init.ts.
3.2 Directory Layout
The directory structure created by thoughts init is:
<thoughtsRepo>/<reposDir>/<repoName>/<user>/ # repo-specific personal notes
<thoughtsRepo>/<reposDir>/<repoName>/shared/ # repo-specific team notes
<thoughtsRepo>/<globalDir>/<user>/ # cross-repo personal notes
<thoughtsRepo>/<globalDir>/shared/ # cross-repo team notes
<thoughtsRepo>/<reposDir>/<repoName>/searchable/ # hard links for search tools
A README.md is auto-generated in both the repo-specific and global directories. The searchable/ directory uses hard links to originals, so editing either path mutates both — but the docs explicitly direct users to reference files by their canonical path (e.g. thoughts/<user>/todo.md), not via searchable/.
Source: hlyr/src/commands/thoughts/init.ts.
3.3 Symlink and Overload Behavior
hlyr/src/thoughtsConfig.ts defines overloaded signatures for both createThoughtsDirectoryStructure and updateSymlinksForNewUsers, supporting both a legacy positional argument shape and a newer (config, repoName, user) shape. This dual API is the in-tree evidence of a "backward compatible" refactor — the README claims the same.
| Function | Legacy Signature | New Signature |
|---|---|---|
createThoughtsDirectoryStructure | (thoughtsRepo, reposDir, globalDir, repoName, user) | (config: ResolvedProfileConfig, repoName, user) |
updateSymlinksForNewUsers | (currentRepoPath, thoughtsRepo, reposDir, repoName, currentUser) | (currentRepoPath, config, repoName, currentUser) |
Source: hlyr/src/thoughtsConfig.ts.
4. SDKs and Contracts
The two first-party SDKs — TypeScript and Go — share a common conceptual model: sessions, approvals, MCP servers, and events. The TypeScript SDK is auto-generated from the daemon's OpenAPI spec; the Go SDK is a hand-written wrapper around the Claude Code subprocess.
4.1 TypeScript SDK (`@humanlayer/hld-sdk`)
The TS SDK is published as @humanlayer/hld-sdk (via a file:../hld/sdk/typescript path in the WUI's package.json). It exposes a single HLDClient class with multiple sub-clients.
#### 4.1.1 Client Surface
| Sub-client | Backing API | Source |
|---|---|---|
sessionsApi | SessionsApi | hld/sdk/typescript/src/client.ts |
approvalsApi | ApprovalsApi | same |
settingsApi | SettingsApi | same |
filesApi | FilesApi | same |
agentsApi | AgentsApi | same |
systemApi | SystemApi | same |
#### 4.1.2 Constructor Options
new HLDClient({
baseUrl?: string,
port?: number,
headers?: Record<string, string>,
onFetchError?: (error: Error, ctx: { url: string; method?: string }) => void,
})
#### 4.1.3 SSE Event Handling
HLDClient maintains a Map<string, EventSourceLike> of Server-Sent Events connections, abstracted through a unified EventSourceLike interface so it works in both browser and polyfill environments. Handlers are passed in via the SSEEventHandlers interface:
interface SSEEventHandlers {
onMessage?: (event: any) => void
onError?: (error: Error) => void
onConnect?: () => void
onDisconnect?: () => void
}
Source: hld/sdk/typescript/src/client.ts.
#### 4.1.4 Generated Models
The SDK ships a large set of generated models. Two of the most central are Approval and MCPServer.
Approval contract (selected fields):
| Field | Type | Notes |
|---|---|---|
id | string | Required |
runId | string | Required |
sessionId | string | Required |
status | ApprovalStatus | Required |
createdAt | Date | Required |
respondedAt | Date | Optional |
toolName | string | Required |
toolInput | { [key: string]: any } | Required |
comment | string | Optional |
Source: hld/sdk/typescript/src/generated/models/Approval.ts.
MCPServer contract (selected fields):
| Field | Type | Notes |
|---|---|---|
type | string | e.g. stdio, http |
command | string | For stdio servers |
args | Array<string> | For stdio servers |
env | { [key: string]: string } | For stdio servers |
url | string | For HTTP servers |
headers | { [key: string]: string } | For HTTP servers |
Source: hld/sdk/typescript/src/generated/models/MCPServer.ts.
4.2 Go SDK (`claudecode-go`)
The Go SDK is a programmatic wrapper around the Claude Code CLI subprocess. It is intentionally minimal: it spawns Claude, captures its output, and exposes typed result/error shapes.
#### 4.2.1 Configuration
type SessionConfig struct {
// Core
Query string
SessionID string // Resume existing session
// Model
Model Model // ModelOpus, ModelSonnet, or ModelHaiku
// Output
OutputFormat OutputFormat
// MCP
MCPConfig *MCPConfig
PermissionPromptTool string
// Control
MaxTurns int
WorkingDir string
SystemPrompt string
AppendSystemPrompt string
AllowedTools []string
DisallowedTools []string
Verbose bool
}
#### 4.2.2 Output Formats
| Format | Description |
|---|---|
OutputText | Plain text output (default) |
OutputJSON | Structured JSON with metadata |
OutputStreamJSON | Real-time streaming JSON events |
#### 4.2.3 Error Handling
result, err := client.LaunchAndWait(config)
if err != nil {
// Handle launch/execution errors
log.Fatal(err)
}
if result.IsError {
// Handle Claude-reported errors
fmt.Printf("Error: %s\n", result.Error)
}
Source: claudecode-go/README.md.
4.3 Daemon Event Contracts (WUI side)
The WUI's humanlayer-wui/src/lib/daemon/types.ts defines the event payloads exchanged with the daemon. The shape of these events is what the SDKs and WUI agree on as the "wire contract".
| Event | Key fields | Purpose |
|---|---|---|
NewApprovalEventData | approval_id, session_id, tool_name | A new approval has been requested |
ApprovalResolvedEventData | approval_id, session_id, decision | An approval was answered |
SessionStatusChangedEventData | session_id, old_status, new_status | Session lifecycle transitions |
SessionSettingsChangedEventData | session_id, auto_accept_edits, dangerously_skip_permissions, dangerously_skip_permissions_timeout_ms, reason, expired_at | Dangerous skip settings changed |
The SessionSettingsChangeReason constant currently exposes a single value — EXPIRED: 'expired' — used when the "dangerous skip permissions" window times out. This is the precise mechanism referenced by the community request in issue #956: today the system can *expire* the dangerous-skip window, but it does not yet support a *policy-deny* mode where the option is never offered.
Source: humanlayer-wui/src/lib/daemon/types.ts.
5. CodeLayer Desktop App
The humanlayer-wui package is a Tauri 2 desktop application wrapping a React 19 frontend. It is the surface that consumes the SDKs at runtime.
5.1 Stack
| Layer | Technology |
|---|---|
| Shell | Tauri 2 (@tauri-apps/cli ^2) |
| UI | React 19, Vite, Tailwind 4 |
| State | Zustand 5 (with per-slice stores under src/stores/) |
| Editor | Tiptap 3 (with lowlight for code highlighting) |
| Routing | react-router-dom 7.6.3 |
| Telemetry | posthog-js 1.279.3 |
| Search/keyboard | cmdk, react-hotkeys-hook, fuzzy |
| Test | bun test (Bun runtime) |
| Storybook | v9.1.5 |
Source: humanlayer-wui/package.json.
5.2 State Management
The demo-store README describes the canonical pattern: keep slices focused, use TypeScript strictly, test first, document sequences, and handle edge cases. Two patterns are documented as "common":
// Conditional state updates
const updateIfFocused = (id: string, updates: Partial<SessionInfo>) => {
const { focusedSession, updateSession, setFocusedSession } = store.getState()
updateSession(id, updates)
if (focusedSession?.id === id) {
setFocusedSession({ ...focusedSession, ...updates })
}
}
// Workflow actions
const completeApproval = (approvalId: string) => {
const { removeApproval, sessions, updateSession } = store.getState()
removeApproval(approvalId)
const session = sessions.find(s => s.status === SessionStatus.WaitingInput)
if (session) updateSession(session.id, { status: SessionStatus.Running })
}
Source: humanlayer-wui/src/stores/demo/README.md.
6. Release Pipeline
CodeLayer ships three release tracks that share the same codebase but use different identity, store paths, and update channels. The orchestration lives in the Tauri shell.
6.1 Store Path Resolution
The Rust helper get_store_path in humanlayer-wui/src-tauri/src/lib.rs is the single source of truth for which on-disk store file a given build writes to:
fn get_store_path(is_dev: bool, branch_id: Option<&str>, is_nightly: bool) -> PathBuf {
let home = dirs::home_dir().expect("Failed to get home directory");
let humanlayer_dir = home.join(".humanlayer");
if is_dev {
if let Some(branch) = branch_id {
humanlayer_dir.join(format!("codelayer-{branch}.json"))
} else {
humanlayer_dir.join("codelayer-dev.json")
}
} else if is_nightly {
humanlayer_dir.join("codelayer-nightly.json")
} else {
humanlayer_dir.join("codelayer.json")
}
}
The branch identifier is derived from the environment, with the ticket-id slugging logic visible in the surrounding code (sanitizing characters and falling back to the literal branch name, or "production" / "dev" if no branch is detectable).
6.2 Build Matrix
| Build | Identifier contains "nightly"? | Store file | Use case |
|---|---|---|---|
| Production | No | ~/.humanlayer/codelayer.json | Stable releases |
| Nightly | Yes | ~/.humanlayer/codelayer-nightly.json | Cutting-edge previews |
| Dev (default) | No + is_dev=true | ~/.humanlayer/codelayer-dev.json | Local development |
| Dev (branch) | No + is_dev=true + branch_id=Some(...) | ~/.humanlayer/codelayer-<branch>.json | Worktree-isolated dev |
Source: humanlayer-wui/src-tauri/src/lib.rs.
6.3 Daemon Lifecycle
The start_daemon Tauri command in lib.rs is the entry point for spinning up the local hld daemon from the desktop app. It takes is_dev and an optional branch_override, starts the daemon via the DaemonManager, then writes the resolved DaemonInfo (including branch_id) to the appropriate store path.
#[tauri::command]
async fn start_daemon(
app_handle: tauri::AppHandle,
daemon_manager: State<'_, DaemonManager>,
is_dev: bool,
branch_override: Option<String>,
) -> Result<DaemonInfo, String> { /* ... */ }
Source: humanlayer-wui/src-tauri/src/lib.rs.
6.4 Nightly Distribution
The latest nightly artifact described in the community context is codelayer-0.1.0-nightly-20260227142452, distributed via two channels:
``bash brew tap humanlayer/humanlayer brew install --cask codelayer-nightly ``
- Homebrew (recommended):
- Manual: Download the DMG, open it, and drag to Applications.
Each nightly build is explicitly flagged as potentially containing unstable features.
6.5 Release Flow Diagram
graph TD
A[Commit to main] --> B[CI Build]
B --> C{Channel}
C -->|production tag| D[codelayer.json]
C -->|nightly schedule| E[codelayer-nightly.json]
F[Local dev] --> G{is_dev?}
G -->|yes, branch X| H[codelayer-X.json]
G -->|yes, no branch| I[codelayer-dev.json]
G -->|no| J[uses release store]
D --> K[User's ~/.humanlayer/]
E --> K
H --> K
I --> K
J --> K7. `hack/linear` — Companion CLI
hack/linear is a small companion CLI for Linear issue tracking. It is shipped alongside the rest of the repo as a developer utility, and it follows the same "ship a thin shell wrapper + a TypeScript implementation" pattern as hlyr.
| Subcommand | Behavior |
|---|---|
list-issues | List active assigned issues (excludes done/canceled) |
get-issue [ENG-XXXX] | Show an issue; auto-detects ID from current git branch |
add-comment "<msg>" | Adds a comment; auto-detects issue from branch |
fetch-images ENG-XXXX | Downloads issue images to the local thoughts dir |
Shell completions are provided for fish, zsh, and bash. The recommended CLAUDE.md snippet is:
## Linear
When asked to fetch a Linear ticket, use the globally installed Linear CLI: `linear get-issue ENG-XXXX > thoughts/shared/tickets/eng-XXXX.md`
Source: hack/linear/README.md.
8. Cross-Cutting Concerns
8.1 Authentication and API Keys
HUMANLAYER_API_KEY is the single credential required across the CLI, the MCP servers, and the SDK consumers. The CLI also reads channel-specific variables (HUMANLAYER_SLACK_CHANNEL, HUMANLAYER_EMAIL_ADDRESS) but those are routing, not authentication.
Source: hlyr/README.md.
8.2 MCP and Approval Flow
The end-to-end approval flow is the most security-sensitive path in the system. It is implemented as a relay between the Claude Code subprocess, the local hld daemon, the hlyr mcp claude_approvals MCP server, and (optionally) a human in Slack/email/web.
graph LR
A[Claude Code subprocess] --> B[hld daemon]
B --> C[hlyr mcp claude_approvals]
C --> D{Contact channel}
D -->|Slack| E[Human in Slack]
D -->|Email| F[Human in Email]
D -->|Web UI| G[Human in WUI]
E --> B
F --> B
G --> B
B --> AThis is the surface that community issue #956 wants hardened: enterprise customers need a way to forbid the "Disable bypass permissions" option entirely, so that the dangerously_skip_permissions flow can never be enabled regardless of who clicks what in the UI. As of the source files reviewed, the SDK and daemon contract distinguish only between "enabled" and "expired" — they do not yet express a "policy-denied" state.
8.3 Common Failure Modes
| Symptom | Likely cause | Reference |
|---|---|---|
hlyr does not contact a channel | Missing or misnamed env var; config file not passed via --config-file | hlyr/README.md |
claude init exits with no action | Non-TTY environment without --all | hlyr/README.md |
| Thoughts hard links appear stale | Forgot to run thoughts sync; remember searchable/ is just a hard-link mirror | hlyr/src/commands/thoughts/init.ts |
| Linear CLI hangs on no API key | Set LINEAR_API_KEY; help/completion work without it | hack/linear/README.md |
| Auto-scroll feels "weird" in CodeLayer | Issue #944 — UI feedback under review | Community context |
| Archiving a session is multi-step | Issue #905 — community wants CMD+C shortcut equivalent to Claude Code's /clear | Community context |
| Dev store conflicts across worktrees | Each branch now has its own codelayer-<branch>.json automatically | humanlayer-wui/src-tauri/src/lib.rs |
See Also
- hld Daemon — the HTTP/SSE service that all surfaces ultimately talk to
- CodeLayer WUI Architecture — Tauri + React + Zustand deep dive
- MCP Approval Protocol — contract details for
claude_approvals - Thoughts System Deep Dive — profile, symlink, and hard-link semantics
- Claude Code SDK Reference — Go SDK for subprocess control
Source: https://github.com/humanlayer/humanlayer / Human Manual
Doramagic Pitfall Log
Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
Doramagic Pitfall Log
Found 11 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.
1. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/humanlayer/humanlayer/issues/981
2. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/humanlayer/humanlayer/issues/994
3. Configuration risk: Configuration risk requires verification
- Severity: medium
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: capability.host_targets | github_repo:838542536 | https://github.com/humanlayer/humanlayer
4. Capability evidence risk: Capability evidence risk requires verification
- Severity: medium
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: capability.assumptions | github_repo:838542536 | https://github.com/humanlayer/humanlayer
5. Maintenance risk: Maintenance risk requires verification
- Severity: medium
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | github_repo:838542536 | https://github.com/humanlayer/humanlayer
6. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: downstream_validation.risk_items | github_repo:838542536 | https://github.com/humanlayer/humanlayer
7. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: risks.scoring_risks | github_repo:838542536 | https://github.com/humanlayer/humanlayer
8. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/humanlayer/humanlayer/issues/959
9. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/humanlayer/humanlayer/issues/983
10. Maintenance risk: Maintenance risk requires verification
- Severity: low
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | github_repo:838542536 | https://github.com/humanlayer/humanlayer
11. Maintenance risk: Maintenance risk requires verification
- Severity: low
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | github_repo:838542536 | https://github.com/humanlayer/humanlayer
Source: Doramagic discovery, validation, and Project Pack records
Community Discussion Evidence
These external discussion links are review inputs, not standalone proof that the project is production-ready.
Count of project-level external discussion links exposed on this manual page.
Open the linked issues or discussions before treating the pack as ready for your environment.
Community Discussion Evidence
Doramagic exposes project-level community discussion separately from official documentation. Review these links before using humanlayer with real data or production workflows.
- humanlayer thoughts init is unusable in non-TTY shells (agents/CI): per- - github / github_issue
- [[Feature]: Allow agents to create triage tickets, similar to how agents](https://github.com/humanlayer/humanlayer/issues/987) - github / github_issue
- [[Feature]: Riptide - Expose a local HTTP API for external tool integrati](https://github.com/humanlayer/humanlayer/issues/959) - github / github_issue
- [[Feature]: support commands in ~/.claude](https://github.com/humanlayer/humanlayer/issues/927) - github / github_issue
- [[Feature]: Fuzzy Finder](https://github.com/humanlayer/humanlayer/issues/986) - github / github_issue
- [[Feature]: multi org connection](https://github.com/humanlayer/humanlayer/issues/983) - github / github_issue
- [[Bug]: The first auto-started
create-research-questionssession that r](https://github.com/humanlayer/humanlayer/issues/981) - github / github_issue - [[Feature]: Jump to bottom of conversation](https://github.com/humanlayer/humanlayer/issues/978) - github / github_issue
- codelayer-0.1.0-nightly-20260227142452 - github / github_release
- Configuration risk requires verification - GitHub / issue
Source: Project Pack community evidence and pitfall evidence