docs(client): explain adapter ownership and recovery
Show where new operations belong and how callers handle their results.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687# Client API ownership
The Go `daemon` package owns the daemon protocol. Application commands and TUIscreens call named operations and receive typed results. They do not constructdaemon routes, select HTTP retry policies, or decode response envelopes.
## Request flow
Previously, some screens assembled session URLs, built JSON maps, checkedcapabilities, and decoded responses themselves. Other screens already usednamed operations. A malformed response could become an empty successful result.
Opening a context page now follows one flow:
1. The screen calls `GetContextPage` with its session, section, and page.2. The adapter checks the required capability, constructs the request, and enforces its deadline and response bounds.3. The adapter checks the response and returns a typed page or an error.4. A typed UI message carries the result back to the screen. The screen owns selection, rendering, and rejection of outdated replies.
Session lists, previews, agents, trees, models, commands, catalogs, pages, andwebhooks use the same ownership boundary. Extension-specific command resultsremain explicit `json.RawMessage` values. Tool arguments and tool results usedfor local display can also remain dynamic data.
## Code organization
Each domain keeps its requests, results, operations, and decoders together.Sessions, submissions, models, agents, context, trees, settings, catalogs,pages, and webhooks have their own files. Session stream parsing is separatefrom the other chat operations. Transport execution, shared JSON decoding,and receipt recovery remain private adapter machinery.
The CLI owns plain session-list rendering. The presentation package ownsshared session text sanitization and age formatting. Local discovery andlauncher operations keep their separate files and responsibilities.
## Changes and recovery
Typed requests preserve omitted values, explicit removals, and false values.Leaving a preference unspecified keeps it. Disabling it sends false. MCP secretpatches distinguish keeping a secret, replacing it, and removing it, includingindividual header and environment names.
Reads can recover through the connection's existing rediscovery callback.Ordinary mutations can retry an explicit authentication refusal only when itmeans the daemon did not admit the action. A lost acknowledgement does notauthorize replay. Creation and submission keep their original operation IDsand encoded requests while resolving receipts. An operation handle exposesits immutable identity through `ID()`; callers cannot replace that identity.Shutdown does not recover.A page-loading command follows command recovery rules even though the screenuses it to display information.
Confirmed changes remain visible when a later step fails. For example, asuccessful model selection survives a failed cap update, and a newly generatedwebhook secret remains available after a later configuration step fails.
The model picker calls `ChangeModel` and `SetModelContextCap`; the adapterowns command encoding and capability checks. Catalog, capability, and MCPupdates use named request structs instead of adjacent positional strings.Webhook mutations return the updated hook as well as preserving any generatedsecret from creation or rotation.
## Local startup stays separate
Discovery, attachment, launch, and upgrade retain their existing responsibilities.The interactive CLI still offers to restart a running daemon once per invocation.Keeping it running is the default, and replacement requires the user's choice.API recovery cannot launch or replace a daemon.
[Daemon attachment and local startup](daemon-lifecycle.md) describes the startuppolicy, authentication, and operator overrides.
## Adding a client operation
Add the named operation and its request and response types to the adapter first.Put route encoding, required capabilities, accepted statuses, response checks,limits, and recovery rules there. Call it from the application or screen andtranslate its result into UI state through a typed message.
Use the real-daemon harness to test observable workflows. Controlled HTTP testscover malformed responses and failures that a healthy daemon cannot produce.Keep generic transport helpers private and reuse existing decoding where itexpresses the current contract. Do not add a wrapper that merely forwards anunrestricted request.3 unmodified lines456789103 unmodified linesAlbedo is daemonized with the CLI and (future) WebUI being clients of this daemon. This ensures the agents can be programatically created, controlled, and even stopped all while still providing an experience similar to other harnesses like Claude Code and Codex. Albedo provides a Python REPL for the agents to use as a scratchpad and data manipulation allowing them to experiment, reason, and play with code before actually writing it down. This is similar to what other harnesses call CodeMode and is based on [prime-agent's](https://github.com/PrimeIntellect-ai/prime-agent/)'s Python REPL and design.
[Daemon attachment and local startup](daemon-lifecycle.md) explains how clientsdiscover, attach to, start, and explicitly restart a daemon.
[Client API ownership](client-api.md) explains how named operations separatedaemon requests from application commands and TUI screens.