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

Section Related Pages

Continue reading this section for the full explanation and source context.

Section API Surface

Continue reading this section for the full explanation and source context.

Section Real-Time Event Stream

Continue reading this section for the full explanation and source context.

Section Core Data Models

Continue reading this section for the full explanation and source context.

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| User

The 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.

PathTypeResponsibility
humanlayer-wui/Vite + React 19 + Tauri appDesktop-class UI for CodeLayer (humanlayer-wui/package.json).
hld/Daemon (Go)Hosts sessions, approvals, files, MCP and emits SSE events.
hld/sdk/typescript/Generated SDKTyped HTTP + SSE client used by the UI (hld/sdk/typescript/src/client.ts).
hlyr/Node CLIcontact_human, claude init, thoughts subcommands (hlyr/README.md).
apps/react/Standalone React appGeneric Vite/React entry point (apps/react/src/frontend.tsx).
hack/linear/Utility CLILinear issue tracker integration (hack/linear/README.md).
humanlayer-wui/src/lib/daemon/types.tsShared typesUI-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:

APIPurposeNotes
SessionsApiCreate, list, continue, archive sessionsPrimary interaction surface for CodeLayer.
ApprovalsApiList, fetch, respond to pending approvalsDrives the human-in-the-loop flow.
SystemApiHealth and capability discoveryUsed by the UI on startup.
SettingsApiUser and daemon configurationIncludes UserSettingsResponse and UpdateUserSettingsRequest.
FilesApiCreate directories, fuzzy-search filesPowers command palette and @-mentions (hld/sdk/typescript/src/generated/apis/FilesApi.ts).
AgentsApiDiscover Claude Code agents and sub-agentsIncludes 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: SessionStatusChangedEventData carries old_status and new_status so the UI can animate transitions deterministically.
  • Approvals: NewApprovalEventData (and its older alias ApprovalRequestedEventData) signals that a tool call is awaiting human input, and ApprovalResolvedEventData carries the Decision back to the daemon.
  • Settings changes: SessionSettingsChangedEventData reports mutations to auto_accept_edits, dangerously_skip_permissions, and the timeout. A SessionSettingsChangeReason.EXPIRED value 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.

ModelKey FieldsNotes
ConversationEventeventType, role, toolName, toolResultContent, isCompleted, approvalStatus, approvalIdeventType is one of message, tool_call, tool_result, system, thinking (hld/sdk/typescript/src/generated/models/ConversationEvent.ts).
Approvalid, runId, sessionId, status, createdAt, respondedAt, toolName, toolInput, commentstatus transitions through pending, approved, denied, resolved (hld/sdk/typescript/src/generated/models/Approval.ts).
MCPServertype, command, args, env, url, headersCovers 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

ConcernLibrary / Tool
FrameworkReact 19 (^19.1.0) with React Router 7.
BuildVite + Tauri 2.
StylingTailwind CSS 4, tailwind-merge, class-variance-authority.
StateZustand 5 (with documented slice patterns).
EditorTipTap 3 (with lowlight for code highlighting, react-syntax-highlighter).
UX primitivesRadix UI (checkbox, dialog, dropdown, popover, scroll-area, select, slot, collapsible, label).
Telemetryposthog-js with a custom sanitizer.
Notificationssonner.
Command palettecmdk.
Hotkeysreact-hotkeys-hook.
TestingBun 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_permissions and a dangerously_skip_permissions_timeout_ms per session, and emits a SessionSettingsChangeReason.EXPIRED event 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 ConversationEvent stream; it lives in the renderer that maps eventType to the rendered block.
  • Issue #905 asks for a CMD+C shortcut 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 existing archive + create API 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

SubcommandDescription
contact_humanSends 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 initCopies Claude Code commands, agents, and settings into a project's .claude/ directory. Supports --all (non-interactive) and --force.
thoughtsManages a developer-notes repository (per-project and global), with profile support: thoughts profile create / list / show / delete.
MCP server modeRuns 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 --> L

Source: 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:

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:

  1. New hlyr subcommands follow the pattern of grouping under a top-level verb (e.g. thoughts, claude, contact_human). New thoughts features land alongside thoughtsConfig.ts, which already models the ResolvedProfileConfig and symlink-update logic for multi-profile setups (hlyr/src/thoughtsConfig.ts).
  2. New SDK API groups should be added as both a generated apis/*Api.ts and a corresponding *Api field on the HLDClient class in hld/sdk/typescript/src/client.ts. The existing six groups (Sessions, Approvals, System, Settings, Files, Agents) set the convention for argument shapes, method prefixes (*Raw for runtime.ApiResponse<T>), and JS doc summaries.

Common Failure Modes and Troubleshooting

SymptomLikely CauseWhere to Look
SSE stream stalls after the laptop sleepsThe EventSourceLike needs a manual reconnect; UI depends on the SDK's onDisconnect handler firinghld/sdk/typescript/src/client.ts
Tool call "hangs" without surfacing in the UIAn Approval is still in pending state; check ApprovalsApi.listApprovalshld/sdk/typescript/src/generated/models/Approval.ts
"Dangerous skip permissions" toggle stops working mid-sessionDaemon emitted SessionSettingsChangeReason.EXPIREDhumanlayer-wui/src/lib/daemon/types.ts
humanlayer thoughts writes to the wrong repoProfile resolution; verify thoughts profile list and thoughts confighlyr/README.md
humanlayer claude init errors in CIThe command requires a TTY unless --all is passedhlyr/README.md
PostHog events appear empty in dashboardsSanitizer stripped the keys; check console.warn output from sanitizeEventPropertieshumanlayer-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

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

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Session Lifecycle

Continue reading this section for the full explanation and source context.

Section Session Manager

Continue reading this section for the full explanation and source context.

Section Claude Code Wrapper

Continue reading this section for the full explanation and source context.

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 --> AM

Key responsibilities of each subsystem

SubsystemFileResponsibility
Entrypointhld/cmd/hld/main.goParse flags, load config, wire the daemon together, signal handling
Daemon lifecyclehld/daemon/daemon.goLong-running supervisor that owns all managers and graceful shutdown
Session managementhld/session/manager.goCreate / continue / interrupt / archive Claude Code sessions
Claude Code integrationhld/session/claudecode_wrapper.goSpawns and tracks the claude subprocess, streams output back
Permission monitorhld/session/permission_monitor.goWatches tool calls and decides when human approval is required
Approvalshld/approval/manager.goLifecycle of approval requests: pending → approved/denied, with retries
MCPhld/mcp/server.goExposes request_approval and friends to the agent via MCP
Storagehld/store/sqlite.goPersistent store for sessions, approvals, file snapshots, settings
Event bushld/bus/events.goPub/sub channel that all managers publish to and that SSE consumers subscribe from
RPC transporthld/rpc/server.goJSON-RPC endpoint used by the CLI and SDK
REST transporthld/api/handlers/server.goHTTP handlers generated from the OpenAPI spec
API contracthld/api/openapi.yamlSource 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.

VariableDefaultPurpose
HUMANLAYER_DAEMON_HTTP_PORT7777TCP port for the REST + SSE server. Set to 0 to disable HTTP.
HUMANLAYER_DAEMON_HTTP_HOST127.0.0.1Bind 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 SessionStatus transitions 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:

FieldTypeDescription
idstringDaemon-internal approval identifier
runIdstringRun the approval belongs to
sessionIdstringSession the approval belongs to
statusApprovalStatus enumpending, approved, denied, etc.
createdAtDate (ISO 8601)When the request was created
respondedAtDate?When the human responded
toolNamestringTool the agent is calling
toolInputobjectJSON input parameters to the tool
commentstring?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 → resolved contract 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):

TablePurposeKey columns
sessionsOne row per session + versioned runid, run_id, claude_session_id, parent_session_id, status, working_dir, model, created_at, archived_at
approvalsPending and historical approvalsid, run_id, session_id, status, tool_name, tool_input (JSON), comment, created_at, responded_at
file_snapshotsPer-tool pre-edit snapshots used for diff/undotool_id, file_path, content, created_at
settingsUser config and per-deployment policykey/value
events (optional cache)Optional durable event log feeding SSE replayderived 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-APIResponsibility
SessionsApiCreate, continue, list, archive, interrupt sessions
ApprovalsApiList, fetch, and decide approvals
SystemApiHealth, version, daemon info
SettingsApiRead and update user/deployment settings
FilesApiRecent paths, fuzzy file search, directory validation/creation
AgentsApiDiscover 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

SymptomLikely causeWhere to look
HLDClient cannot connectDaemon not running, wrong port, or HTTP disabledCheck HUMANLAYER_DAEMON_HTTP_PORT and hld start
SSE stream keeps droppingReverse proxy buffering, or eventsource polyfill missingVerify Content-Type: text/event-stream and no Content-Encoding rewrite
Approval stuck in pendingExternal channel (Slack/email) not delivering, or wrong channel IDInspect approval.pending events on the bus and the CLI's contact_human config
dangerouslySkipPermissions accepted when policy says it shouldn'tWUI does not yet respect deployment-level policyTrack issue #956; needs a launch-time policy check in session/manager.go
File diff looks wrongSnapshot taken too late or toolId mismatchInspect file_snapshots table; ensure snapshot is recorded before the edit
WUI auto-scrolls on hoverUI hover handler in WUI is re-anchoring to block topTrack issue #944; pure UI fix, no daemon change needed
Archive flow takes 4 keystrokesNo CMD+C shortcut implemented in WUITrack issue #905; one-keystroke archive is a thin wrapper over BulkArchive

See Also

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

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Goals

Continue reading this section for the full explanation and source context.

Section Scope Boundaries

Continue reading this section for the full explanation and source context.

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

GoalDescriptionSource
Orchestrate coding agentsDrive one or more Claude Code sessions from a unified UIREADME.md
Keyboard-first workflowsReplace mouse-heavy flows with hotkeys and command palettesREADME.md
Multi-Claude parallel workRun multiple Claude Code sessions in parallel, including across worktreesREADME.md
Advanced context engineeringApply battle-tested patterns when scaling agents to large reposREADME.md
Auto-managed daemonStart/stop the hld daemon transparently per git branchhumanlayer-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 hlyr CLI 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)

Section Related Pages

Continue reading this section for the full explanation and source context.

Section 2.1 Command Groups

Continue reading this section for the full explanation and source context.

Section 2.2 Contact Channel Resolution

Continue reading this section for the full explanation and source context.

Section 2.3 MCP Server Surface

Continue reading this section for the full explanation and source context.

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
ComponentPathPurpose
hlyr CLIhlyr/Terminal entry point, MCP servers, thoughts management
TypeScript SDKhld/sdk/typescript/Generated client for the hld daemon
Go SDKclaudecode-go/Programmatic Claude Code subprocess control
CodeLayer WUIhumanlayer-wui/Desktop client (Tauri + React + Zustand)
Linear CLI helperhack/linear/Linear issue tracking from terminal
Thoughts systemhlyr/src/commands/thoughts/, hlyr/src/thoughtsConfig.tsPer-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

CommandSubcommandsNotes
contact_human-m, --message, --slack-channel, --email, --config-fileOne-shot human-in-the-loop ping
mcpserve, claude_approvals, inspector serve, inspector claude_approvalsModel Context Protocol servers
thoughtsinit, sync, status, config, profile {create,list,show,delete}Multi-profile notes system
claudeinit, init --all, init --forceScaffolds .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:

  1. CLI flags (e.g. --slack-channel C08G5C3V552)
  2. Environment variables (HUMANLAYER_SLACK_CHANNEL, HUMANLAYER_EMAIL_ADDRESS)
  3. Config file passed via --config-file (default schema: .hlyr.json)
  4. 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
CommandPurpose
thoughts initInitialize 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 statusShow active profile + sync status
thoughts configShow 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.

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.

FunctionLegacy SignatureNew 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-clientBacking APISource
sessionsApiSessionsApihld/sdk/typescript/src/client.ts
approvalsApiApprovalsApisame
settingsApiSettingsApisame
filesApiFilesApisame
agentsApiAgentsApisame
systemApiSystemApisame

#### 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):

FieldTypeNotes
idstringRequired
runIdstringRequired
sessionIdstringRequired
statusApprovalStatusRequired
createdAtDateRequired
respondedAtDateOptional
toolNamestringRequired
toolInput{ [key: string]: any }Required
commentstringOptional

Source: hld/sdk/typescript/src/generated/models/Approval.ts.

MCPServer contract (selected fields):

FieldTypeNotes
typestringe.g. stdio, http
commandstringFor stdio servers
argsArray<string>For stdio servers
env{ [key: string]: string }For stdio servers
urlstringFor 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

FormatDescription
OutputTextPlain text output (default)
OutputJSONStructured JSON with metadata
OutputStreamJSONReal-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".

EventKey fieldsPurpose
NewApprovalEventDataapproval_id, session_id, tool_nameA new approval has been requested
ApprovalResolvedEventDataapproval_id, session_id, decisionAn approval was answered
SessionStatusChangedEventDatasession_id, old_status, new_statusSession lifecycle transitions
SessionSettingsChangedEventDatasession_id, auto_accept_edits, dangerously_skip_permissions, dangerously_skip_permissions_timeout_ms, reason, expired_atDangerous 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

LayerTechnology
ShellTauri 2 (@tauri-apps/cli ^2)
UIReact 19, Vite, Tailwind 4
StateZustand 5 (with per-slice stores under src/stores/)
EditorTiptap 3 (with lowlight for code highlighting)
Routingreact-router-dom 7.6.3
Telemetryposthog-js 1.279.3
Search/keyboardcmdk, react-hotkeys-hook, fuzzy
Testbun test (Bun runtime)
Storybookv9.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

BuildIdentifier contains "nightly"?Store fileUse case
ProductionNo~/.humanlayer/codelayer.jsonStable releases
NightlyYes~/.humanlayer/codelayer-nightly.jsonCutting-edge previews
Dev (default)No + is_dev=true~/.humanlayer/codelayer-dev.jsonLocal development
Dev (branch)No + is_dev=true + branch_id=Some(...)~/.humanlayer/codelayer-<branch>.jsonWorktree-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 --> K

7. `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.

SubcommandBehavior
list-issuesList 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-XXXXDownloads 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 --> A

This 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

SymptomLikely causeReference
hlyr does not contact a channelMissing or misnamed env var; config file not passed via --config-filehlyr/README.md
claude init exits with no actionNon-TTY environment without --allhlyr/README.md
Thoughts hard links appear staleForgot to run thoughts sync; remember searchable/ is just a hard-link mirrorhlyr/src/commands/thoughts/init.ts
Linear CLI hangs on no API keySet LINEAR_API_KEY; help/completion work without ithack/linear/README.md
Auto-scroll feels "weird" in CodeLayerIssue #944 — UI feedback under reviewCommunity context
Archiving a session is multi-stepIssue #905 — community wants CMD+C shortcut equivalent to Claude Code's /clearCommunity context
Dev store conflicts across worktreesEach branch now has its own codelayer-<branch>.json automaticallyhumanlayer-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.

medium Installation risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Installation risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Configuration risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Capability evidence risk requires verification

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.

Sources 10

Count of project-level external discussion links exposed on this manual page.

Use Review before install

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-questions session 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