diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index f5512e8..7abfb25 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -76,6 +76,14 @@ This file is the day-to-day queue for design and implementation gaps. ## Post-v1 +- [ ] `P2` Design coordinated Arbiter clusters and multi-endpoint clients. + Future work, excluded from the current authentication design delivery. + Cover configuration and credential-state synchronization, shared artifact + storage and one-time consumption, cluster management, failover and migration + availability for one logical server identity. Define safe authority handoff + and operation-replay behavior before choosing replication or storage tooling. + Context: [authentication design](authentication/design.md). + - [ ] `P2` Research IMAP search bottlenecks and search performance options. Current `imap:search_messages` behavior can be slow enough to hit client or server operation deadlines on real mailboxes. Acceptance checks: @@ -394,6 +402,27 @@ This file is the day-to-day queue for design and implementation gaps. sidecars, per-user workers, OAuth delegation, PKI-mediated secret release, and confidential-computing/enclave designs; and document what each option does and does not protect from the Arbiter operator. + Note (2026-10-16): owner explicitly deferred implementation; retain this + as longer-term research, separate from near-term authentication work. + Scope clarification (2026-10-18): current authentication is single-owner. + Multi-owner hosting depends on a credible path for hosting others' secrets. + Each future owner must have their own policies, and their agents must see + only that owner's listed accounts, subject to the agent's account grants. + Preserve the existing account-to-policy flow; do not introduce a second + policy layer for the current single-owner design. + A candidate is a user-provided unlock key delivered only after independent + verification of an enclave's attestation. Credential use, request + authorization, policy enforcement and upstream TLS must stay inside the + protected boundary, rather than returning decrypted passwords to the host + or agent. Assess trusted-client provisioning, approved-code updates, + encrypted storage, restart/unlock and recovery, tenant isolation, and + engineering and operating costs before choosing a platform. AWS Nitro + Enclaves is an example, not a selected dependency: the parent can relay + encrypted network traffic over vsock. Linux image builds and QEMU + emulation permit local development; real Nitro attestation and isolation + require supported EC2 infrastructure. See + [AWS enclave image builds](https://docs.aws.amazon.com/enclaves/latest/user/cmd-nitro-build-enclave.html) + and [QEMU's emulation limitations](https://www.qemu.org/docs/master/system/nitro.html#emulated-nitro-enclaves). - [ ] `P2` Finish the installation security evaluator. Reploy now has `doctor` and `install` checks for generated deployment diff --git a/docs/README.md b/docs/README.md index 5edf633..f53e2e9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,6 +18,7 @@ planning, assessments and design records. | Document | Status | | --- | --- | +| [Authentication and enrollment](authentication/README.md) | Requirements, HLD and eleven-PR implementation plan stamped after actual DBB and SWE reviews. Next is operator authority/local control implementation; no code slice has started. | | [IMAP folder policy](imap-folder-policy-design.md) | Much of the policy is implemented; the proposed client policy-check surface remains design work. | | [Discovery surface](info-surface.md) | Mixes implemented discovery with proposed diagnostics. Public references describe current behavior. | | [Transport and identity](future/transport-and-identity.md) | Future identity direction; its earlier HTTP transport proposal is superseded by native HTTPS. | diff --git a/docs/archive/README.md b/docs/archive/README.md index 4c0f4ea..aa412a7 100644 --- a/docs/archive/README.md +++ b/docs/archive/README.md @@ -5,6 +5,7 @@ instructions or API references. | Document | Why archived | Current reference | | --- | --- | --- | +| [Authentication design history](authentication-and-enrollment/README.md) | Byte-preserved pre-consolidation draft/interview; contains superseded proposals and historical progress claims. | [Current authentication documentation](../authentication/README.md). | | [Native HTTP protocol](protocol.md) | Initial protocol sketch; later implementation and error-contract changes supersede it. It also proposes artifact uploads that are not implemented. | [Client](../../website/docs/reference/client.md), [server](../../website/docs/reference/server.md) and [errors](../../website/docs/reference/errors.md). | | [Generic deployment tool](generic-deploy-tool-design.md) | Early proposal to build Reploy inside Arbiter. Reploy is now an external dependency. | [Deployment preparation](../../website/docs/operate/deployment/1-docker-prepare.md). | diff --git a/docs/archive/authentication-and-enrollment/README.md b/docs/archive/authentication-and-enrollment/README.md new file mode 100644 index 0000000..3c43e1b --- /dev/null +++ b/docs/archive/authentication-and-enrollment/README.md @@ -0,0 +1,27 @@ +# Authentication design history + +Captured 2026-10-20 before consolidation. These files are historical evidence, +not the current contract or instructions to execute old questions/workflows. + +| Snapshot | Original path | Preserved size | +| --- | --- | --- | +| [Original draft](draft-2026-10-20.md) | `docs/authentication-and-enrollment.md` | 2,933 lines | +| [Original interview](interview-2026-10-20.md) | `temp/design-interviews/docs-authentication-and-enrollment.md` | 3,669 lines | + +Both snapshots retain their original bytes. The [manifest](manifest.json) +records SHA-256 hashes, sizes and source-line positions for D1–D104. Snapshot +relative links retain their original spelling and may need resolving against +the original path above; do not rewrite these evidence files to repair links. +The current evidence index provides usable paths for the required review inputs. + +Use the [current overview](../../authentication/README.md), +[requirements](../../authentication/requirements.md), +[HLD](../../authentication/high-level-design.md) and +[decision/evidence index](../../authentication/evidence.md). +The working interview record is now a compact checkpoint, not a new question run. + +Later decisions supersede some early text: D77 replaces short-code pairing, +D78 replaces proxy-readable native traffic, D33 revises identity provisioning +order, and D38 removes a second manual fingerprint handoff. The current package +records those distinctions without deleting the original approvals or research. +Historical percentages and prior completion claims are not readiness evidence. diff --git a/docs/archive/authentication-and-enrollment/draft-2026-10-20.md b/docs/archive/authentication-and-enrollment/draft-2026-10-20.md new file mode 100644 index 0000000..6fa6ee1 --- /dev/null +++ b/docs/archive/authentication-and-enrollment/draft-2026-10-20.md @@ -0,0 +1,2933 @@ +# Authentication and mutual enrollment + +Status: first-round product decisions approved by the owner on 2026-10-18; +technical design resumed with a corrected round-assessment workflow. Design +finalization requires DBB review, which has not started. The engineering protocol +and configuration profile remain incomplete. This document +describes design work, not implemented behavior, security validation or permission +to expose the current unauthenticated server remotely. + +Review requirement: obtain the DBB assessment and disposition its findings before +finalizing this design. Interview approval does not waive this requirement or +approve an implementation. Record unresolved issues explicitly. The owner has +requested this review as a subsequent step; this note does not start an agent or +an automatic deep-design review loop. + +## Goal and existing direction + +Define an explicit flow in which a client establishes trust in the intended +Arbiter instance and Arbiter establishes trust in that client. Keep identity, +transport encryption and plugin policy distinct. Bidirectional information +exchange and challenges are possible tools; no protocol has been selected. + +Approved transport direction (2026-10-19): native clients and Arbiter establish +an authenticated encrypted channel through any forwarding proxy. A separate +future browser administration interface continues to use ordinary browser HTTPS, +including Apache/Certbot deployments. Its login mechanism and delivery remain +separate work; the native channel must not require a browser extension or the +native client protocol for browser administration. + +Setup priority (2026-10-19, owner clarification): the private Arbiter deployment +must be the easiest path to set up. Public DNS, Let's Encrypt/Certbot, exposing +the server to the Internet and manually provisioning a public certificate must +not become prerequisites for the baseline private installation or enrollment. +The existing self-signed transport plus approved operator-mediated pairing +remains the baseline candidate. Public certificates are an optional deployment +convenience. This priority does not approve accepting unauthenticated peers, +replace D77's long pairing secret with eight digits, or select the private +browser-admin trust/setup flow; that interface remains a design requirement. + +The owner reaffirmed retaining the current pairing design after comparing +Codex-style device codes and certificate provisioning. Keep short-code/device- +flow improvements deferred; the discussion did not replace the approved long +pairing secret or mandate public certificates/TCP passthrough. Private browser +administration is explicitly on the remaining interview agenda. Its access UX +and initial browser trust must be resolved before the full design is finalized, +without turning browser UI implementation into part of this interview. + +The owner wants to consider authentication before 1.0. The current scope is a +single owner who also operates Arbiter and supplies the upstream credentials. +Delivery slices remain to be decided. The first recovery implementation uses an +operator-held private backup key; passkey unlocking is future work. + +Multi-owner hosting is deferred until there is a credible way to host other +people's secrets. In that future model, each owner has their own policies; +their agents see only that owner's listed accounts, subject to the agent's +account grants. This is a future isolation requirement, not a new policy layer +or a change to the current account-to-policy flow. + +The first identity-provider implementation will deliver AMI only. External +identity-provider integrations are deferred. Preserve the general portability, +owner-authority, extensibility and transport-independent identity requirements. +Hermes and OpenClaw can use Arbiter tooling with AMI credentials; native reuse +of external identities is not in the first delivery. This scope decision does +not require a speculative provider framework. + +AMI uses X.509 certificates as signed identity credentials binding durable +agent identity to its current public key. These credentials are independent of +HTTPS certificates and do not require TLS client authentication or a public CA. +The issuer and stable-identity profile, application proof protocol, validity, +revocation and recovery mechanics still require design. + +## Current implementation + +- Native HTTPS and self-signed or supplied certificate files exist in + [server configuration](../server/src/arbiter_server/config.py). +- The [HTTP application](../server/src/arbiter_server/main.py) exposes discovery, + operations and nonce-protected artifacts without a caller identity layer. +- The [native client](../client/go-cli/internal/arbiterhttp/client.go) supports + certificate validation with a supplied CA. The + [CLI](../client/go-cli/internal/cli/cli.go) skips certificate verification for + loopback HTTPS when no CA file is configured. +- The [current security model](../website/docs/operate/security.md) restricts + supported use to trusted local clients. The deployment operator controls + service credentials, configuration and plugin policies. Caller identity and + caller-specific account grants are absent; plugins already enforce their + configured account policies. + +These observations come from source inspection, not a new runtime or security +assessment. Existing HTTPS can be reused. Authentication will affect the server +request boundary, client credential/trust handling and installation flow. +The first authenticated release requires enrollment for every client invoking +service operations, including localhost clients. Existing callers must pair and +adopt the authenticated client contract. Migration instructions and exact +commands remain to be designed. General discovery requires authentication; +minimal health and pairing bootstrap are the public exceptions described below. + +Approved account-information visibility: account discovery and direct lookup +require an authenticated client and expose only accounts granted to it. This +hides ungranted account names, descriptions, guidance and public settings, +including account information exposed through related discovery paths. This +policy applies consistently across those paths. + +Approved anonymous API boundary: expose only a minimal health check and the +protocol/enrollment information and exchange needed to begin pairing. Require +authentication for the remaining discovery API, including plugin catalogs and +operation schemas. Preserve bounded operator-controlled enrollment windows; +public bootstrap does not open enrollment or grant service access. Exact +endpoints and public fields remain to be specified. Existing unauthenticated +discovery callers must enroll. + +Approved revocation contract: revoke the client's authority, terminate its +active requests/downloads and reject subsequent requests. Target authenticated +client identity rather than IP address or assuming one TCP connection equals +one client; proxy/backend connections may be reused. This requires coordination +of active client access but does not require guaranteed cancellation of already +running upstream work. Such work may finish without returning its result to the +revoked client. Upstream changes already committed and data already delivered +cannot be recalled. Any continuing blocking work retains its admission capacity +until it actually finishes. Exact termination/check mechanisms and proxy +behavior remain to be designed and verified; no implementation is claimed. + +Approved artifact policy: client-facing artifact metadata and downloads require +both the nonce and authentication as the client identity that produced the +artifact. A copied URL does not grant another client access. This restricts +URL sharing and requires authenticated downloads; +helpers using the same parent identity would remain compatible. Existing +artifacts lack client ownership records, so migration must not guess their +owner. Artifact expiry and one-time consumption remain separate controls. + +Approved migration policy (Q25): invalidate existing pre-authentication artifact +links and delete their temporary server-side artifact payloads/metadata when +upgrading to the authenticated artifact contract. These entries have no client +owner and are stored in plaintext; do not guess ownership or preserve a +nonce-only access exception. Limit cleanup to legacy per-plugin `artifacts/` +entries. The artifact store shares the plugin data root, so cleanup must not +remove that root or unrelated plugin state. Upstream email and files already +saved on clients are outside this cleanup. Explain the link invalidation and +data loss in upgrade guidance. Arbiter has not been publicly released, so this +upgrade does not require a legacy artifact ownership/conversion flow. The +upgrade must not automatically replay operations to recreate artifacts. +This is an approved design policy; no files have been deleted. + +### Agreed: encryption of stored and downloaded artifacts + +Encrypt all artifacts by default, including retained server copies and files +downloaded and saved on the client. Ordinary operation responses have not been +brought into scope by this decision. + +The approved direction is server-decryptable encryption for retained server +copies and recipient encryption for downloaded files. The client keeps saved +files encrypted by default and decrypts them when used. This assigns separate +server and client decryption authority; exact key management remains open. +An established file-encryption format must be evaluated; HPKE is +an available primitive, not a complete selected file format. +Server-authorized identity access plus nonce remains required under D48. + +Future compatibility requirement: preserve Arbiter's ability to inspect upstream +plaintext for prompt-injection risks. This extends the existing +[data-filtering backlog direction](BACKLOG.md); it does not authorize building +a detector or claim that inspection can reliably eliminate prompt injection. +Inspection during initial processing can precede encryption, with any approved +transformation applied before encrypting the artifact that will be released. +Exact hooks, enforcement, resource limits and plaintext handling remain future +design work. + +Preserving independent later inspection of retained server copies is approved. +This does not extend artifact retention or authorize inspection implementation. +Server storage encrypted exclusively to a client's key would prevent such +inspection. The earlier proposal to persist only client-decryptable ciphertext +on the server therefore does not satisfy the agreed compatibility requirement. +The revised split fits the trusted operator model: Arbiter can decrypt its +retained copy for future inspection; the client's saved copy requires the +client's private key. Concrete encryption and key-management mechanisms remain +unselected, including whether both copies share an encryption format. + +This can protect copied artifact files and backups when the corresponding +private key is not also available. It does not protect against the trusted +Arbiter process/operator, which sees the upstream plaintext, or another local +actor that can read the client's private keys. Lightweight mode currently +accepts agent-readable keys; recipient encryption must not be presented as +same-host agent isolation. The future sandbox/broker boundary remains relevant. +Metadata and temporary plaintext copies require explicit handling as well. + +Costs include authenticated binding of encryption keys to client identity, +encryption-aware save/view/stream commands and lifecycle handling. Do not assume +an authentication signing key is an encryption key. Rotation or owner-approved +identity recovery does not by itself recover files encrypted for a lost key; +retention of decryption keys or a recovery mechanism requires a separate policy. +Revocation cannot retract plaintext or decryptable ciphertext already obtained. +Encryption defaults and these decryption roles are approved design decisions. +The format and remaining key lifecycle remain open; no +encryption mechanism has been implemented. + +### Agreed: explicit plaintext export + +Name the plaintext export command `artifact save-decrypted` to make its effect +explicit. It replaces the current `artifact save` name in the proposed client +contract. This is for an explicit user request to retain a readable local file; +agents should prefer temporary-file or stdin processing for routine inspection. +Server storage and default recipient-encrypted delivery remain approved; +export decrypts at the client. No compatibility alias or transition behavior +has been selected, and the implemented CLI has not been renamed. + +The earlier proposal for encrypted archives and owner recovery for `save` +does not follow from this plaintext-export use case and is not part of this +command's requirements. Key retention for remaining encrypted artifacts still +needs design. + +### Agreed: explicit temporary decryption for tool processing + +Allow a private, short-lived plaintext working file for tools that require a +path only when the caller supplies an explicit flag for passing that file to +the tool. The flag name remains unselected. Decrypted temporary-file creation +must not happen implicitly. This is a tool-processing exception, not general +persistent export; `save-decrypted` remains the deliberate export command. +Clean up the temporary file when processing finishes and prefer stdin when the +tool supports it. + +Current `with-temp` already uses a private directory, mode-0600 file and deferred +cleanup, but does not have the new decryption flag. The approved exception +preserves path-based tool compatibility but cannot promise crash-proof deletion +or protection from other actors sharing the OS user. No encrypted filesystem +or memory-backed execution mechanism has been selected or implemented. + +Research references: [HPKE](https://www.rfc-editor.org/rfc/rfc9180.html), +[age file format](https://age-encryption.org/v1), and +[X.509 key usages](https://www.rfc-editor.org/rfc/rfc9295.html). + +## Technical proposal: artifact encryption lifecycle + +This is partial technical synthesis, not a selected production dependency or +an approved client-file recovery policy. Authentication rekey and artifact +decryption are different lifecycles. Keep separate key material for these +purposes; do not delete a file-decryption key merely because the authentication +key reaches its 30-day rekey threshold. Any encryption-key replacement must +account for ciphertext still needed by the client. + +Use independent server-storage and client-delivery encryption operations. +The server retains a copy it can decrypt for the approved future inspection +use case. On an authorized download it decrypts that copy and encrypts delivery +for the client's authenticated recipient key. A public recipient supplied in +an arbitrary download request is not enough: bind recipient registration and +replacement to the enrollment's authenticated key/owner-approved lifecycle. +This does not make an agent's authentication signing key an encryption key. + +An age v1 X25519 profile is a candidate established file format. It provides +streaming authenticated encryption, with fresh per-file secrets and separate +recipient wrapping, so copying file bytes does not also copy decryption +authority. Its encryption alone does not establish who produced the file. +The design still needs authenticated origin/metadata binding, limits and +truncation handling before tool use. See the [age format](https://age-encryption.org/v1) +and [Go implementation](https://github.com/FiloSottile/age). +The Python [pyrage bindings](https://github.com/woodruffw/pyrage) are a candidate +for using the same format without requiring an additional operator application; +native builds, supported wheels, streaming behavior, dependency advisories and +cross-language interoperability require verification. No library is installed, +selected or security-validated by this research. + +### Streaming feasibility assessment (2026-10-19) + +The released [pyrage 1.4.0 source](https://github.com/woodruffw/pyrage/blob/v1.4.0/src/lib.rs) +exports `encrypt_io` and `decrypt_io` with buffered, file-like input/output. +The byte-array convenience APIs are therefore not a reason to buffer complete +artifacts. However, the wrappers show no explicit GIL release, and output uses +Rust buffering without an explicit outer flush/error check. These are concrete +integration checks, not proof of a failure or of event-loop responsiveness. +A thread-pool submission alone does not establish that Python can continue +serving health checks during the native call. Test slow I/O, final short writes, +flush failures, cancellation and contention before selecting these bindings. + +[PyPI's 1.4.0 release files](https://pypi.org/project/pyrage/1.4.0/#files) +provide CPython 3.10+ ABI3 wheels for Windows x86-64, glibc Linux x86-64/ARM64 +and universal macOS, but no Windows ARM64 or musl wheel. This matches the server's +Python minimum in metadata; it does not establish native runtime compatibility. +Windows ARM64 would need an independently verified Rust source-build/wheel path. +The earlier Noise/cryptography experiment does not verify pyrage packaging. + +The [Go age API](https://pkg.go.dev/filippo.io/age@v1.3.2) +exposes streaming readers and writers; encryption must check `Close` to finish +the final chunk. Its [v1.3.2 module](https://github.com/FiloSottile/age/blob/v1.3.2/go.mod) +declares Go 1.24.0, matching the current CLI's language floor. No dependency graph, +advisory scan, cross-language artifact experiment or platform execution has run +for this candidate. No extra helper executable, maintained fork or compiler-floor +change is selected by this assessment. + +The [age format](https://age-encryption.org/v1) authenticates chunks and requires +an error if EOF arrives without a valid final chunk. A successfully decrypted +prefix is not proof that the complete artifact arrived. The client chooses the +processing mode, preserving the existing `with-stdin` and `with-temp` paths +(D83). `with-stdin` decrypts and streams authenticated chunks as they arrive; +a later integrity or truncation error must fail the operation, but cannot undo +effects the receiving tool already performed. Do not force full-download +buffering or a second decryption pass on this path. + +`with-temp` completes the download and verification before starting the tool. +Its private plaintext temporary file remains subject to the explicitly approved +plaintext-file flag and processing-lifetime cleanup. A verification failure +must prevent tool startup and trigger cleanup of the partial file. This does +not promise crash-proof deletion. Neither path may report a partial download +as complete. + +Also support an optional complete encrypted download followed by plaintext +streaming to the tool (D84). Store ciphertext in a private, size-bounded temporary +file and verify the complete artifact before starting the tool. Then decrypt +that same ciphertext into its stdin. No plaintext staging file is created. +Full verification can run while receiving the ciphertext, discarding the +decrypted output; supplying stdin afterward needs a second decryption pass. +This waits for the download to finish and uses temporary encrypted storage. +On download or verification failure, do not start the tool and clean up the +temporary data. Retain the required decryption key through processing and clean +up ciphertext afterward, without promising crash-proof deletion or atomic tool +execution. Immediate streaming and explicit plaintext temporary files remain +available. This is a client choice, not a new default or a mandatory buffering +requirement. The option's CLI spelling is not selected, and the crypto +integration remains unimplemented. + +### Proposed artifact identity and recipient binding + +This specifies application obligations within the agreed encryption direction; +the format/library profile still needs interoperability and security review. + +Register a distinct artifact-decryption public key through the authenticated +enrollment channel, with proof that the client holds the corresponding private +key. Bind the record to the server enrollment and a key version. Do not accept +a replacement recipient from a URL, proxy header or arbitrary download argument. +Changing this key requires an authenticated update authorized for that enrollment, +proof of the new key and a conditional durable update. It neither rotates the +authentication credential nor changes account grants. Hold the selected key +version through each admitted download/processing operation; a concurrent update +must not silently redirect that operation to another recipient. + +The operation's authenticated caller context determines artifact ownership. +Keep the plugin-facing creation interface free of a caller-supplied owner +override. Bind the resulting artifact reference to the server identity, local +enrollment, artifact identifier and plugin/account source. Helpers sharing the +same enrolled identity remain the same caller; an independently enrolled client +cannot download another client's artifact merely by gaining access to the same +upstream account or learning its nonce. + +Split storage into encrypted content metadata/payload and a minimal private +authorization/lifecycle index. The index needs opaque artifact and enrollment +references, nonce verification state, storage-key version, physical allocation, +creation/access deadlines and consumption state so admission and cleanup can +run without decoding upstream content. Keep filenames, media types, plaintext +hashes and upstream source details in encrypted metadata. This index still +exposes activity and allocation information to someone who reads server storage; +storage encryption is not protection from the trusted server/operator. + +For the candidate age path, encrypt sensitive metadata together with its payload +under a bounded, versioned application framing profile. Do not place sensitive +fields in the public age header or add a custom encryption primitive. The exact +framing and parser bounds remain explicit profile work, not a claim that age +itself defines Arbiter metadata or authenticates a sender. The +[stable age specification](https://c2sp.org/age@v1.1.0) defines the file-encryption +layer; the enclosing authenticated Arbiter channel supplies live server origin. + +Carry the expected artifact identity, plaintext length/hash and selected recipient +version in the authenticated descriptor/download context. Check decrypted metadata +against that context before releasing payload bytes. Compute the plaintext length +and digest while processing and require a valid final encrypted chunk plus matching +length/digest before reporting complete success. Immediate streaming retains its +accepted partial-input risk; verified-download and plaintext-temp modes withhold +tool startup until these completion checks pass. Do not infer server origin from +the ability to decrypt an arbitrary age file: anyone with a public recipient key +can encrypt a new file to it. The temporary ciphertext and its trusted context +belong to one live client operation; standalone offline import/authentication of +encrypted archives is not introduced here. + +On the server, authorize ownership and current access before decrypting content +or reserving the one-time GET. HEAD remains non-consuming. Once GET consumption +commits, later crypto/network failure does not reopen its nonce. Reject revoked +access and stop delivery under the existing cancellation contract. Keep crypto, +storage locks and backpressure outside the event loop with bounded admission; +retain capacity until underlying work ends. No new replay guarantee or bypass +of storage limits follows from encryption. Key-update crash recovery, the +complete framing profile and native worker behavior remain engineering work. + +Client guidance must explain the processing tradeoffs (D85): + +- Immediate streaming starts processing sooner and needs no temporary artifact + storage. The tool can receive authentic but incomplete data; a later download + failure cannot undo its earlier effects. Use it when the consumer can safely + handle partial input. +- Verified encrypted download needs temporary disk capacity for the ciphertext + and waits for the full download and verification before starting the tool. + It then streams plaintext without a plaintext staging file. This prevents + incomplete downloads from reaching the tool, but does not make the tool's + execution atomic or prevent later local failures. +- A plaintext temporary file supports tools that require a pathname. Explain + the explicit plaintext-file flag and cleanup limits before choosing it. + +Expose this choice in client documentation and operation help. Do not describe +the first two modes as having identical completeness or storage guarantees, +and do not infer a default from this guidance. + +Admission must precede starting crypto work. Cancellation must retain its slot +until the underlying operation actually finishes, with bounded backpressure and +all files closed. Reuse the existing admission lifetime requirements; do not +assume an unbounded thread queue or a cancelled await stops a native call. +Storage/delivery metadata binding and the precise processing path remain open. +This is source-level feasibility evidence, not a completed T4 design or a +security/interoperability signoff. + +Retain bounded streaming and the existing plaintext size/count/storage limits. +Account for ciphertext and metadata overhead in physical storage admission; +encryption must not turn the 50 MiB artifact limit into a limit on ciphertext +that unexpectedly rejects a previously valid plaintext size. Keep plaintext +out of persistent staging files except the explicitly approved export/tool +paths. Sensitive metadata also needs encryption or an explicitly justified +minimal plaintext representation; its exact envelope remains work. + +The current server consumes the nonce on GET before streaming. It retains the +payload until normal cleanup but rejects another GET even while those bytes +exist. HEAD does not consume it. Defaults remain ten minutes idle and 24 hours +maximum retention, with cleanup activity-based. Thus client key recovery cannot +promise another download merely because the server once held that artifact. +This observation does not authorize changing one-time GET or retention. + +No long-term encrypted client archive use case has been established. Normal +artifact use is processing through stdin or a temporary working file; the +explicit durable plaintext export is `save-decrypted`. The earlier question +about archive recovery after loss of a client decryption key inferred an +additional use case and is withdrawn. It does not require a new owner decision +or add client-key escrow/backup machinery to this design. Keep decryption +working through an active processing operation and routine authentication rekey. +This does not promise secure deletion or a fixed lifetime for files left after +a crash or deliberately retained outside the normal workflow. If durable +encrypted archives are introduced later, design their retention and recovery +then. The approved server recovery bundle remains separate. + +## Decisions from this interview + +- Confidential execution to protect users from the host operator is interesting + longer-term research. The owner explicitly deferred implementation; it is + not a near-term authentication deliverable. Retain the exploration in the + [hosted secret-execution backlog item](BACKLOG.md). No platform or protocol + has been selected. +- The near-term model has a single owner and trusted operator who supplies the upstream + service passwords. Protecting those passwords from that operator is outside + this design's near-term scope. Credentials remain separated from agents. + Multiple clients can enroll under that owner. Multi-owner hosting is deferred; + remote deployment support and an authentication protocol still need design. +- Each enrolled client has a separate identity and credential. Clients can + share approved service accounts, while the operator can restrict or revoke + one client's access independently. AMI's X.509 credential format and the + owner-approved pairing flow are selected; their engineering profile is open. +- Identity and enrollment must be friendly to existing agent systems, + specifically Hermes and OpenClaw. Evaluate candidate systems against their + existing integration paths, setup effort and credential handling before + selecting a mechanism. Reuse of native identities is a research objective, + not a claim that either agent already supports the proposed authentication. +- Clients using an existing identity establish or select it before enrollment. + In the approved lightweight flow, the trusted server represents the owner + and provisions the client identity during enrollment with owner approval. + This revises the earlier requirement that every client establish an identity + before enrollment. AMI uses X.509; external provider integration is deferred. + Creating an identity does not itself establish mutual + trust or grant account access. +- Enrollment is a standalone flow for adding clients to an existing server. + Server setup may use that same flow for the first client. Each client needs + its own identity, explicit approval, server trust and account grants. One + person may perform both operator and client-side steps; setup does not grant + the first client a separate trust shortcut. Hosted-service authority and + onboarding remain to be designed. +- The future server admin interface is the intended place to view pending + enrollments and approve or reject them. Initially, local server-side operator + commands, used directly or through SSH, open enrollment and review, approve + or reject requests. Existing trusted host administration establishes initial + operator authority. The future interface is not a prerequisite for enrollment; + its authentication and delivery timing remain open. +- Client-initiated enrollment uses operator-controlled windows. New requests + are closed by default; the operator temporarily opens enrollment. Pending + requests, request rates and request lifetimes are bounded. Each request still + needs explicit approval before service access. Exact limits, administration + commands and the trust-verification protocol remain open. Invitation-URL + support in the first version has not been selected. +- When enrollment is closed, the client must receive actionable guidance on + asking the operator to open it through trusted administration, then retrying + enrollment. This guidance does not authorize the client to open enrollment. + Exact commands and any operator-contact mechanism remain unselected. +- Enrollment must account for which configured accounts an agent may access. + Account grants remain changeable afterward: an enrolled agent can receive + access to additional accounts without enrolling as a new identity. Its owner + can approve the agent and grant specific configured accounts. In the current + scope, the owner is also the operator; separate cross-owner grant authority + is deferred with multi-owner hosting. Account access and identity verification + are distinct concerns. +- Establish bidirectional trust first: the client verifies the intended Arbiter + instance, and Arbiter verifies the intended client identity. Account grants + are separate authorization state and may be assigned or changed afterward. + This ordering does not select direct trust versus owner-signed identity or + a proof protocol, and trust establishment alone does not grant account access. +- The server needs an owner-registration flow so it can recognize the owner + behind an agent attestation. Registration must establish the association + between the intended owner and their cryptographic identity. The registration + bootstrap and proof mechanism remain undecided. Registering additional owners + and defining their authority are deferred with multi-owner hosting. + This requirement does not select Buzz or permit public self-registration. +- Provide a lightweight identity setup choice for users for whom adopting + Buzz would be too much setup. Buzz remains interesting, but its full + application/workspace must not be assumed to be the required user journey. + AMI with X.509 is the first delivery; Buzz integration is deferred. Do not + require a separate identity application for the selected lightweight path. +- Identity must be usable without a mandatory central external system. Do not + require an external vendor account, public identity directory or third-party + signing service for the baseline owner/agent identity journey. Assess how + identity creation, verification and key lifecycle work with operator-controlled + infrastructure. This does not establish an air-gapped or offline requirement. +- Keep the design open to other identity providers that meet the requirements. + Do not make enrollment and account grants depend on one provider's identity + format. Evaluate providers against the same continuity, owner-proof, + credential-control and dependency requirements. The integration interface, + cross-provider identity linking remain future work. Deliver AMI first. +- Lightweight setup is the requirement. Self-identification is one candidate + approach to evaluate, not a required or selected mechanism. Compare possible + approaches without assuming users already have an external identity. The + credential profile and detailed setup commands remain engineering work. +- For the lightweight path, installing Arbiter must be sufficient. Its CLI + handles identity setup; users must not need an additional identity application + or separately operated background service. Embedded libraries are acceptable, + and compatible existing identities may be an optional convenience. This does + not require a separate identity application. AMI and X.509 are selected; + storage and credential profiles remain engineering work. +- Every supported identity system must let a registered owner authorize a + replacement for an agent's lost private key while preserving the agent's + enduring identity. This is a general requirement, not a feature limited to + the lightweight path or one provider. Recovery proof, old-credential + invalidation and owner recovery remain to be specified. Once verified, key + replacement preserves existing server enrollments and account grants without + another operator approval. Existing suspensions and revocations remain in + effect; identity recovery does not reinstate revoked access. +- Only the owner may authorize recovery of their owner identity through an + owner-controlled recovery mechanism. Authority to administer an Arbiter server + does not confer authority to recover another owner's identity. Server-local + access administration remains separate. The recovery mechanism remains open. +- Agent identity and verifiable ownership must remain portable across + independent Arbiter servers, including after owner-authorized agent key + replacement. Each server must be able to verify continuity without depending + on another Arbiter server. Enrollment, account grants, suspensions and + revocations remain independently controlled by each server. The identity + system and continuity-proof mechanism remain to be selected. +- Agents may not create durable identities; durable agent identities require + owner authorization. Transient helper agents act under the parent agent's + enduring identity and permissions, potentially with an indicator + of the helper or execution. Such an indicator is not itself a new durable + identity. Sharing an identity does not select shared private keys: credential + custody and helper attribution remain to be designed. Narrower helper access + and scoped temporary credentials are deferred until a concrete use case + emerges. No implementation-cost estimate has been established for that work. +- Lightweight mode permits the agent to read its own client private key. + This approval extends the earlier POC-only acceptance to lightweight mode. + Put `NEVER SHARE THIS` at the top of the key file. The + warning is guidance, not an enforced protection: agent-controlled code can + still copy or disclose the key and enable impersonation. This does not + authorize access to owner or recovery keys. Reploy isolation remains a + deferred future direction. +- A doctor diagnostic should warn when lightweight mode is active, once a + supported secure mode is available to recommend. Explain that the agent can + read and copy its client key and give guidance for switching to the supported + alternative. No secure mode is implemented; + exact diagnostic syntax and secure-mode availability checks remain open. +- The intended hardened architecture combines an isolated agent with a trusted + broker that holds its private client key and performs Arbiter requests. + Arbiter enforces service access and operation policy; Reploy supplies network, + filesystem and host isolation. Reploy controlled sessions are the likely + integration mechanism. This is future architecture, not implemented + protection or a prerequisite for lightweight mode. +- AMI enrollment uses one operator-mediated random pairing secret to establish + bidirectional trust. The client generates and displays a one-time secret; + the owner copies it into trusted server administration and approves enrollment. + An established authenticated pairing protocol must bind the intended client + and server, then exchange and retain their trust information automatically. + This supersedes the separate manual fingerprint-comparison requirement for + this flow. The secret is not a public request number and must not be sent in + the initial unverified network request. Protocol/library selection, attempt + resource admission, trust persistence and rotation remain open. Pairing secret, + attempt and lifetime defaults are specified below. Normal HTTPS + certificate validation remains available when a trusted-CA certificate is used. +- For every identity provider and authentication mode, durable Arbiter and + client identities and their established trust must be independent of HTTPS + certificates. Replacing or renewing the transport certificate, or placing + the same Arbiter instance behind a TLS-terminating proxy, must not require + reenrollment or a new identity-trust confirmation from existing clients. + Clients must still authenticate the previously trusted Arbiter identity at + the application layer. This is a general architectural requirement, not an + AMI-specific property. An unexpected change to that durable identity remains + a separate trust event. Transport validation and migration mechanics must + satisfy this requirement; no blanket TLS-verification bypass is selected. + +## Engineering work before implementation + +The interview fixes the product behavior and trust boundaries; it does not +select a complete wire protocol. The following work remains substantive and +must not be mistaken for implemented or security-reviewed behavior: + +- Required early compatibility POC: establish a suitable Python/Go library + pair before selecting dependencies or relying on it in the implementation + plan. Pin exact versions and protocol profiles. Demonstrate a correct-code + exchange with matching keys and mutual confirmation, rejection after wrong + secrets or altered context/messages, and handling of malformed messages. Check + deployment compatibility separately: Python 3.10–3.14 and current Linux, + macOS and Windows x64/arm64 release targets. A successful exchange does not + establish implementation security; library assessment and DBB design review + remain necessary. The isolated experiment below now demonstrates local + interoperability for one candidate pair. Production dependency selection and + native execution across the deployment matrix remain incomplete. +- Library research correction: existing Python bindings include + [spake2-cffi](https://pypi.org/project/spake2-cffi/) and + [opaque-ke-py](https://pypi.org/project/opaque-ke-py/). A native-backed Python + dependency does not require the Go client to use CGo or the same underlying + library. Interoperable independent implementations remain an option. + The previous question asking for blanket native-build approval was premature + and is withdrawn; it did not establish that such a build change is necessary. + Preserve the approved copy-paste secret and ordinary installation; surface a + concrete build/platform cost if the actual evaluated pair requires one. +- Historical short-code screening did not establish a suitable match for + `spake2-cffi`'s BoringSSL Ed25519/SHA-512 variant. The + [dosgo port](https://github.com/dosgo/spake2-go/tree/3b8be66d26f7e61a26685d5d708e200cb016c33f) + has a matching-looking API/profile, but contains its own low-level curve + arithmetic, no `_test.go` files in the inspected tree and no clear repository + license found. It is not selected or demonstrated interoperable. The + [backkem implementation](https://github.com/backkem/spake2-go) targets RFC 9382, + with a P-256/SHA-256 default rather than this BoringSSL profile, and warns + that it lacks formal security review. The + [niomon implementation](https://github.com/niomon/spake2-go) explicitly warns + about timing attacks. These are findings about checked candidates, not proof + that no suitable Go library exists. Short-code pairing is now deferred; these + findings do not require delivering a PAKE backend in the initial version. +- An alternative Go candidate is [bytemare/opaque](https://github.com/bytemare/opaque), + which targets RFC 9807 and is maintained by a protocol coauthor; it explicitly + lacks an independent audit. It would require evaluating an OPAQUE Python/Go + pair, not connecting it to SPAKE2. Current source declares Go 1.26 and + `opaque-ke-py` declares Python >=3.12, whereas this repository's Go module + declares 1.24 and its server supports Python >=3.10. Do not silently raise + those requirements or infer compatibility from the shared OPAQUE name. + Registration setup, exact ciphersuite/context/encoding, supported package + versions and wheels also remain to be checked. Research has not approved + switching protocol or dependencies. +- Specify and assess an established pairing protocol/library, request and + response authentication, replay protection and reverse-proxy behavior. + Preserve the single secret-code handoff, operator approval and identity + independence from transport certificates. Do not invent cryptography. +- Define X.509 identity/issuer profiles, portable ownership and continuity, + crash-safe key replacement, bounded old/new credential overlap and revocation + checks. Normal certificate validity must support the agreed 30-day rotation + and 180-day inactivity rules without earlier forced pairing. +- Define authenticated encryption formats, encryption-key binding/retention, + metadata protection and bounded streaming for server and client artifacts. + Preserve server inspection, explicit plaintext export and temporary-tool use; + identity recovery alone cannot recover a lost artifact decryption key. +- Specify persistent enrollment/grant state, bounded pending requests, expiry, + retry cleanup and exact CLI/configuration contracts. Preserve the existing + account-to-policy path; do not add another client policy layer. +- Specify consistent encrypted recovery exports, safe credential capture, + validation and atomic restore, version handling and single-active migration + cutover. Restore the snapshot directly with the dated warning, without a + permission-review gate. Define the narrow legacy-artifact cleanup. +- Verify interoperability, real proxy/streaming behavior, cancellation/revocation, + failure recovery and migration. No runtime, security or acceptance checks for + these new mechanisms have run as part of this interview. + +These are engineering deliverables within the agreed requirements, not silently +approved protocol proposals. If research exposes a material change in product +behavior, setup burden, trust or scope, return that decision to the owner. An +interview confirmation does not make this a complete implementation-ready +protocol specification. No automatic deep-design review is authorized. + +## Technical synthesis: pairing + +This is a technical proposal within the approved flow, not an implemented or +independently reviewed protocol. The copied secret authenticates a temporary +channel; durable identities are exchanged and retained through that channel. +Do not transmit the secret as a login password on the unverified connection. + +### Common exchange and activation sequence + +1. The client generates a fresh private key locally for this server enrollment and a public pending-request + identifier. Its provisional local state survives interruption. It displays + one copyable pairing value containing the public selector and secret. + Public request metadata is bounded and cannot activate an identity. +2. Through trusted local/SSH server administration, the owner supplies the + pairing value and approves that pending request. Accept the secret through + a protected prompt/input rather than requiring it in command-line arguments, + shell history or logs. No separate identity app or public relay is required. +3. Run an established authenticated key exchange. Bind its confirmed channel to + the protocol version, roles, request identifier, proposed client key and + durable server identity. Prove possession of the client key as part of the + enrollment payload. A request identifier alone never proves approval. +4. Deliver the server trust record through the confirmed channel. The client + persists it provisionally before requesting final issuance. Credentials, + trust information and completion travel directly between client and server; + the owner does not copy a return bundle or compare another fingerprint. +5. Commit the approved identity, credential and initial grants consistently on + the server, then return the completion receipt. The client activates its + local credential/trust state atomically before acknowledging completion. + Pending keys cannot invoke ordinary operations merely by existing. +6. A lost final response or acknowledgement does not undo committed enrollment. + A bounded receipt-retrieval path proves possession of the approved client key + and uses the provisionally retained server trust; it retrieves the committed + result rather than issuing a duplicate identity or adding grants again. + Uncommitted expiry/rejection cleans provisional resources. Exact message + schemas, remaining admission parameters and crash-state validation remain work. + +Server and client key confirmations must complete before the channel is treated +as trusted. Retrying the enrolling client's network exchange never resets its +request's expiry or attempt budget and never bypasses operator approval. +Approval initially uses the server CLI, locally or over SSH; neither a web +interface nor a continuously open administrator connection is required. Closing +or reopening that CLI does not reset the pending enrollment's limits. +The trusted administration interface is distinct from unauthenticated bootstrap; +the proposed local control transport is described with the state model below. + +The pairing exchange is only a trust bootstrap. Its confirmed channel carries +the durable public keys, credentials and trust records; private keys remain +local. Keys may be generated locally before pairing, as in the sequence above; +their public credentials become trusted through pairing. An established +authenticated exchange, bounded attempts and a short validity window must +protect this initial step: strong later keys cannot repair pairing with the +wrong party. + +### Approved: copy-paste pairing secret; short codes deferred + +The owner selected a larger random secret for the initial delivery, deferring +short, typable pairing codes to a future improvement. This supersedes the +earlier eight-decimal-digit choice. The client generates 32 bytes (256 bits) +using the operating system's secure random generator. Encode those bytes as +43 unpadded URL-safe Base64 characters for copy-paste. This is the secret alone; +the single copyable value also carries a separate public request selector and +version framing. Its total length is approximately 70–90 characters; the exact +framing remains engineering work. + +The owner copies that value into trusted local/SSH server administration and +approves the bound pending request. Never send the secret itself in the initial +network request or treat it as a public selector. Establish and confirm an +authenticated channel using an existing protocol for high-entropy pre-shared +secrets, then exchange durable credentials through it. A larger secret makes +offline brute-force search infeasible; it does not by itself prevent public-key +substitution or authenticate an arbitrary exchange. + +Keep the existing ten-minute lifetime from request creation and at most five +admitted pairing attempts per pending request, including failed or abandoned +exchanges. Both endpoints retain those bounds across network retries. Expiry +or exhaustion requires a fresh secret and owner approval; it does not lock an +existing enrolled identity. The twenty-pending-request cap and separate work/ +message admission controls remain. These bounds limit active attempts and +resource use; secret strength addresses offline guessing. + +Noise supports 32-byte PSKs. An illustrative profile is +`Noise_NNpsk0_25519_ChaChaPoly_SHA256`; the unmodified unauthenticated NN pattern +does not provide equivalent authentication. Python `noiseprotocol` and Go +`flynn/noise` are candidates exposing PSK configuration. No exact profile, +dependency or native-build architecture is selected by the long-secret +decision. Require the early Python/Go compatibility POC and library assessment +before relying on the path. In particular, the Python project's security-review +and platform-coverage limitations remain to be assessed. The experiment below +provides local interoperability and limited packaging/build evidence, without +establishing implementation security or full platform compatibility. +See the [Noise specification](https://noiseprotocol.org/noise.html#pre-shared-symmetric-keys), +[Python candidate](https://github.com/plizonczyk/noiseprotocol) and +[Go candidate](https://github.com/flynn/noise). + +A future short-code mode would require a suitable PAKE or another established +short-code authentication protocol with its own assessed implementation. It +must not reuse the high-entropy PSK protocol with an eight-digit secret. The +previous PAKE investigations remain evidence for that deferred work; they do +not commit initial delivery to custom cryptographic bindings. + +### Compatibility experiment: isolated Python/Go pairing + +On 2026-10-19, an explicitly authorized isolated POC tested +`Noise_NNpsk0_25519_ChaChaPoly_SHA256` with Python `noiseprotocol==0.3.1` and +Go `github.com/flynn/noise v1.1.0`. It used fresh 256-bit secrets and synthetic +request/key/identity data, without a network listener or product integration. +The Python package's tag is commit +`73375448c55af85df0230841af868b7f31942f0a`; the Go tag is +`4d9f71cd4ba1fe81415efac312664ccc4bc79b46`. + +All thirteen test groups passed on CPython 3.13.12 / Go 1.26.8, Linux amd64 +under WSL2. Both role combinations derived matching handshake hashes and +directional session keys and exchanged encrypted confirmations. Tests rejected +wrong secrets, mismatched request context, altered keys/payloads in either +handshake message, malformed/truncated messages, transport tampering and replay. +Missing or wrong-length PSKs were rejected explicitly by the POC adapters. +Fresh sessions used different keys. The secret itself was absent from the +simulated network messages. These checks demonstrate compatibility for the +tested profile; they do not assess side channels, full protocol conformance, +hostile load, durable enrollment transactions or identity credentials. + +The Go peer cross-compiled without CGo for Linux/macOS/Windows amd64 and arm64. +Its pinned `golang.org/x/crypto v0.58.0` and `x/sys v0.49.0` require Go 1.26; +this does not establish compatibility with Arbiter's current Go 1.24 module +requirement or approve raising that requirement. Python pinned +`cryptography==48.0.1`, `cffi==2.1.1` and `pycparser==3.11`. +The crypto version fits Arbiter's existing `>=42,<49` constraint. +Wheel-only resolution succeeded for Python 3.10–3.14 on Linux glibc 2.34 +amd64/arm64, macOS 14 x64/arm64 and Windows amd64 (25 combinations). +It failed for all five Windows arm64 combinations because the pinned +`cryptography` version had no matching published wheel. This wheel-only result +did not establish a new Arbiter platform incompatibility: Arbiter already +depends on `cryptography`, and its Windows arm64 CI supplies OpenSSL for +dependency builds. Older Linux baselines and musl were not checked. + +Follow-up [draft PR #34](https://github.com/omry/arbiter/pull/34), commit +`94994fafe8c568f608387fbecf2a32bd37fbc645`, tracks the portable probe in +`experiments/pairing-noise/` and adds it after existing product tests in the +native Windows arm64 job. The +[native job](https://github.com/omry/arbiter/actions/runs/39146689439/job/117731852591) +passed all thirteen groups on Windows 11 ARM64, CPython 3.13.16 and Go 1.26.9, +with the exact Python pins above and CGo disabled. Explicit interpreter and Go +host/target checks confirmed native arm64 execution. Installation reused a +cached `cryptography-48.0.1-cp313-abi3-win_arm64.whl`; this is not a claim that +such a wheel was available from the package index or that the experiment +rebuilt it from scratch. The experiment step took 29 seconds; the existing +OpenSSL setup and product tests accounted for most of the job's eleven minutes. +Artifact `pairing-noise-windows-arm64` (ID `12143363252`) retains the environment, +installation, binary metadata and test results. A local copy is under +`temp/pairing-noise-poc/windows-arm64-ci-39146689439/`. +This establishes native compatibility for Windows arm64 / Python 3.13 with +these pins. Other Python versions on that target and native execution on the +remaining platform/version combinations remain unverified. + +Two integration requirements were confirmed. An absent PSK must fail closed: +the Go library can otherwise configure plain NN. Noise also does not reject +a replayed first message under the same secret/context by itself. The fresh +responder's session rejected the old session's confirmation, but Arbiter must +still enforce pending-request ownership, approval, expiry, attempts and one-time +commit. Do not establish durable trust from the initial payload alone. Discard +failed handshake instances; the probe did not rely on library rollback/retry +semantics. Real framing and public endpoint admission remain separate work. + +The Python wrapper's tested release dates to March 2020, states explicit Linux +support only, and lists peer review and side-channel countermeasure work as +unfinished. The published Go nonce advisory affects versions below 1.0.0, +not this pin. A `govulncheck v1.9.0` source scan reported no reachable vulnerable +symbol in this probe, while retaining module/package advisories for the local +Go 1.26.8 toolchain and the unimported `x/crypto/openpgp` package. This is not +a security signoff or an all-dependencies-clean result. No Python vulnerability +scan or independent design review ran. + +The isolated source, exact pins, reproducibility instructions and raw evidence +are in `temp/pairing-noise-poc/` (ignored local experiment artifacts). The +[experiment README](../temp/pairing-noise-poc/README.md), `test-results.json`, +`platform-results.json` and `dependency-screen-summary.json` preserve what ran +and its limits. No product dependency or build setting changed. Production +library/profile selection, full native platform coverage and DBB design review +remain open. This experiment provides early Linux and +Windows arm64 interoperability evidence, not a finalized authentication design. + +### Dependency assessment and proposed pairing constraints + +Further isolated checks on 2026-10-19 tested the same profile and Go peer on +Go 1.24.13 with `flynn/noise v1.1.0`, `x/crypto v0.48.0` and `x/sys v0.41.0`. +All thirteen compatibility groups passed against Python `noiseprotocol==0.3.1`. +The peer built without CGo. Both Python/Go role combinations also reproduced +all six messages and the handshake hash of the exact-profile Cacophony +reference vector, byte for byte (source commit +`18b7348c54fd61fcd0c220298883de0d09c8364d`). These checks preserve the possibility of the +existing Go 1.24 language floor; the original POC's current dependency pins +do not make a floor increase intrinsic to the protocol. The older dependency +set was checked on Linux only, not the complete release matrix. +Evidence and exact module pins are in +`temp/pairing-noise-poc/go124-assessment/`, including `reference-results.json` +and its input-vector hash. The isolated Go peer accepts deterministic ephemeral +bytes only for reference-vector testing; production must use its secure random +source, never those fixtures. + +A `govulncheck v1.9.0` source scan with the current local Go 1.26.8 toolchain +found no reachable vulnerable symbol in that assessment module. Module-level +advisories still exist, and this scan does not establish security of binaries +built by an older compiler or constitute an audit. Keep the language-compatibility +floor separate from using a supported, patched release compiler; Go 1.24 is +outside the current upstream support window. Do not adopt an old compiler +as the production security baseline merely because it passes this probe. +See the [Go release policy](https://go.dev/doc/devel/release#policy). + +The Python repository's default branch remains at the March 2020 release. +Its upstream report of failing newer vectors lists unsupported patterns and +PSK fixture-input mismatches; it is not evidence that this exact profile fails. +The independently checked exact-profile vector above passes. Conversely, its +reported transport-size defect was reproduced: encrypting 65,535 plaintext +bytes produces 65,551 ciphertext bytes, which its receive API rejects. +The standard 65,519-byte plaintext / 65,535-byte ciphertext boundary passed in +both cross-language directions. Sources: +[vector report](https://github.com/plizonczyk/noiseprotocol/issues/43), +[size report](https://github.com/plizonczyk/noiseprotocol/issues/44), +[Noise framing requirements](https://noiseprotocol.org/noise.html#message-format). + +Engineering proposal for the pairing profile: + +- Use exactly `Noise_NNpsk0_25519_ChaChaPoly_SHA256` and a decoded 32-byte PSK. + Reject a missing key, a short password, another pattern or a downgrade; + there is no negotiation to unauthenticated NN. +- Set the client as initiator and the server as responder. Bind the protocol + version, roles, request selector and immutable pending-request/key digest in + the Noise prologue. Treat pre-pairing server metadata as untrusted until the + confirmed channel authenticates the server's durable identity information. +- Send no credentials in the first handshake payload. Exchange credential + material only after both handshake messages; require explicit confirmations + bound to the resulting handshake hash and immutable request. Client-key + possession and server-identity proof must follow the final T2/T3 profiles, + rather than treating PSK possession as possession of another private key. +- Enforce the standard 65,535-byte wire-message ceiling before parsing or + invoking the library, and the 65,519-byte transport-plaintext ceiling before + encryption. Check final output size too. Keep public HTTP body/work admission + outside the library. Do not rely on the wrapper's incorrect plaintext cap. +- Serialize each direction's state. Do not consume Noise state twice on HTTP + retransmission; return a bounded cached response for the same accepted step. + A conflicting step terminates that exchange, and a new exchange consumes a + new attempt under the existing ten-minute/five-attempt rules. +- On malformed input, authentication failure, cancellation or lost ephemeral + state, discard that exchange. Commit an identity only after mutual + confirmation, client provisional persistence and the conditional durable + transaction described below. A handshake hash alone is not an activation + receipt or durable identity. + +Disposition: retain this profile and library pair as the concrete candidate for +the requested DBB design/library assessment. The known size defect has a precise +standard-boundary mitigation; test that adapter boundary in implementation. +Do not describe the old wrapper as actively maintained or independently audited. +No fork/maintenance commitment, production dependency adoption or version-floor +change is approved here. If review requires substantial wrapper maintenance or +a different backend, surface that concrete cost before taking it on. T1's +remaining identity/wire/activation details depend on T2/T3; they are explicit +design work, not unspecified implementation details. + +### Technical proposal: CLI approval and pending-state ownership + +The following state model specifies proposed behavior within the approved +flow. It is not implemented or independently reviewed. + +The server process owns enrollment transitions. The initial administrator CLI +uses a local Unix-domain control socket in a private directory owned by the +server account. Restrict the directory to that account and the socket to its +owner; do not expose this interface through the public HTTP listener or Apache. +Run the CLI locally, over SSH, or inside the server's container/namespace when +necessary. Root and the server account remain trusted administrators. This +adds no remote administrator credential or mandatory background service beyond +the existing server. Other operating-system transports require an equivalent +local access boundary; a loopback TCP listener alone does not provide that +boundary. Windows local administration remains a portability gap in this +proposal, not a decision to remove an existing supported platform. Python +provides Unix-domain stream support in +its [asyncio API](https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_unix_server). + +The CLI sends one bounded approval command and receives a receipt. It supplies +the code through a protected prompt, not an argument, environment variable or +log entry. The server accepts ownership of that command before acknowledging +it. The CLI can then exit while the client completes the exchange. If the +receipt is lost, querying the request reports its existing state; repeating +approval does not reset time or attempts or replace the approved public key. +An operator can still explicitly reject a pending request before commitment. + +Each request has an independent public selector and immutable client public-key +binding. The secret code is not used as a database lookup key, and the public +request must not contain the code, its hash or another offline guessing oracle. +Display the selector alongside the encoded 256-bit secret as one copyable +pairing value. The selector identifies which pending request the CLI approves; +it adds no authentication strength and does not replace secret entropy. +Unverified display names are labels, not proof of ownership. The exact selector +encoding and CLI spelling remain to be specified without adding another +operator return handoff. + +Use a transactional local store for pending state, durable identities, +credentials, grants and completion receipts. SQLite is the proposed store; +its [atomic commit behavior](https://www.sqlite.org/atomiccommit.html) supplies +the all-or-nothing database transition, subject to its filesystem assumptions. +Keep the database and journals private to the server account. Run blocking +storage and pairing work behind bounded admission, outside the event loop; +transaction contention must not queue unbounded work or block health checks. +Only the server process mutates live authorization state through this interface. + +The approved default is twenty uncommitted enrollment requests server-wide, +configurable by the operator. Count pending, approved, exchanging and confirmed +requests against the same allowance. Reject new requests immediately when full; +do not create a waiting queue. Commit or terminal cleanup releases the slot. +This limit does not cap enrolled clients or consume their operation-worker +allowance. It bounds retained requests, not fair admission: spam during an open +window can still prevent a legitimate new enrollment. Bound creation rate, +message size, cryptographic work and terminal-record retention separately. + +| State | Meaning and permitted transitions | +| --- | --- | +| Pending | Holds a public selector, immutable key binding, creation/deadline, attempt count and version. No identity or account access exists yet. | +| Approved | Trusted administration has approved that exact request and chosen initial grants. The code is available only to the bounded live pairing context. | +| Exchanging | Reserve an attempt durably before emitting its exchange response. At most one exchange per request runs at a time. A failed or abandoned exchange consumes that attempt. | +| Confirmed | Both peers have confirmed the pairing key; the client has retained provisional server trust. Recheck deadline, approval/version and configured accounts before commitment. | +| Committed | One transaction records the enduring identity, issued credential, selected grants and recoverable completion result. Return credentials only after commit. | +| Expired, exhausted or rejected | Deny completion and release provisional resources. Never reactivate merely because the CLI or client reconnects. | + +Retransmission of a previously accepted message in the same exchange returns its +cached result; it is not a new password guess. A fresh cryptographic exchange +reserves another attempt. Conflicting messages for an existing exchange do not +overwrite its state. Do not serialize and replay a key-exchange implementation's +single-use state to achieve HTTP retry handling. On server restart, invalidate +uncommitted pairing contexts whose ephemeral secrets were lost and require fresh +pairing/approval. Keep durable committed identities and receipts. A CLI restart +alone has no such effect. Keep the pairing secret out of the authorization +database, logs and recovery exports; it belongs only to the bounded live +pairing context, not the durable client credential. + +Signing a credential and committing its authorization are distinct operations. +If signing occurs before the transaction, keep the result private and discard +it if the final conditional transaction fails. The transaction rechecks that +approval has not been rejected, replaced or expired and that its key binding +still matches. Concurrent completion must resolve to the same committed result, +not another identity or duplicate grants. A later revocation always takes +precedence over retrieval of an old completion result. + +Before submitting its final confirmation, the client persists its private key +and provisional server trust in private local files. After server commit, lost +responses can be recovered by proving possession of that same client key to +the retained server identity. This retrieval returns the committed result; it +does not create a new credential or restore revoked access. Terminal pending +records, cached exchange messages and completion receipts need bounded storage +and cleanup. The corresponding caps and retention profile remain open; expiry +checks must run when admitting or completing work, not depend solely on cleanup. + +This closes neither the complete wire profile nor T5: numeric resource caps, +receipt retention, local client state format, clock handling, recovery consistency +and crash/cancellation acceptance checks remain work. The state model requires +tests for duplicate approval, concurrent completion, lost final responses, +restart before/after commit and revocation racing with receipt retrieval. + +## Technical synthesis: portable identity and recovery + +This is a partial engineering proposal. The X.509 issuer/identifier/validity +profile and signed continuity format remain open; this section does not select +an invented identity system or claim that certificates alone solve continuity. + +Keep these records distinct: + +- **Owner authority:** the issuer material and explicit trust configuration + that permit verification of an owner's authority over a client. AMI manages + issuance for the current trusted operator; an ordinary agent credential + cannot act as an issuer or authorize another durable identity. +- **Enduring client reference:** the verified owner/client identity that an + independently enrolled server remembers across key replacement. It is not + a display name, HTTPS hostname, certificate serial number or current public + key fingerprint. Select the standard identifier/profile before implementation. +- **Current credential:** a signed binding between that reference and a key, + with its purpose, issuer, validity and revocation/continuity state checked. + A new certificate is not automatically proof that an older credential has + been superseded. Certificate serial numbers do not provide a general recovery + ordering mechanism. +- **Local enrollment:** the server's account grants, suspension/revocation + state, activity history and accepted credential state for that reference. + Importing owner trust or verifying a credential does not create grants. + +An identity-provider verification boundary must produce the verified owner and +client references, key/purpose and continuity result from evidence checked +against previously established trust. The request cannot nominate an arbitrary +new issuer and thereby recover an existing identity. External providers remain +future work; the boundary is not permission to deliver another provider now. +Do not copy an owner's private issuer/recovery key to agents or to another +independently operated server merely to support portable verification. + +Routine rotation proves the currently accepted client key and possession of the +new local key. Owner-approved recovery has separate authority: possession of a +stolen old client key must not produce an owner-authorized recovery event or +block a later valid owner-authorized replacement. Each server retains sufficient +authenticated continuity state to reject rollback to a superseded credential. +The exact signed evidence, ordering and issuer delegation profile need assessment; +ordinary chain validation is insufficient. For example, Go's +[`Certificate.Verify`](https://pkg.go.dev/crypto/x509#Certificate.Verify) does +not itself check revocation. + +Applying an accepted owner-recovery update must be an atomic local transition: +verify the authority and new-key proof, check continuity against remembered +state, replace accepted keys, invalidate old-key sessions and persist the new +state without changing the enduring identity or account grants. Preserve local +suspension and revocation. The result distinguishes replacement of credentials +from reinstatement of service access; it must not clear a local access denial. +Concurrent old-key rotation cannot reverse an applied owner recovery. + +### Technical proposal: portable ownership versus local access + +Provisionally accepted direction (D103, resolving U51): the owner accepts the +separate portable identity-key role for lightweight AMI, explicitly relying on +DBB review before finalization. Continue designing against this direction; +do not treat it as security signoff, production adoption or review authorization. +Portable identity and per-server authentication prove different things. An +ordinary access key for A must not become a credential for access or replacement +at B. A public name or UUID alone also cannot prove that a requester is the +agent whose ownership another issuer certified. + +Candidate structure using existing X.509 mechanisms: + +| Role | Private-key holder and permitted use | +| --- | --- | +| Owner issuer | The trusted AMI owner environment. Certifies the enduring agent identity; agents do not receive issuer or owner-recovery keys. | +| Portable agent identity | The client holds an owner-certified, non-CA identity key. Proves possession of that enduring identity during another server's enrollment. It grants no service access or account permissions. | +| Server-enrollment access | The client holds a separate key for each server, as approved in D72. Ordinary operations and local routine rotation use that key and the server's accepted enrollment state. | + +The [SPIFFE X509-SVID profile](https://spiffe.io/docs/latest/spiffe-specs/x509-svid/) +is an existing candidate for URI-based leaf identity and CA/leaf restrictions. +Its [identity standard](https://spiffe.io/docs/latest/spiffe-specs/spiffe-id/) +allows operator-controlled trust domains without public DNS registration. +Using the profile would not require deploying SPIRE. Its precise Arbiter URI, +issuer and interoperability profile is not selected here. A self-asserted owner +name or a new trust-domain spelling is not trusted ownership evidence. + +For first AMI enrollment, generate provisional identity/access keys locally; +the owner still authorizes creation of the enduring identity. Issue its owner +certificate only after that approval. For another server, verify the existing +identity against previously registered owner trust and prove possession before +binding its independently generated access key to the local enrollment. Public +owner trust can be imported without disclosing its private issuer key. Do not +silently trust an owner root supplied by the requesting agent merely because +it displays a familiar name. + +Use [PKCS#10](https://www.rfc-editor.org/rfc/rfc2986.html) for requested-key +proof rather than an invented CSR/signature format. Match the request keys and +CSR contents to the approved pairing record; do not honor arbitrary issuer, +CA or identity claims in a CSR. A reusable CSR is not fresh proof that its +presenter holds the key. The existing identity must also prove live possession, +for example through certificate authentication on the verified native TLS +enrollment-control connection. That control role must not gain ordinary access. +The complete handoff/binding profile still requires validation; neither the +pairing POC nor bare X.509 chain verification proves this integration. + +The portable key cannot authorize local key replacement at an already enrolled +server. Existing-server recovery still needs its explicit trusted owner approval; +neither a stolen A access key nor a stolen portable identity key can use this +path to replace B's accepted key. First enrollment with a new server also needs +that server's owner approval and explicit grants. No automatic admission of +all agents signed by an owner is added. + +Lightweight mode would store the additional private identity key alongside its +client-managed credentials. Theft could permit presenting that identity during +new enrollment requests, but would not by itself grant existing server access. +The owner provisionally accepted this additional key in D103; its complete +lifecycle/profile remains subject to the required DBB review. It is not the +owner's issuer key. Per-server access keys retain the approved automatic +rotation and inactivity rules; replacing a portable ownership credential must +be authorized by its owner issuer and cannot silently replace local access +keys or clear denials. Loss/expiry of this portable credential need not interrupt +an otherwise valid existing enrollment, but it prevents proving ownership for +another enrollment until owner-authorized replacement. No portable-key rotation +interval, additional operator ceremony or production dependency is selected. + +### Approved: authentication keys belong to a server enrollment + +Generate a distinct authentication key locally for each client/server +enrollment. Keep the enduring client identity portable, but bind the access +credential to the target server's durable identity, not its hostname or HTTPS +certificate. A server accepts a key only for its own explicitly approved +enrollment. Presenting the same client identity or another server's valid +credential must not enroll it, replace the local key or grant access. + +If the authentication key for server A is stolen, revoke and replace that +enrollment's credential on A. The stolen key cannot authenticate to B and does +not authorize replacing B's credential. No server registry, automatic server +discovery or cross-server notification is required. The earlier proposal to +notify every server assumed shared keys and an enrollment inventory; it was +not approved and is superseded by this decision. Its history remains in the +interview record. + +Apply the existing owner approval, account grants, rotation and inactivity +rules to each server enrollment. Recovery preserves that enrollment's identity +and grants without clearing its suspension or revocation. Migration or HTTPS +certificate renewal that preserves the server's durable identity does not +create a different enrollment merely because its address or certificate changes. + +This contains theft of an individual authentication key. An attacker who reads +the complete client credential directory may steal multiple enrollment keys; +that remains an accepted lightweight-mode risk. Owner/issuer/recovery-key +compromise is a different incident. The decision does not select artifact +encryption-key scope or add a client policy layer. The exact X.509 profile, +portable ownership proof and server-binding format remain technical work. + +### Technical implications of enrollment-scoped keys + +Keep a local credential record keyed by the trusted server identity and the +enduring client reference. Before trust is established, keep the newly generated +key in private pending state associated with the request identifier. Do not +derive private keys from URLs, the pairing code or a portable public identifier. +Only promote that record after the pairing exchange verifies the server identity +and the server commits the credential. A supplied URL is a destination, not +evidence that a credential belongs there. + +At the server, chain/ownership verification and local key acceptance are +separate checks. Ordinary access must match the enrollment's accepted public +key and credential purpose as well as its client identity and active status. +A certificate for the same identity issued elsewhere cannot replace that key. +Routine rekey proves the currently accepted local key and the new local key; +owner-approved replacement uses the existing recovery authority. Both bind the +target server and enrollment. Neither accepts proof from another server's +credential as authority to alter the local credential. + +The request/response authentication profile must cover the target server's +durable identity, request contents and freshness, rather than sign only a +portable client name. HTTP Message Signatures provides a candidate mechanism +for authenticated message components; the complete profile and replay state +remain to be specified. See [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421.html). +This binding must protect artifact HEAD/GET and download/tool paths as well +as operation JSON. The current native client has separate HTTP construction +paths for those downloads, so adding authentication only to the operation +client is insufficient. Authentication headers and signed requests must not +be forwarded automatically to a different destination through redirects; +migration to a new URL retains the remembered server identity and requires +verification before sending an authenticated operation. + +Sharing an enduring identity is already approved for transient helpers. Do not +reopen that principle when specifying installation credentials. A helper can +operate through its parent's existing Arbiter client/enrollment without a new +durable identity or separate enrollment for each helper. Helpers using the same +credential cannot be revoked independently; revoking that credential affects +all callers using it. Attribution labels do not create a separate authentication +or revocation boundary. + +### Deferred extension: independent installation credentials + +The owner approved deferring management of separately enrolled installations +under one enduring agent identity. Initial delivery keeps the existing AMI +new-identity enrollment, shared parent client for helpers, and separate +authentication keys for different server enrollments. Owner-approved recovery +can replace a lost or compromised enrollment credential while preserving its +identity and grants; it does not add a parallel installation credential. +Bounded credential overlap during routine rotation is a transition, not this +deferred feature. Lightweight mode cannot enforce physical installation +uniqueness or distinguish copies of the same credential. + +Keep identity, enrollment, credential and account-grant records logically +separate. Do not use the current public key as the enduring identity or make +account grants properties of a particular key. This permits a future extension +with multiple owner-approved, independently revocable installation credentials +under the same identity and grants. Do not implement the additional approval +flow, credential-management commands or per-helper credentials now. + +The future flow could attach a new installation's pairing request/key to an +existing identity through explicit trusted owner approval. Naming the identity +or knowing a pairing code alone would not authorize the association. Its final +UX and credential lifecycle require design when the use case is taken up. + +## Proposed options and deferred work + +X.509 is selected for AMI identity credentials; the complete authentication and +pairing protocols remain unselected. Confidential-execution +implementation is explicitly deferred as longer-term research. +The earlier [transport and identity notes](future/transport-and-identity.md) +provide historical context; their transport proposals are superseded and their +identity candidates are not binding selections for this design. + +### Enrollment nonce and completion + +The earlier proposal required a server-generated client-specific nonce handed +back through the operator. For AMI, the approved flow replaces that manual +return handoff with direct client/server completion after owner approval. Any +protocol nonce remains bound to the intended request and client; it is not a +generic invitation. The proof and nonce mechanism remain to be selected. + +Direct delivery alone does not establish initial server trust. For AMI, the +operator-mediated secret pairing exchange supplies that authentication and +binds the trust information received by the client. No extra manual fingerprint +comparison is required in this flow. Reuse an established pairing protocol; +none has been selected or implemented. PAKE-based tools such as +[Magic Wormhole](https://magic-wormhole.readthedocs.io/en/latest/welcome.html) +provide a precedent, not a selected dependency or external relay requirement. + +### Approved: planned server identity-key replacement + +Approved server-authority lifecycle (D104, U52): support operator-triggered +replacement of the long-lived server identity key. Clients verify and adopt a +legitimate planned transition automatically, without routine re-pairing. Keep +scheduled periodic replacement out of the initial scope; no interval is selected. +The durable server identity stays the same. This key is separate from public +HTTPS certificates and agent access keys; do not inherit the client's 30-day +rotation timer. Moving the same server identity to another host or renewing its +HTTPS certificate does not itself require replacing the identity key. + +Planned replacement supports deliberate retirement or an algorithm change; it +is not recovery from theft. A stolen old key can also endorse an attacker's +replacement. Compromise recovery requires an independent trusted owner path, +not automatic acceptance based only on that old key. The exact transition, +offline-client, restore and recovery mechanisms remain technical design work +subject to DBB review. This approval does not claim a working implementation. + +Existing PKI mechanisms support old-key-authenticated planned root updates; see +[RFC 9483 section 4.3.2](https://www.rfc-editor.org/rfc/rfc9483.html#section-4.3.2). +That is not evidence that a compromised old key can prove a replacement is +legitimate. Recovery from untrusted/lost identity authority needs independent +owner trust establishment; its precise implementation still needs DBB assessment. +No CMP implementation, new root key or rollout has been created here. HTTPS +renewal and proxy changes remain covered by the existing independence requirement. + +#### Technical proposal: planned trust-key transition + +This proposal implements D104's trust boundary on paper. It is not a deployed +rollover, selected certificate profile or evidence of interoperability. Keep +server trust replacement separate from client access-key rotation, owner +identity issuance and the backup-signing key. Replacing one role must not +silently replace the others or widen their authority. + +**Records and authority.** The client remembers the durable server reference, +its accepted server trust anchor and a local trust-record revision. The URL is +a route, not that reference. The server persists a replacement transaction +containing its server reference, predecessor/new anchor fingerprints, public +transition certificates and phase. A transaction identifier is for concurrency +and idempotency; it is not independent evidence of authority or a globally +ordered counter that survives arbitrary restores. + +Use X.509 CA-key transition certificates, rather than inventing a signature +scheme for a JSON key-update object. The replacement public anchor must match +the new key certified by the previously trusted authority. Validate the +certificate path, constraints, purpose and identity binding through the final +T2 profile. Supplying an old and new certificate in one response does not by +itself establish that relationship. The standard root-update mechanism is the +one referenced above; adopting that mechanism does not require exposing a CMP +service or importing an entire CMP implementation. + +**Preparation and activation.** Only trusted operator administration starts +the change. Generate the replacement private key locally. Stage its public +anchor, transition evidence and server presentation chain durably before +publishing any update. Check that the staged private key matches the new public +key and that both the current and replacement presentation chains validate in +the intended roles. A preparation failure leaves the current presentation and +authority untouched. Concurrent preparation is serialized against the exact +current authority; a stale command cannot overwrite a later activation. + +Publish the public transition material and switch the preferred presentation +as one recoverable server generation. The server must remain reachable by a +client that still trusts the predecessor: either the presented chain verifies +to that remembered anchor, or a bounded unauthenticated retrieval supplies +public transition certificates which the client can validate from that anchor. +Unverified retrieval may supply public data only. It must not receive agent +certificates, artifact nonces, ordinary operations or account information. +No outer HTTPS certificate or proxy assertion can authorize the trust change. + +**Client adoption.** Build the candidate verification context separately from +the active trust record. Require a valid transition from the currently accepted +anchor and then a successful native TLS handshake that proves the candidate +server holds the corresponding server credential for the same durable server +reference. An unsigned update hint, name match or increasing revision alone is +insufficient. Validate with normal certificate time and purpose checks; do not +accept an expired path simply to avoid asking the owner for recovery. + +Atomically install the verified new trust record using compare-and-swap against +the predecessor revision. Shared helpers must reload after another process +updates the record, rather than accepting whichever response arrived last. +Only after durable installation does the client acknowledge adoption over the +verified native channel. Failure to save is a local failure, not a successful +adoption; retain the complete previous record and retry only the idempotent +control transaction. Do not replay an operation or consuming download. + +**Disconnected clients and retirement.** Preserve public transition evidence +needed by supported offline clients; a client's failure to acknowledge does +not authorize extending its access or inactivity deadline. Existing inactivity, +revocation, grants and rotation obligations still apply. Server-side adoption +tracking is diagnostic and a retirement precondition, not authority to rewrite +a client's trust record. Acknowledgement loss is safe: a later authenticated +connection can report the same adopted anchor without creating another change. + +Retirement must not require retaining an old private signing key merely to +serve already-created public certificates. Do not silently delete transition +evidence or expand the verifier to accept every historical root indefinitely. +The chain/history byte limit, supported transition depth, validity overlap and +exact retirement preflight remain T2/T5 design gaps. In particular, retaining +only one transition without restricting or assessing repeated operator changes +would strand a client that missed two replacements. There is no approved +additional cutoff, automatic retirement timer or root-history fallback policy. + +**Restore and compromise.** Recovery bundles preserve the active authority and +in-progress transition transaction coherently. Restoring an older snapshot can +bring back an authority that an up-to-date client has already replaced. Do not +silently trust it again or borrow the client access-key predecessor fallback +for server trust. Report the trust mismatch and use the existing independent +owner-approved repair path when valid forward transition evidence is unavailable. +This preserves the accepted possibility of client repair after a stale restore; +it does not promise root rollback will be unattended. + +If the predecessor key may be stolen, do not use its transition signature as +sufficient recovery evidence. Trusted owner administration must establish the +replacement independently, through the pairing/recovery path. Do not force +clients to accept a peer merely because it claims the expected server name. +No automatic discovery or cross-server recovery registry is introduced. + +Required, unrun scenarios: current clients adopt while offline clients remain +able to verify; missed consecutive replacements; malformed or unrelated CA +transitions; wrong server reference; expiry; client/server crash at every +publication or persistence boundary; acknowledgement loss; concurrent helpers; +rollback to a stale backup; and compromise requiring independent repair. +Check unchanged grants, access-key deadlines, URL trust rules and operation +replay behavior. Full certificate profiles and concrete storage/transport +limits are still needed before this mechanism is implementation-ready. + +### Public HTTPS certificates + +Administration may be served through an Apache reverse proxy with Certbot-managed +public certificates so browsers trust its HTTPS endpoint. This is an optional +browser-facing deployment arrangement, separate from AMI identities and native +client pairing. It does not replace administrator authentication or select an +identity provider. The native Arbiter service need not use that public +certificate merely because the administration front end does. + +The CA-validated path can use certificates obtained and renewed by Certbot, +including Let's Encrypt certificates for the service hostname. Arbiter already +accepts a supplied certificate chain and private key through +`arbiter.server.tls.source=CERT_FILES`, `cert_file` and `key_file`. This is source +inspection evidence, not an executed Certbot integration test. Renewal must be +followed by a reload or restart of the TLS-serving process; certificate hot +reload has not been verified. Certbot can also manage HTTPS at a reverse proxy, +but proxy integration and any client-certificate forwarding are not selected. + +Public HTTPS server certificates authenticate the service hostname. They are +separate from AMI's authority to issue client identities; a publicly issued +server certificate does not give Arbiter CA signing authority over agent keys. +Keep HTTPS renewal independent of durable client identity and enrollment. + +This independence applies to all Arbiter identity providers, not just AMI. +Existing clients must continue to recognize the same Arbiter instance behind +a new transport certificate or proxy. The durable identity proof belongs at +the application layer; the HTTPS certificate identifies the transport endpoint. +Exact channel authentication, encryption, replay protection, streaming and proxy +rules remain to be specified using established mechanisms. The previous +signature-only candidate cannot satisfy the newly approved confidentiality +requirement: signatures authenticate contents without hiding them +([RFC 9421 section 8.2](https://www.rfc-editor.org/rfc/rfc9421.html#section-8.2)). + +### Approved: encrypted native API and browser administration + +On 2026-10-19, the owner accepted encryption directly between native clients +and Arbiter regardless of the forwarding proxy, and explicitly retained the +future browser admin interface. This supersedes Q21/D60's decision not to +require an inner encrypted native API channel. It does not change the current +single-owner trust model or claim protection from the Arbiter operator/server. + +The native client authenticates the durable Arbiter identity established by +pairing, and Arbiter authenticates the enrolled client. Ordinary native API +requests/results travel only after that authenticated encrypted channel is +established. An outer HTTPS proxy forwards ciphertext; changing its certificate +must not replace the remembered Arbiter identity or require reenrollment. +Proxy certificates alone do not authorize access to the inner channel. Routing +and traffic metadata may remain visible; the proxy can interrupt or deny service. +No channel protocol, TLS-verification bypass or plaintext fallback is selected +by this direction alone. Bootstrap, redirects, channel establishment and failure +handling need explicit rules before implementation. + +Arbiter decrypts the native messages itself and still sees upstream plaintext +while enforcing policies and preparing responses. The future prompt-injection +inspection direction remains viable. Proxy confidentiality is distinct from +server-side storage encryption and the separately approved recipient encryption +of downloaded artifacts; preserve their access, retention and export rules. + +Browser administration is a separate authenticated surface using normal HTTPS +and browser certificate validation, including a publicly trusted certificate at +Apache where configured. It need not use the native channel or install native +agent credentials. Its future login/session/authorization design must protect +administrator operations; the encrypted native endpoint must not introduce an +unauthenticated browser-admin path or a plaintext fallback to ordinary native +service operations. The admin UI is not brought into the current delivery by +this reminder. Initial owner approval through local/SSH CLI remains available. + +The additional implementation cost is an authenticated channel/transport +adapter, bounded session/handshake state, streaming and reconnect behavior, and +tests through a real forwarding proxy. Prefer an existing mature protocol over +designing encryption primitives or assuming the pairing PSK profile can be +reused for ordinary API sessions. The temporary pairing secret is not a durable +API credential. These are engineering requirements for T3, not implemented or +security-reviewed behavior. + +References: [Certbot user guide](https://eff-certbot.readthedocs.io/en/stable/using.html), +[Let's Encrypt validation methods](https://letsencrypt.org/docs/challenge-types/). + +The Q37 proposal to register/endorse each unrelated self-signed proxy authority +is not selected. The owner chose the encrypted native channel instead. The +earlier discussion remains in the interview ledger as history, not a pending +decision or an additional operator step in the selected native-client flow. + +### Technical candidate: TLS inside a proxy-forwarded tunnel + +A concrete candidate is standard TLS 1.3 between the native client and Arbiter, +carried as opaque bytes over a dedicated WebSocket path. The outer HTTPS +connection may terminate at Apache, while the inner TLS connection terminates +only at Arbiter. Pairing supplies the trusted identity material for the inner +connection; its certificates/keys are separate from the outer HTTPS certificate. +The existing X.509 identity direction fits this candidate, but exact certificate +profiles, ownership/continuity and revocation checks still belong to T2. +This is a proposed protocol/transport combination, not selected or tested. + +Python's standard `ssl` library provides TLS 1.3 and MemoryBIO operation in the +supported Python range, and Go's `crypto/tls.Client` can wrap a `net.Conn`. +That provides an existing cryptographic implementation for the byte channel +without turning the initial pairing PSK into a permanent secret. Source/API +checks establish feasibility only; no Python/Go TLS-over-WebSocket exchange, +real Apache deployment or cross-platform test has run here. Sources: +[Python 3.10 SSL](https://docs.python.org/3.10/library/ssl.html#memory-bio-support), +[Go TLS](https://pkg.go.dev/crypto/tls#Client). + +The server would expose separate outer routes for minimal bootstrap, the opaque +native tunnel and future browser administration. Both the native route and +browser UI could share one public HTTPS port. Browser administration keeps +normal certificate validation and its own future administrator authentication; +it does not pass through the native tunnel or become an alternate plaintext +operation API. Native operations must never fall back to an outer plaintext +route when the tunnel or inner identity check fails. + +Keep the existing core operation/artifact application and global admission +state. The adapter must propagate a caller identity derived from the verified +inner channel into request authorization; proxy-supplied certificate headers +are not that evidence. ASGI defines a TLS extension for verified peer-chain +metadata, but inspecting the installed Uvicorn 0.48.0 HTTP protocol code did +not establish such integration. Identity propagation, application lifecycle, +streaming/backpressure and cancellation are real adapter work to prove before +adoption. Do not create independent unbounded queues, duplicate artifact stores +or a second authorization path to avoid that work. A valid handshake alone +does not bypass current enrollment, grants, revocation or inactivity checks. + +The deployment consequence is that a reverse proxy must forward WebSocket +upgrades/binary traffic on the native path and support the required stream +duration. Apache documents this capability, including cohosting ordinary HTTP +routes; modern Apache can handle upgrades through `mod_proxy_http`. +See [Apache's tunnel documentation](https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html). +This is ordinary reverse-proxy configuration. Q38 was withdrawn after the +Apache clarification; it is not an additional operator policy approval, and +the clarification does not select a final transport implementation. +Do not silently add an ordinary-HTTP encrypted-envelope fallback as a second +protocol. Outer-certificate handling, redirects, session bounds, reconnects, +resumption and failure semantics remain design work after that disposition. + +### Technical proposal: integrate the encrypted native channel + +Retain the current JSON HTTP API inside the authenticated channel. This is not +an MCP migration. Use the existing HTTP request/response and artifact streaming +contracts rather than inventing another operation message format. The initial +candidate carries HTTP/1.1 over inner TLS 1.3 over the WebSocket byte stream. +WebSocket frame boundaries are transport boundaries, not HTTP message or TLS +record boundaries. Use existing implementations for all three protocols. + +The client needs one authenticated transport used by operation/discovery calls, +artifact HEAD/GET, stdout processing, temporary tool files and `save-decrypted`. +Today those artifact paths construct requests separately in `cli.go`; changing +only `arbiterhttp.Client.RunOperation` would leave the contract incomplete. +Resolve relative artifact paths against the remembered enrollment. Do not send +client credentials or artifact nonces to a new authority through automatic +redirects. A new deployment address must prove the same durable Arbiter identity +before an authenticated operation or download is sent. A redirect is never +permission to invoke an operation again or to enroll another server. + +The outer public listener exposes only bounded bootstrap, the native tunnel +entry point and the future separately authenticated browser-admin surface. +It must not also publish ordinary operation/discovery/artifact routes outside +the inner channel. A WebSocket upgrade grants no service authority. Do not use +proxy headers, source addresses, browser cookies or outer TLS certificates as +evidence of an enrolled native caller. Transport errors must not trigger a +plaintext fallback. Native authentication material travels only inside the +authenticated inner connection. Browser administration continues to use normal +HTTPS and does not inherit the native transport's certificate rules. + +The inner TLS verifier must check the paired server identity and purpose, and +verify the enrolled client's certificate/key. Chain validation is necessary +but insufficient: the accepted key, credential generation, revocation, +inactivity and account grants also come from Arbiter's authoritative local +state. T2 must define the exact identity certificate and issuer profiles. +Disable TLS early data for this candidate: TLS 1.3 0-RTT does not give the +ordinary handshake's replay guarantees. Start without session resumption so +there is no ticket-based path around credential replacement or revocation; +any later optimization must preserve those checks. TLS record replay protection +does not make an application operation safe to retry after a lost response. +See [TLS 1.3 replay considerations](https://www.rfc-editor.org/rfc/rfc8446.html#section-8). + +The verified channel supplies an immutable caller context to the existing ASGI +application. Maintain one shared application/admission/store lifecycle; do not +instantiate an independent worker pool for every connection. Register active +requests and streams against the enrollment and its authority generation. +Check current authority before dispatch and invalidate registered work when +revocation, suspension or grant removal takes effect. Synchronize registration +with invalidation so work cannot escape termination by racing a state change. +Subsequent requests on an established connection must not rely on the old +handshake alone. Closing the affected channel stops delivery; existing blocking +work keeps its capacity until it actually exits. Already committed upstream +actions cannot be undone. Restricted rotation completion after grace expiry +must not become ordinary access through a previously authenticated connection. + +Carry cancellation and backpressure through every layer. A lost WebSocket or +failed TLS stream closes its underlying resources and signals HTTP disconnect; +it does not enqueue a replacement operation. Keep the current shared admission +before operation-body reading, the 1 MiB body ceiling, and streaming capacity +ownership through file closure. Bound transport frame buffers, incomplete +handshakes and active channels separately: the eight blocking workers do not +bound idle tunnels or TLS handshakes. Numeric transport limits and overload +handling remain T5 work, not newly approved defaults. WebSocket control traffic +must not count as artifact payload progress for the download idle timer. +Open capacity decision U53: propose a configurable server-wide ceiling of 64 +open native encrypted connections, counting both authenticating and established +tunnels. This is a proposed default, not approved or implemented. Reserve before +accepting the WebSocket/starting inner authentication, reject excess without +an unbounded waiting queue, and hold the slot through actual cleanup. Existing +connections continue; ordinary health and trusted local control do not consume +this native allowance. A connection cap does not cap enrolled identities, bound +all OS/listener resources, or replace separate handshake CPU/time/byte limits. +Helpers sharing one identity still consume a slot for each open connection. + +Connection setup includes the outer connection, upgrade and inner handshake +under the existing separate connect budget; do not reset that budget at each +layer or turn it into a total artifact-download limit. + +This proposal specifies integration obligations, not a demonstrated adapter. +The native transport trust profile below derives the outer/inner separation +from the approved certificate-independence requirement. It does not approve +a generic HTTPS verification bypass. An isolated channel integration check still needs to prove +verified peer identity reaches ASGI, streaming remains bounded through Apache, +the browser route coexists, wrong inner identity fails closed, and disconnect, +revocation and interrupted rotation retain their existing semantics. The +pairing POC does not supply that evidence. No new interoperability check, +production implementation or independent review ran for this section. + +### Technical proposal: native transport trust and browser boundary + +The native connection authenticates the durable paired Arbiter identity at the +inner TLS layer. Its outer WebSocket carrier is not an authenticated Arbiter +endpoint merely because its HTTPS certificate validates. Conversely, requiring +the owner to approve each new self-signed outer authority would reintroduce the +certificate dependency rejected in D40/D78. In this candidate, outer certificate +chain/hostname validation is not the native identity acceptance gate. Inner +certificate, purpose, remembered identity and enrollment checks remain mandatory. +A changed inner identity fails closed even when the outer certificate is valid. +This is an engineering consequence of the agreed end-to-end trust boundary, +not a new product option allowing unauthenticated ordinary API requests. + +Implement that rule only in a dedicated carrier that returns an authenticated +inner stream, never in a general-purpose HTTP client. Keep outer and inner TLS +configurations separate. Do not inherit the outer carrier's validation settings +into the inner verifier, reuse its HTTP transport for ordinary operations or +offer an automatic fallback after inner authentication failure. The proposed +outer carrier remains WSS; do not silently switch schemes or destinations after +a failure. Bound and validate the HTTP upgrade, WebSocket and TLS inputs even +when an attacker controls the outer endpoint. This isolates certificate trust; +it does not permit malformed or obsolete TLS or an unbounded bootstrap parser. + +The outer request contains routing and upgrade information, not enrollment +credentials, owner/client certificates, account names, artifact nonces or +browser-admin cookies. No persistent cookie jar or automatic authorization +headers belong on that transport. Only minimal public bootstrap/pending data +may precede authenticated pairing. The one-time secret and private keys never +travel there. Pairing must complete its PSK-authenticated exchange and bind the +request, roles, proposed client key and server identity before persisting trust. +After enrollment, complete and verify inner TLS before sending service requests. +Refusing an unexpected inner identity never triggers silent trust replacement. + +These are layered-protocol requirements to assess in the adapter POC and DBB +review. Go documents that bypassing its default certificate validation does +not authenticate a peer by itself, and provides custom verification callbacks; +our inner identity check must perform real validation rather than return success +unconditionally. See [Go TLS configuration](https://pkg.go.dev/crypto/tls#Config). +No source-level API inspection proves the composed transport secure or tested. + +Browser administration has a different endpoint: if HTTPS terminates at Apache, +Apache can read the admin requests, responses and session credentials, and can +change the delivered page. The native client's inner encryption does not protect +browser administration. Encrypting Apache's backend connection to Arbiter does +not hide this plaintext from Apache itself. This follows from TLS protecting +traffic between its endpoints, combined with HTTP request forwarding: +[TLS 1.3](https://www.rfc-editor.org/rfc/rfc8446.html#section-1), +[Apache reverse proxy guide](https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html). + +Browser-admin deployment guidance (corrected U39): any TLS terminator that +serves administration must be treated as trusted with its plaintext and session +authority. This is a security assumption and deployment recommendation, not an +Arbiter-enforced allow/forbid switch. In the ordinary browser design, Arbiter +cannot reliably determine whether an upstream proxy terminated the browser's +TLS connection and then established a separate TLS connection to the backend. +Requiring HTTPS at Arbiter alone does not prove end-to-end browser TLS. +Document that direct/TCP-passthrough HTTPS avoids exposing admin plaintext to +the forwarding proxy, while HTTP reverse-proxy termination includes that proxy +in the trusted environment. Private loopback/SSH access stays the default +private path. U39's allow/forbid question is withdrawn, not counted as approval +of a topology. No new client-proof mechanism or browser implementation is +selected to enforce the deployment assumption; document and test actual supported +configurations without claiming automatic detection of remote TLS termination. + +Public deployment recommendation pending DBB (2026-10-19): retain TCP +passthrough and Apache HTTPS reverse-proxy termination as candidate supported +topologies. The owner wants one clearly recommended operator setup, rather +than presenting both as equal default instructions. Ask DBB to recommend that +setup after assessing trust/compromise boundaries, certificate issuance and +renewal, backend protection, available request filtering and likely operator +misconfiguration. Identify the concrete security requirements for the alternative +and any extra implementation/testing cost before committing to dual support. +Neither topology is selected as the recommendation yet, and current compatibility +has not been demonstrated. This defers the public recommendation to the required +review; it does not start DBB, expand UI delivery or change the approved private +loopback/SSH default. Do not claim that Arbiter can forbid an operator's proxy +topology or automatically verify where the browser's TLS terminates. + +Approved private browser-admin direction U40 (2026-10-19): how the operator reaches and trusts the +future admin page without mandatory public DNS or certificate installation. +The owner accepted a baseline serving the UI only on loopback, opened through an +authenticated operator command; remote operators use a verified SSH connection +and a loopback-bound tunnel. This avoids a browser connection to an unknown +remote self-signed endpoint. It also requires SSH access for remote use and +does not support simply opening a LAN URL from any device. Local browser HTTP +is an approved exception to the general browser-HTTPS direction, protected by +loopback confinement and, for the remote hop, authenticated SSH. This approves +the access direction, not an implemented or security-reviewed session scheme. +The browser session still needs explicit operator authentication, +strict Host/Origin handling and CSRF protection; a loopback source address alone +is not administrator authority. No generic agent enrollment credential gains +admin privileges, no anonymous local-admin route is implied, and no browser +certificate-warning bypass is proposed. References: +[OpenSSH local forwarding](https://man.openbsd.org/ssh#L), +[browser secure contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts). + +U40 clarification: loopback HTTP removes certificate provisioning, not local +browser/session risks. SSH encrypts the inter-machine hop; the loopback HTTP +legs remain plaintext and trust their respective hosts. Local processes can +connect, and unrelated web pages may attempt local requests, so explicit +operator-session authorization and exact Host/Origin/CSRF checks remain +necessary. Cookies are not isolated by port; an ordinary shared localhost +session cookie must not be assumed safe from other local services merely +because Arbiter chose another port. The session design must prevent that +leakage and bound session lifetime. Browser treatment of localhost as a secure +context does not mean loopback bytes are TLS-encrypted, and browser-specific +Secure-cookie exceptions are not a portable security contract. This is an +unresolved design/DBB review obligation, not evidence of an implemented leak +or a selected cookie/token solution. References: +[cookie port scope](https://www.rfc-editor.org/rfc/rfc6265.html#section-8.5), +[CSRF defenses](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html). + +### Proposal: direct enrollment of a known client + +Minimize operator interactions. With the client's identity already established, +the operator could supply its public identity material through trusted server +administration and explicitly authorize that client in one operation. The +server would return a client-bound enrollment bundle containing its nonce and +server trust information. The operator would deliver the bundle to the client, +which would complete the selected mutual-authentication protocol automatically. +Account grants could be selected during the same administration operation while +remaining separate authorization state. + +This earlier alternative is not the approved AMI flow; its manual return +handoff has been superseded for AMI. It was a proposed replacement for the +open-window/pending-request sequence for +this journey, not an additional approved flow. The user requires streamlining; +the replacement, nonce-as-approval semantics and protocol remain unapproved. +Providing client identity material to the operator is still necessary unless +the operator already has it; do not omit that handoff from the UX assessment. + +### Approved direction: Arbiter-managed identity (AMI) + +For lightweight mode, the trusted Arbiter server represents the owner and +provisions new client identities with the owner's approval. This combines +identity issuance and enrollment, avoiding a separate owner-side issuer and +manual CSR handoff. This direction is approved for lightweight mode, extending +the initial POC proposal. Do not apply it automatically to external identities +or hosted deployments with owners distinct from the operator. + +The owner, acting as the client operator, initiates enrollment from the client +side. The client software performs the protocol on the owner's behalf; it does +not independently decide to enroll or create a durable identity. Server-side +approval remains a separate authority step, even when the same person performs +both roles. + +The approved flow is for the client to generate a key pair locally, submit +its public key in a pending request and display a one-time secret pairing code. +Through trusted server administration, the owner supplies that code and approves +the intended pairing. The secret authenticates the pairing exchange rather than +merely selecting a public request record. The server then assigns the durable client +identity and issues the corresponding credential. The client waits for approval +and receives its credential and completion messages directly from the server; +the owner does not manually pass a completion bundle back to it. The server +issues an X.509 agent identity certificate. Exact approval +binding, credentials and account-grant steps remain to be designed; this is not +a finalized protocol. The agreed name is Arbiter-managed identity (AMI). + +Incomplete enrollment must not accumulate abandoned state on either side: + +- Bound pending requests and their lifetimes. Rejection, cancellation and + expiry must reclaim request state and provisional resources. +- Keep new local keys and credentials in recoverable provisional state until + enrollment completes. Clean abandoned temporary files without deleting an + existing identity or unrelated enrollment. +- Make retries resume the same attempt rather than create duplicate identities, + credentials or grants. Recovery must cover crashes, disconnects and a lost + completion response, including interruption after owner approval or issuance. +- Track issued credentials and any identity/grant changes through completion or + explicit reconciliation. Do not leave orphaned authority, and do not delete a + completed enrollment merely because its final acknowledgement was lost. + +These are cleanup and recovery requirements, not a selected transaction or +storage protocol. Expiry values, retry rules, activation timing, audit retention +and acceptance tests remain to be specified. + +### Agreed: recovery after loss of server state + +Q22 concerns loss of the server's durable identity keys and authorization +records, not ordinary HTTPS certificate renewal or recovery of one client's +key. Approved first-delivery contract: restore the same server identity, +enrollments and grants from an operator-protected, consistent backup. Without +such a backup, initialize a new server identity; existing clients must explicitly +pair with it and the owner must grant account access again. Do not silently +trust a new identity because the hostname is unchanged. Surviving client +identities do not need to be recreated merely because the server was lost. + +Use an encrypted recovery bundle. The recommended ongoing backup arrangement +is an external, operator-controlled process that asks Arbiter to produce a +bundle and saves the ciphertext to durable storage, such as Dropbox (D87). +That process owns scheduling, transfer, retention and reporting failed backups; +Arbiter owns producing a consistent, complete encrypted snapshot on request. +Arbiter does not need an internal backup scheduler or a Dropbox integration. +Dropbox is an operator-managed storage destination, not a required integration +or identity authority. Provide an explicit recovery flow that accepts the bundle and its +decryption material, validates it before activating restored state and restores +the durable identity and authorization records together. The format, export +trigger and exact commands remain to be designed. + +Owner clarification (D86/D87): backup should be ongoing, not a one-off action +positioned before or after first enrollment. Arrange external backup requests +from startup and thereafter; this is a coverage goal, not a promise that every +server mutation is synchronously copied off-host. A snapshot taken after +enrollment includes that enrollment; a prior snapshot needs a later refresh to +include it. Starting backups later leaves the earlier interval without backup +coverage; it does not require reenrolling clients or change their credentials. +Recipient provisioning, snapshot consistency, export authorization and failure +handling still need design. The owner has not approved optional-setup/doctor +warnings or an enrollment-blocking prerequisite; do not infer either. + +The backup process needs only ciphertext and permission to request an export; +it does not need the private recovery key. Use the server-configured recovery +recipient rather than allowing the requester to substitute its own recipient. +An export contains operator-level secrets and must not become an ordinary agent +capability merely because the process calls Arbiter. First delivery uses a +trusted local administrative command, also callable over SSH (D88). The external +job can invoke that command and transfer the resulting ciphertext to durable +storage. Direct remote export through the Arbiter API is deferred; no new +agent export permission or remote administrative credential is introduced. +The exact local command/control protocol remains engineering work. The external process must distinguish +a requested/partial export from a completed bundle stored durably. Export success +alone is not evidence that off-host storage succeeded. + +The same bundle should support migration to a new host while preserving server +identity, enrollments and grants. An address change may require updating the +client's configured URL, but moving the same identity must not require pairing +again. Migration needs a controlled cutover rather than two independently active +copies of the same identity and authorization state; details remain open. + +Approved bundle contents (Q26): include account configuration, policies and the +upstream service credentials needed to restore working accounts, as well as +identity/enrollment/authorization state. Recovery must be useful on a new host, +not merely restore identity records or unresolved secret references. This is an +application recovery bundle, not a host-image, upstream-mail or client-file +backup. Its private key can decrypt the included service credentials as well. + +Verified checkout detail: all four staged IMAP/SMTP account password fields use +`oc.env`, and `reploy-staging/conf/arbiter-server.yaml` configures +`../.arbiter.env`. That file exists. `load_env_file` reads it into the process +environment using `os.environ.setdefault`, so already-set process values take +precedence. This is file-backed credential configuration accessed through +environment interpolation, not a `secret_file` reference. Source configuration +also supports `secret_file`. Only source types and the file's existence were +checked; no secret values were resolved or printed and no running process was +inspected. Restore the configured credentials securely; do not export arbitrary +unrelated environment variables. Exact capture and restore mechanics remain +engineering work and must preserve normal config-display redaction. + +This does not require a separate recovery service. Backup contents, consistent +restore and stale revocation handling require engineering; restoring an arbitrary +old snapshot is not guaranteed to restore current authorization safely. Neither +recovery nor migration tooling is implemented. + +Approved first-delivery scope (Q23): provide the simple operator experience, +"here is the private key for the backups, keep it safe." Associate this recovery +credential with the operator rather than introducing another backup identity. +Configure its public key on the server for unattended exports. The operator +keeps the private key outside the server, agent environment and bundle-sync +destination, for example in a password manager or a protected offline copy. +Recovery uses the encrypted bundle plus that private key. Losing all copies of +the key makes the bundles unrecoverable. Setup and restoration use trusted +operator tooling; the agent does not receive this credential. + +Passkey-based unlocking is a future option, not an initial implementation +requirement. Keep the design compatible with an operator credential store that +can unlock the recovery capability, without requiring literal reuse of an +identity signing key for encryption. PRF support varies by provider and platform; +domain binding and passkey-loss recovery must be addressed before delivering +that option. No Bitwarden dependency or passkey-provider integration is selected. + +The file format and precise identity binding/provisioning remain to be designed. +Public-key file encryption is established tooling +([age usage](https://github.com/FiloSottile/age#usage)); automatic exports do not +need the private key. Bundle origin, integrity, snapshot consistency and safe +restoration still need verification; encryption to a public key alone does not +prove who created a bundle. No encryption or recovery implementation is claimed. + +Approved restore behavior (Q24): decrypt and validate the bundle, then restore +its saved state. Warn with the snapshot date that changes after that date are +not included. Do not add a mandatory permissions review, paused-access mode or +separate activation confirmation. A snapshot predating a revocation can restore +that client's earlier access; the warning must not imply that later changes were +reconstructed or preserved. The operator can make subsequent corrections using +normal administration. For planned migration, use a final consistent bundle at +cutover; exact snapshot and cutover mechanisms remain engineering work. + +Approved restore UX (D89, resolving U44): restore the full saved Arbiter +configuration by default, including its host-specific Arbiter settings. Do not +silently merge with or preserve unrelated target configuration. On another host, +the operator adjusts the restored public URL, ports or paths through normal +configuration before starting Arbiter; no restore-specific override mechanism +or settings wizard is required. This does not restore OS/Reploy/Apache/DNS +configuration. Command spelling remains illustrative, not an implemented API. + +Required undo capability (D90): preserve a coherent recovery point for the target +configuration and state immediately before restoration, so the operator can +revert if the restored system proves broken. Preserve configuration, secrets, +identity and authorization together, not just the configuration files. Restore +validation failure leaves the original state intact; undo must also remain +available after a restore completed successfully and the operator tried it. + +Proposed UX: print the recovery-point reference and an illustrative +`arbiter-server restore undo ` command after a successful restore. +The operator stops Arbiter before undo; undo reactivates the retained pre-restore +generation as one consistent state. It must not depend on the restored server +starting successfully or on downloading the original incoming bundle again. +It reverses local configuration/state replacement, not upstream email operations +or later actions already performed by clients. If there was no prior installation, +report that explicitly rather than promising a previous working server. +Approved undo retention (D99, resolving U48): keep only the latest pre-restore +recovery point, without automatic time expiry. Replace it only after the next +successful restore, or discard it at the operator's explicit request. A failed +restore preserves the existing undo point. This supports undo of the latest +restore, not an arbitrary history of restores. Protect its configuration, +secrets, identity and authorization together. Transient activation storage and +crash-safe cleanup still need an engineering profile; no additional +restore-activation confirmation or multi-generation history is selected. + +Approved restore-undo scope and warning (D100): undo reverses a specific bundle +restoration to its retained pre-restore state. It remains available after the +server has resumed normal use; do not impose a hard cutoff. In that case show +a prominent, high-severity warning before proceeding: local configuration and +state changes since that restore will be lost, including later enrollment, +credential rotation, grant and revocation changes. Upstream email actions already +performed will not be reversed. Show the restore identifier and relevant dates; +do not imply that undo merges subsequent changes or reconstructs current state. +This clarification does not select an additional confirmation prompt or bypass +the existing stopped-server requirement. Retention remains D99's single latest +point, without automatic expiry. No general snapshot-history feature is added. + +Technical proposal for warning delivery: associate the recovery point with the +specific restore identifier, pre-restore state date and restore-completion date. +Before undo replacement, print the affected dates and destructive effects on the +operator diagnostic channel, including in noninteractive use. When subsequent +server use is known, or absence of intervening use cannot be established, use +the high-severity form below. Do not claim an exact number of lost changes or +treat a missing activity record as proof that nothing happened. Warning detection +must not become an authorization gate or a reason to disable undo. + +```text +DANGER: UNDOING THIS RESTORE WILL DISCARD LATER LOCAL CHANGES +Restore: , completed