Claude profiles and client sessions¶
The Claude launcher provides a Python management library and pdum-claude CLI.
The official TypeScript Agent SDK remains in the browser or Node client. Each
connected client controls its own native Claude worker; several workers can share
a profile. Disconnect ends the worker, while its saved conversation remains on disk.
This is a new, unreleased package. See the specification, delivery plan and qualification report. Browser and Node compatibility have each passed live checks against the Python host. The 2026-10-13 checkpoint records the stopping point and the prioritized work to pick up next.
Setup and authentication¶
From the repository root, ./scripts/setup.sh installs the workspace and optional
adapters. Standalone installation will use
habemus-papadum-claude-launcher[management] after publication. Install/select the
native claude executable separately; the launcher uses that explicit selection,
not the Python SDK's bundled binary. The Python SDK dependency supplies public
saved-history functions.
uv run pdum-claude profile create research --workspace /path/to/project --auth native
uv run pdum-claude --profile research auth login
uv run pdum-claude --profile research auth status
uv run pdum-claude --profile research launch
Creation uses a Rich preview and Questionary selectors when attached to a terminal.
--no-interview is deterministic for scripts. Canceling an interview does not write
a profile or start login. --login explicitly starts native login after saving.
Use --profile-dir PATH instead of a name to select a directory; --profiles-dir
changes the root for named profiles. profile list --json and profile show return
metadata without resolving credentials.
| Authentication | Profile creation option | Behavior |
|---|---|---|
| Dedicated Claude account | --auth native |
auth login runs claude auth login --claudeai in the profile environment. Browser/code entry stays in the host terminal's native flow. |
| API key | --auth api-key --api-key-env MY_ANTHROPIC_KEY |
Resolve that environment variable when a worker starts; persist only its name. |
| Existing login reuse | --auth reuse-login |
Read an existing access token at launch, inject it into this worker, and do not modify or refresh the source. |
On macOS, default login reuse reads the ordinary Claude Keychain entry; otherwise
it reads the ordinary Claude credential file. --source-directory selects a native
credential-file directory explicitly. A custom directory's hashed Keychain service
is not reverse-engineered. Authentication status distinguishes native presence from
a successful model request; expired borrowed tokens require renewing the source
login. API keys, account login and provider federation are distinct strategies.
Bedrock and federation adapters are not yet implemented.
Native Claude documents directory-associated Keychain credentials for Claude-account login. Console keyless sign-in has different storage semantics, so the initial login command deliberately selects Claude-account login. Dedicated-profile login and a subsequent live Node SDK turn have passed; credential refresh remains unqualified. Native credential management
Profile configuration¶
Each profile contains profile.json for launcher-owned choices, claude/ as its
native CLAUDE_CONFIG_DIR, and anthropic/ as its ANTHROPIC_CONFIG_DIR.
Native claude/settings.json, agents, commands and other configuration remain
native. --native-settings PATH copies a settings file byte-for-byte, including
unknown fields. Broader selective imports and an existing-profile configuration
interview are not implemented yet.
--setting-sources user,project is the creation default. Project settings are
deliberately shared by workers using that workspace; --setting-sources user
selects only profile user settings. This prevents accidental config collisions,
not host-policy enforcement or filesystem sandboxing. Native fixture tests verify
separate user agents, commands, skills, instructions, plugins and MCP configuration;
selected project configuration is shared. local must be selected explicitly to
include .claude/settings.local.json and CLAUDE.local.md. See the
isolation report for tested behavior and limits,
including managed policy and authenticated customization syncing.
Credentials never go to browser clients.
Temporary work is available through launch --temp --workspace PATH. Its default
auth is reuse-login, with a concise warning. --auth api-key or --auth native
selects another strategy. Temporary profiles are removed after the foreground
manager and workers stop; use a named profile when saved history should survive.
Launch and management¶
The foreground CLI listens on 0.0.0.0:8765 by default. Override --host and
--port as needed; --port 0 selects an available port and prints the actual
endpoint. launch --all-profiles registers all profiles under the selected
root; one selected profile is sufficient for multiple concurrent clients. Workers
start only when their allocated WebSocket is attached. Closing the SDK, losing the
connection, explicit stop or manager shutdown ends the owned worker. There is no
arbitrary idle expiry, durable worker recovery or automatic prompt replay.
uv run pdum-claude status --endpoint http://127.0.0.1:8765
uv run pdum-claude stop WORKER_ID --endpoint http://127.0.0.1:8765
uv run pdum-claude --profile research sessions list
uv run pdum-claude --profile research sessions read CONVERSATION_ID
uv run pdum-claude --profile research sessions rename CONVERSATION_ID 'A title'
uv run pdum-claude --profile research sessions fork CONVERSATION_ID
| HTTP operation | Purpose |
|---|---|
GET /api/profiles |
Configured profile metadata |
GET /api/status |
Owned workers, observation health and public usage estimates |
POST /api/workers |
Allocate {profileId, resume?, options?} and return websocketUrl |
GET /api/workers or /api/workers/{id} |
Active and completed worker status |
DELETE /api/workers/{id} |
Stop this worker |
GET /api/profiles/{id}/sessions |
List saved conversations without model inference |
GET or PATCH /api/profiles/{id}/sessions/{sid} |
Read messages/metadata or rename with {title} |
POST /api/profiles/{id}/sessions/{sid}/fork |
Fork with optional {title, upToMessageId} |
Live worker envelopes use profileId, conversationId and websocketUrl.
History results retain official Python SDK field names such as session_id.
Listing excludes worktrees; SDK read/info helpers may locate same-repository
worktree history within the selected profile. Profiles remain separate.
Supported per-worker options are model, permission_mode, sandbox, tools,
max_turns, and max_budget_usd. Defaults bypass permission prompts, disable the
native sandbox and leave turn/spend limits unset. Host-selected environment and
native executable settings belong to the manager. Node SDK spawn options do not
automatically become remote-worker launch options.
Resume is an explicit new allocation with a saved conversation ID. Fork creates new saved history, not a workspace copy. Concurrent native writers to the same conversation are unqualified; use separate conversations/forks for independent work. One SDK controller owns each worker; shared-worker viewers and coordinated multiple controllers remain future work.
Python composition and official clients¶
from pathlib import Path
from pdum.claude_launcher import ClaudeManager, load_profile, open_relay
async def run(application_ready):
profile = load_profile(Path("/path/to/profile"))
async with ClaudeManager({"research": profile}) as manager:
async with open_relay(manager) as relay:
worker = await manager.allocate("research")
await application_ready(relay.worker_url(worker.id))
management.create_app(manager) supplies FastAPI routes over that same owner.
Its lifespan owns only storage helpers. The embedding application closes workers
and observers. When hosting with Uvicorn, disable its default WebSocket message
size limit (ws_max_size=None) and configure ping/pong liveness. The CLI does this.
Importing/mounting the CLI does not spawn processes or install signal handlers.
The browser and Node examples
pin the official SDK. Build the example and pass
--example-dir examples/claude-client/dist to launch; open /example/ on the
manager. The browser SDK uses its native WebSocket option; the Node entry uses
the public spawnClaudeCodeProcess transport adapter. Both keep conversation
controls and hook callbacks inside the official client query.
The browser page offers profile selection, saved-history browsing, new/resume/fork, rename, streamed conversation text, interrupt and end-session controls. Reading history starts no worker. Sending a message can incur model usage; ordinary chat inherits the manager's defaults without probe turn or spend limits. Separate tabs can use the same profile. Tab closure ends the owned worker; lost prompts are never automatically replayed. Actual Chrome checks passed a live API-key turn, history selection, rename, resume/fork initialization, profile switching and tab-close cleanup. The four-turn browser probe also passed concurrent workers and marker recall after fork/resume. Mid-turn UI interruption remains unqualified.
The browser build currently needs a small process shim. Native terminal attach,
desktop/phone Remote Control and live Python SDK clients are not supported by this
delivery. The small browser example displays text and tool details; file/image input,
AskUserQuestion, native dialog forms and MCP elicitation forms remain unsupported.
Unsupported forms are visibly cancelled; simple tool-permission controls are
implemented but still unqualified in a real browser.
Observation and MITM¶
--record NEW_FILE enables complete client-protocol recording. Bytes are copied
into separate processor queues; decoding and disk I/O are off the forwarding path.
/api/status reports queue bytes, processing lag, failures and actual loss. Public
result events supply usage and cumulative conversation cost estimates. Repeated or
resumed cumulative totals must not be summed as new spend. Missing results remain
unknown, and SDK estimates are not inspected subscription bills.
The async library exposes ObservationHub, JsonlRecorder, UsageObserver and
the small Processor hook. Processors are cooperative; there is no hard fault
containment for arbitrary blocking plugins. Recording preserves full observed
chunks without payload quotas. A shutdown drain timeout reports loss. Raw captures
may contain credentials and must remain outside Git/public CI.
--mitm --capture-dir PATH --capture composes the independent MITM sidecar using
process-scoped proxy/CA settings. Without --capture, interception starts with
recording off. There are no global proxy or CA changes. The Python sidecar handle
supports runtime capture control; the Claude CLI does not yet expose capture toggle
commands. MITM and protocol recording are different observation surfaces.