# AiMe Architecture

Status: Draft, not approved for production use  
Last updated: 2026-08-15

## Objective

AiMe lets a user-authorized ChatGPT conversation call narrowly scoped tools on
the user's Windows computer through MCP. The first milestone was deliberately
read-only: status, one-directory listing, bounded UTF-8 file reads, and
profile-gated `search_text_files` on the supported default stdio/tunnel route.

## Clean-room boundary

Khai Hub and the public Universal Body GPTHAND documentation are observable
reference products. AiMe may reproduce independently derived behavior and
interoperable protocols, but it must not copy proprietary code, binaries,
assets, credentials, signing material, or private service interfaces.
Public observations and inferences are recorded separately in
`REFERENCE_PRODUCT_SECURITY_REVIEW.md`.

## Proposed trust boundaries

```text
ChatGPT Chat
    |
    | OpenAI Secure MCP Tunnel (outbound HTTPS)
    v
OpenAI tunnel-client (standard user)
    |-- control-plane runtime key delivered by a private one-shot pipe
    |-- spawns one explicit AiMe stdio command
    v
AiMe standard-user process
    |-- MCP schema and local policy boundary
    |-- local policy and consent broker
    |-- privacy-preserving audit sink
    `-- narrowly scoped workers
          `-- approved Windows filesystem roots
```

Design decisions:

- Use the official [OpenAI Secure MCP Tunnel](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels)
  as the initial remote transport instead of exposing a public listener or
  operating a custom reverse tunnel.
- Treat the ChatGPT workspace and Platform organization association as the
  upstream caller gate. The stdio protocol does not establish a verified
  ChatGPT user or conversation identity for local policy decisions.
- Keep the tunnel runtime key outside the Node MCP process. The official tunnel
  client currently lets a stdio child inherit its process environment, so a
  persistent key is stored only as a DPAPI CurrentUser blob. A native supervisor
  decrypts it into a private one-shot named pipe and rewrites a fixed `file:`
  sentinel immediately before launch. The tunnel process starts with a strict
  environment allowlist; the key value is never placed in argv, environment,
  JSON control messages, logs, or the MCP child.
- Use forward-slash absolute paths in the tunnel stdio command. The current
  upstream command parser treats backslashes as escapes, including inside
  quotes.
- Bind tunnel health/admin endpoints to an ephemeral loopback port. Do not
  enable the remote admin UI; loopback is not an authentication boundary
  against other local processes.
- Run the main application as a standard user. Do not elevate a user-writable
  application tree.
- Keep the initial externally reachable MCP surface to exactly `get_status`,
  `list_directory`, and `read_text_file`. Unknown tools and unknown input
  fields fail closed. Higher-capability tools remain local-only until their
  separate release gates pass.
- Identify approved roots by local aliases. Never disclose the absolute root,
  hostname, account name, environment variables, IP address, or bearer tokens
  through status or error responses.
- Store persistent secrets with Windows DPAPI or Credential Manager, protected
  by an explicit user-only ACL. Never store them in plaintext JSON.
- Do not expose write, shell, clipboard, screen, browser, UI automation, or
  admin capabilities through stdio or Managed transport until each has a
  separate threat model, user-presence policy, and release evidence. Internal
  local-only tests may exercise an independently gated capability first.
- If privileged operations are ever required, use a minimal separately signed
  broker installed under an administrator-owned location with narrow IPC. The
  desktop process itself must remain unelevated.

## Current prototype

The repository contains a real stdio MCP host for the three read-only tools,
strict profile loading, fail-closed JSONL audit, and a Windows native filesystem
helper. On Windows, production reads and directory listings use handle-relative
opens, validate the root file identity, reject reparse points and multiple hard
links, and return data from the verified handle. Non-Windows development keeps
the pathname backend.

The prototype also contains a pure Windows launch-plan builder for the official
Secure MCP Tunnel client. It invokes an absolute executable directly without a
shell, sends only a fixed runtime-key sentinel to the native supervisor, strips
the parent environment down to `SystemRoot` and `WINDIR`, uses forward-slash
paths for the upstream nested-command parser, fixes health to an ephemeral
loopback listener, disables both remote and automatic web UI, and writes tunnel
logs to a separate file. Mutable health and log files are derived inside a
dedicated run directory; binaries, configuration, and the DPAPI key blob must be
outside that directory. Path inputs reject rooted-but-not-drive-qualified paths,
namespaces, UNC, alternate data streams, traversal components, reserved DOS
names, DOS short-name syntax, trailing dot/space aliases, wildcards, quotes,
and control characters.

The built stdio artifact is exercised end to end on Windows. Tests prove that
the production route rejects a hard link, does not leak the outside canary, and
exits without serving when the native helper is missing. This remains a
prototype, not a release candidate.

A separate Windows-local composition now loads one schema-v2 profile, owns
native Read and Modify runtimes plus JSONL/protocol audit, binds a pending-action
broker to a native default-Deny confirmation UI, and connects an AiMe MCP server
to stdio only through the protocol-audit wrapper. Real Windows tests cover
`create_text_file`, exact structured single-file `apply_patch`, expected-content
`replace_text_file`, and bound rollback. Apply compiles strictly ordered,
newline-sensitive hunks into one content replacement, binds the old, patch, and
result digests through confirmation, and reuses SafeFs atomic publication and
rollback artifacts. Tests cover idempotent retries, exact-byte restoration,
mismatch/change-ID denial, redacted confirmation and audit records, native
handle cleanup, UI exit, startup interruption, and ordered shutdown.
`preview_patch` is implemented internally as a metadata-only Modify preview
but remains outside the release surface. Move and delete remain unavailable on
the Modify surface. The profile-gated `search_text_files` tool is exposed by
the supported default Read stdio/tunnel route. It is an exact literal,
case-sensitive, UTF-8 recursive search with a query
capped at 256 UTF-8 bytes and no NUL, CR, or LF, one first
match per line, line and UTF-16 column reporting, and deterministic
handle-relative Windows traversal without reparse points. It uses a dedicated
cancellable helper so ordinary reads are isolated. Its audit records contain
only redacted counters, truncation reason, and root/path fingerprints. The direct child
is internal and has no public npm start script. A dedicated pre-release tunnel
composition can supervise it while retaining both native helper paths as
immutable inputs. It publishes no Managed security metadata and is not an
accepted release surface.

A lower-level internal profile-v2 `run_process_preset` composition and direct
test harness expose asynchronous `start_process_preset`, `get_process_task`, and
`cancel_process_task` MCP tools. The caller selects only an approved preset; the
profile fixes its absolute executable, executable SHA-256, argv,
workspace-relative cwd, root, display title, and limits. Exact local
default-Deny confirmation is bound to those fields before the native runner
starts the standard-user child suspended, verifies the retained root and
executable, assigns a kill-on-close Job Object with process and memory limits,
and resumes it. Wall time, cancellation grace, stdout, stderr, total output,
and UTF-8-safe output frames are bounded; status reads use one combined logical
cursor across both streams. Cancellation, timeout, output-limit, helper-crash,
and nonzero-exit paths are covered by redacted durable audit and real Windows
descendant-cleanup tests.

That runner does not pin argv-referenced scripts, recursive imports,
`node_modules`, package lifecycle hooks, build-tool config/plugins, Git config,
or network access. `executesWorkspaceCode` and `network:not_enforced` are
warnings rather than isolation. The generic mechanism is therefore Full-risk,
not an accepted Modify build/test wrapper. The production local Modify runtime
and stdio host reject `run_process_preset` profiles before acquiring owners;
Managed and ordinary Read reject them independently. The lower-level mechanism,
in-memory registry, closed stdin, packaging, and tests remain for a future
Full-session gate or dedicated structured wrapper. They do not claim Git,
public Chat activation, or live packaged-release readiness.

SafeFs provides handle-relative single-file publication, ordered NTFS flush and
reconciliation, and bounded private rollback artifacts. This is best-effort
ordered recovery, not a filesystem transaction or hostile same-user
compare-and-swap guarantee. A `repair_required` state hard-stops every mutation
in that runtime/profile. The confirmation presentation and decision broker are
implemented; a trusted operator repair UI and workflow remain unimplemented.

The repository also contains a local executable proof of the future Managed
data plane. A separately signed local approval is consumed once, an explicit
Ed25519 or ECDSA-P256 device proof issues a revocable schema-v2 certificate,
and every reconnect requires a fresh challenge bound to that algorithm and
public-key fingerprint. Device IDs also bind tenant, algorithm, and canonical
SPKI fingerprint. A separate Windows helper can create a current-user
Software-KSP P-256 signing key, require non-exportable private-key policy, and
sign without returning private bytes to Node. A five-minute HMAC-signed Read
lease then binds one immutable
tenant/user/connection/device/profile/policy route to an outbound device
session and the existing local Read boundary. Each logical session gets its own
MCP server/transport instance; local schemas, roots, native filesystem policy,
and tool audit remain device-side. A bounded Streamable HTTP adapter has been
exercised through this route with session-bound authentication, Host/Origin
validation, body caps, explicit DELETE cleanup, protected-resource metadata,
fixed OAuth-style challenges, and strict issuer/client/resource/scope/expiry
checks. HTTP authentication is bound to the signed lease identity, and leases
are rechecked in both message directions. A standalone resource-server verifier
now enforces a bounded RS256 `at+jwt` profile, exact issuer/audience/resource,
short lifetime, strict private route claims, and a statically pinned bounded
JWKS fetch with cache/rotation tests. A local token-issuer slice now produces
matching five-minute RS256 access tokens and public-only JWKS output, including
key-pair and minimum-modulus validation. A separate headless authorization-code
authority now binds an explicit local approval to a one-time code and PKCE S256,
then returns a bounded access grant after exact client/resource checks and
optional legacy redirect matching.
The domain token service passes that redeemed grant directly to the issuer and
rejects widened output or retry/error oracles. A local public-application router
now composes authorization-server metadata and JWKS, explicit authorization,
the token endpoint, protected-resource metadata, JWT verification, and the MCP
relay. A real local end-to-end test exchanges a one-time PKCE code, verifies the
RS256 token, and calls the existing device-side Read tools. The relay reserves
and bounds requests before reading unauthenticated bodies, publishes an MCP
session only after its durable open audit succeeds, and accepts only the exact
MCP resource path. Managed discovery applies one global OAuth `aime.read`
scheme to every Read descriptor at the top-level and compatibility `_meta`.
The server rejects simultaneous managed tool security and Modify configuration,
so the Managed route remains Read-only. Stdio startup separately rejects every
profile containing a Modify capability rather than silently downgrading it.

A separate bounded device-wire stack now multiplexes logical MCP transports
over real sockets with authenticated device-wire handoff, authenticated
device-session binding, bounded loopback WebSocket carriage, and the original
loopback TCP transport proof. It uses strict framing, monotonic sequence
numbers, byte/frame/stream caps, backpressure, heartbeat, abort, and bounded
cleanup even when a local stream operation hangs. None of these local slices is
a deployed service. An unwired PostgreSQL authorization-code adapter and
migration now provide transaction-shaped replay, capacity, bounded-retention,
and digest-only burn semantics, but the real PostgreSQL integration remains
unexecuted without an explicit disposable test database. A wired and
real-database-verified production authorization-code store,
login/consent UI, durable signing-key ring, public HTTPS/WSS, durable tenant
storage, and production authorization remain unimplemented.

The device-side reconnect supervisor treats each successful retry as a new
generation, applies bounded exponential backoff with jitter, aborts connect,
backoff, and online waits during shutdown, and keeps its audit records free of
connection, device, profile, endpoint, certificate, and error details. Its
connection contract deliberately contains only lifecycle controls because a
device cannot authenticate a connection ID generated and authorized by the
gateway. Fresh route and lease binding therefore remains a gateway-side policy
decision. A real loopback reconnect test composes the WebSocket carrier,
device proof, gateway session, signed lease, and existing MCP Read server. It
proves a fresh connection ID after forced loss, rejects the stale lease with
`route_mismatch` before opening a device stream, and accepts a new lease for the
new route. The test-only loopback carrier does not establish deployed TLS/WSS or
Chat-surface behavior.

A narrow managed network host now owns one Node HTTP server shared by the public
OAuth/MCP router and authenticated device WebSocket gateway. It deliberately
does not listen automatically, choose a public address, terminate TLS, load
tenant identity, or own authority state. Shutdown first fences admission and
stops new accepts, then closes the public application and device gateway while
bounding the owned HTTP socket drain. This closes a previously test-only
listener-composition gap without pretending to be a deployed service. Above it,
a managed consumer gateway runtime now owns the composed OAuth/MCP/WSS service
lifecycle: it binds verified access-token identity to a strict non-secret
device/profile selection, issues the short-lived route lease internally, and
closes the host before token, code, signing, and authority owners. The runtime
does not call `listen`, terminate TLS, load raw deployment secrets, or decide
tenant membership and pairing policy.

The complete repository suite reports 1,284 tests. On the Windows development
host on 2026-08-15, 1,279 passed, none failed, and five were skipped: the opt-in
real PostgreSQL integration lacked `AIME_TEST_POSTGRES_URL`, and four cases are
intentionally POSIX/non-Windows-only.
The repository typecheck also passes. An independent read-only review of the
latest production boundary that rejects generic Full-risk process presets from
Modify reported no actionable findings. The consolidated evidence/exposure
summary and resume order are recorded in
[Implementation Status and Next Steps](IMPLEMENTATION_STATUS.md).
The passing set
includes native NTFS, Job Object, DPAPI, protected-config, authenticated WSS,
and deterministic PostgreSQL transaction-contract tests. The
separately recorded VM evidence remains the release reference and must be
repeated against a distributable build. Test success alone does not satisfy a
Chat-surface or release gate.

The production tunnel command now composes the strict config loader, a fresh
per-run directory, the launch-plan builder, native supervision, and readiness.
It handles shutdown requested by Ctrl+C, termination, or stdin EOF, keeps
stdout empty, and emits only fixed redacted diagnostics to stderr. The
readiness module independently reads the atomically published health URL
with strict UTF-8 and a 1 KiB cap, accepts only the exact
`http://127.0.0.1:<port>` form emitted by the pinned client, never follows a
redirect or environment proxy, and reports ready only when exact `/healthz`
and `/readyz` probes both return HTTP 200 and the bounded `/metrics` response
contains a finite positive `commands_poll_last_successful_timestamp_seconds`
value in the same polling cycle. That metric starts at zero for each process,
so a positive value proves at least one successful control-plane poll in the
current daemon lifetime; it does not prove continuing health or a callable
ChatGPT app. The base URL file alone is only listener discovery and must never
be treated as ready.

A separate internal Modify tunnel entrypoint selects only the dedicated Modify
stdio child and adds `aime-safe-fs-win32.exe` plus
`aime-confirmation-ui-win32.exe` and `aime-process-runner-win32.exe` to the
supervisor's retained immutable-path set. Those helper paths are absent from the
nested MCP command and child environment. The existing Read tunnel entrypoint
and scripts remain unchanged.
This retained-handle boundary prevents replacement after supervisor admission;
it does not authenticate the initially opened bytes or replace a signed,
administrator-protected installation directory.

The first offline packaging slice now stages only an exact runtime allowlist:
the compiled local Modify graph, its pinned runtime-package roots, the bundled
Node executable and license, required native helpers, an unmanaged x64 launcher,
and manifest assets. It excludes tests, source maps, unrelated helpers, build
stamps, and the user-owned tunnel client. The generated MSIX manifest uses the
launcher as the packaged classic medium-integrity application, enables package
content integrity, requests `runFullTrust`, and exposes one app-list entry backed
by that launcher. A real Windows SDK MakeAppx test imports the staged module
graph, packs with SHA-256 blocks, inspects the archive, and unpacks byte-identical
manifest content without installing, activating, or trusting it.
The exact payload now includes the process runner helper and its process service,
platform-composition, and runner modules; their presence is packaging evidence,
not acceptance of public activation or the Phase 5 exit gate.

The launcher is native C rather than managed code so inherited CLR profiler
variables cannot run before sanitization. It derives the package root from its
own module path and the config from the Local AppData Known Folder, retains and
revalidates the Node and entrypoint leaves, performs offline Authenticode
verification against the retained Node handle, starts Node suspended with an
explicit three-handle list and only `SystemRoot`/`WINDIR`, then assigns the tree
to a bounded kill-on-close Job Object. A per-session mutex prevents a duplicate
tree. The child emits only exact bounded lifecycle frames; the launcher maps them
to Starting, Personal Connect setup required, OpenAI control-plane ready, Stopping, and
Failed states without claiming Chat connectivity. A standard status window and
notification icon expose those states. Duplicate activation reveals the existing
instance, while Stop closes the retained stdin writer and force-terminates a
non-cooperative Job tree after 30 seconds. Setup and failure terminal states
remain user-dismissible for a bounded ten seconds after child exit, while the
Job tree is terminated immediately. Its ancestor namespace guarantee
intentionally comes from installed-MSIX package integrity; writable unpackaged
trees are not a supported security boundary. The Node staging implementation
similarly requires an exclusive, trusted build workspace because path APIs cannot
remove the final hostile same-user namespace race. The proof remains unsigned
and uninstalled: actual shell visibility, production publisher signing, live
activation/update behavior, and release-key operations are still gates.

A native Windows supervisor now launches the tunnel process suspended, assigns
it to a kill-on-close Job Object before the first instruction can run, then
resumes it. It passes a sorted two-variable environment, uses an explicit
application path and Windows-compatible argv quoting, allowlists inherited
stdio handles, and keeps child output separate from the JSONL control channel.
Real Windows integration tests prove that a child and grandchild both terminate
when the supervisor crashes and when a stubborn tree exceeds its stop grace
period. Before process start, the native supervisor now opens every immutable
input and the run directory component by component relative to verified Windows
handles, rejects intermediate and terminal reparse points, rejects multiple hard
links, captures volume/file identities, and re-opens the full chains to compare
those identities immediately before `CreateProcessW`. It retains non-delete-
sharing ancestor handles and read-only immutable handles for the process-tree
lifetime, and creates the child console log relative to the verified run-directory
handle. The pinned tunnel-client SHA-256 is checked from a second handle-relative
open whose file identity must match the retained executable capability; a hash
mismatch fails before creating logs or starting a child. Real Windows tests cover
both a junction in `cwd` and a junction within an immutable path without creating
child output. It also rejects a broad or inherited runtime-key-blob DACL, replaces the
fresh empty run-directory DACL with a protected current-user/SYSTEM/Administrators
allowlist before log creation, and verifies both ACLs fail closed. Executable
signing and a repeated swap-race test remain release gates before distribution.

A separate native enrollment helper accepts a runtime key only through an
interactive no-echo console prompt, requires the value twice, rejects redirected
stdin and unknown arguments, binds the protected envelope to the exact tunnel ID,
and creates a new DPAPI CurrentUser blob with a protected three-principal DACL.
It never accepts the key through argv, environment, a source file, or clipboard.
The supervisor validates the blob through retained handles, decrypts with UI
disabled, validates the tunnel-bound envelope, creates a random first-instance
outbound named pipe with a private DACL and remote clients rejected, and replaces
the fixed sentinel with that pipe path. It verifies that the connecting pipe PID
is the supervised tunnel process and does not report `started` until the key has
been consumed. A mismatch, child exit, or timeout terminates the Job Object and
fails closed. The pipe behavior was verified against the pinned v0.0.11 client;
it is not a documented stable upstream API, so every client upgrade must repeat
that compatibility test.

The integrated VM compatibility probe used a dummy tunnel-bound DPAPI envelope
and an intentionally unreachable loopback control-plane address. The exact
pinned client consumed the one-shot pipe without exposing the dummy value in
captured output or logs, then exited cleanly with no process tree left behind.
No OpenAI account or real credential was involved in that probe.

The current native implementation deterministically clears its managed and
unmanaged buffers, but the decrypted envelope and key briefly exist in managed
byte arrays. The .NET GC does not guarantee that no internal copy remains. An
unmanaged-only runtime path is therefore still required before production
hardening. DPAPI CurrentUser also does not defend against malware already running
as the same user, an administrator or SYSTEM process, or memory/pagefile/crash-
dump inspection. The pinned tunnel client necessarily retains its own plaintext
key in process memory after reading the pipe.

The pinned v0.0.11 Windows-amd64 distribution has two distinct trust values:
the official release manifest pins the ZIP archive as
`eb912c86c6ccde90cda805cb17009507176a656725cf86c36fabe1901a12e29b`,
while the extracted `tunnel-client.exe` that the native supervisor verifies is
`7d3c7d492ce84b52835e11865a835a8a5bcd4a669dee84e169aa11b314dc952a`.
Both the tunnel client and bundled cloudflared executable are unsigned in that
archive, so code signing remains a release blocker even though provenance is
pinned by the independently fetched release manifest.

The TypeScript tunnel runtime composes native supervision with local readiness.
It requires fresh health, tunnel-log, and console-log output paths, never deletes
stale caller paths, races readiness against process exit, and closes the entire
Job Object tree if readiness fails. Its successful state proves that the local
tunnel client is alive, locally ready, and has completed at least one successful
control-plane poll. It still does not prove that an AiMe app is installed or
callable from a ChatGPT Chat conversation.

The tunnel parent now derives a SHA-256 binding from the exact raw profile bytes
that it parses and validates. That derived value is carried only through the
internal launch plan and native supervisor protocol. Before log creation, key
decryption, or process creation, the supervisor requires the profile path to be
one of its immutable inputs, reopens it handle-relative, verifies the retained
file identity, single-link regular-file shape, 65,536-byte ceiling, and digest,
then keeps the no-write/no-delete handle chain for the process-tree lifetime.
The binding is not persisted in the tunnel document or exposed to the MCP child,
arguments, environment, readiness, audit, or diagnostics. Replacing the file
with byte-identical content before admission is intentionally equivalent at the
policy layer; literal parent-handle identity handoff remains unnecessary for
this bounded slice.

Remaining release blockers include production signing and installed activation
of the staged package, the external tunnel-dependency distribution decision,
replacing the temporary managed plaintext buffers, integrating the native
Managed enrollment flow into a user-facing setup experience, completing the
NTFS race/resource test matrix, defining and testing an operator repair
workflow, authenticating the installed package under the accepted publisher,
and validating actual ChatGPT Chat tool discovery, confirmation, timeout, and
revocation behavior. Managed Modify also requires a separately versioned scope
and per-tool enforcement rather than the current global `aime.read` scheme.

The first Personal Connect foundation now adds two local composition
boundaries without changing that release status. A Read-profile finalizer
validates approved roots and the audit parent through the native no-follow
filesystem boundary, then publishes the profile through the native staged
config transaction. The helper pins the target parent chain before semantic
preflight, writes to a private random delete-on-close temporary file, and keeps
the final target absent until a handle-relative atomic rename commits it.
Controller EOF, helper crash, or rollback leaves no committed artifact behind.
After the rename the helper reopens the final file relative to the same pinned
parent and verifies identity, bytes, DACL, attributes, and link count before
acknowledging success. The TypeScript layer performs preflight only after the
native `config_target_ready` event and does not place capability tokens in argv.
If a commit response is lost, an idempotent retry accepts only the same
single-link, private-DACL file with the exact expected bytes; a different
existing file fails closed. Windows profile loading and Windows tunnel-config
loading both read their policy files through the native handle boundary and
reject leaf symlinks, parent junctions, hard links, ADS, and junction-configured
roots. The JSONL audit file is opened or created handle-relative by the native
helper, retained for the sink lifetime, and flushed before each write is
acknowledged. A strict Personal Connect facade accepts only a tunnel ID plus
paths to the existing profile, DPAPI-protected runtime-key blob, and tunnel
client, then composes the tunnel finalizer internally. A native setup dialog
exposes exactly those four fields. A separate native fixed-state operation
derives Local App Data through the Known Folder API, pins and validates the
private `Ai&Me\state\runs` chain, and returns the sibling `tunnel.json` target
without trusting caller-selected state paths or ambient environment variables.
Node and the UI never receive the raw runtime key. The tunnel child can invoke
this flow once after a setup-required result and retry startup exactly once
after an accepted no-replace publication. Its `config_ready` result means only
that protected local configuration was published; it does not claim tunnel or
ChatGPT connectivity. This first slice creates a missing configuration only; a
different existing `tunnel.json` still fails closed. It does not create an
OpenAI tunnel, runtime-key blob, profile, ChatGPT app, or managed AiMe account.

The first Managed-mode foundation now extends beyond the earlier unauthoritative
pairing-intent payload. Tests prove a separately signed local approval artifact,
atomic single-use consumption, explicit Ed25519/P-256 device-key proof, a
revocable algorithm-bound certificate, fresh connection proof, bounded state,
and fail-closed audit rollback. The pairing,
lease, session, and revoke authorities now run through one tested local
composition root. It opens and replays an authenticated append-only journal
before admitting work, hydrates a shared synchronous device-revocation fence,
binds the active credential to every lease and device session, and disconnects
sessions before closing the authorities and journal. A new headless
device-enrollment coordinator now composes the public pairing intent with an
injected authenticated broker and explicit local confirmation seam, validates
the exact schema-v2 pairing challenge before invoking the non-exporting signer,
checks that the returned certificate envelope canonically embeds the validated
claims, and exposes success only after an injected protected store acknowledges
an atomic credential create. The Windows implementation validates a canonical
schema-v2 record, keeps the certificate out of argv and environment data, and
uses a separate DPAPI entropy/binding domain plus a private handle-relative
no-replace transaction. Read, exact-existing recovery, restart, guarded delete,
ACL, link, rollback, and cross-identity race behavior are exercised against the
real helper. The enrollment coordinator deliberately does not start reconnect.
A separate post-enrollment Windows bootstrap now reloads that protected record,
opens the exact fingerprint-pinned CNG identity, and owns the authenticated WSS
reconnect supervisor through shutdown. A real native-helper plus loopback
WebSocket integration proves resume after local handles are closed without
replaying enrollment. Multi-process registry coordination, rollback-resistant
state checkpoints, a durable cleanup outbox or staged remote activation,
binding the flow to a real local confirmation UI, and connecting it to
authenticated web users remain Phase 3 work. Software KSP
non-exportability
prevents private-byte export but does not prevent other code already running as
the same Windows user, Administrator, or SYSTEM from requesting signatures.

OpenAI's current tunnel setup requires a Platform `tunnel_id`, a runtime API
key, and an MCP server reachable by the client over stdio or HTTP. Tunnel
creation/editing requires **Tunnels Read + Manage**; running the client and
selecting a tunnel while creating an app require **Tunnels Read + Use**. These
Platform permissions are separate from ChatGPT developer-mode access. AiMe
will accept the key only as a protected `file:` reference and will not place its
value in the tunnel or MCP child environment. The current prototype satisfies
that transport boundary with a tunnel-bound DPAPI blob and a one-shot named pipe,
but this does not make the credential lifecycle production-ready.

## First release gate

Before connecting a real ChatGPT account, all of the following must pass on a
real Windows NTFS volume in the disposable VM:

- root traversal, drive-relative, UNC, device namespace, ADS, reserved DOS
  device, trailing-dot/space, control-character, wildcard, long-path, and
  percent-encoding negative vectors;
- junction, symlink, mount-point, terminal reparse point, dangling link, link
  loop, root replacement, and a repeated swap race with zero outside-canary
  reads;
- strict UTF-8 and file-size boundaries, sparse/growing files, directory entry
  limits, response-size limits, cancellation, timeout, and bounded concurrency;
- unauthenticated, expired, wrong-audience, wrong-profile, and revoked tokens
  denied before any filesystem access;
- audit logs contain allowlisted metadata only and never tokens, absolute paths,
  file contents, prompts, screen data, or secret canaries; internal search
  audit stays redacted to counters, truncation reason, and path fingerprints.

No Critical or High finding may remain open at release.

## Account-dependent validation

The scoped investment gate has now passed with real AiMe MCP calls from the
Chat surface on the disposable VM. The tested working PC path used `High` mode,
and the same private app returned tool results on tested mobile and tablet
clients. `Pro` mode on the tested PC/account did not reliably invoke the app on
2026-08-13. This is an observed OpenAI product constraint rather than a local
AiMe policy guarantee. Exact browser-reload behavior remains a regression check,
and the successful investment gate does not waive the release gates above.

Account login, password, MFA, and consent remain user actions. Remaining
account-dependent validation includes the exact approval UI, token renewal and
runtime-key revocation behavior, cancellation of already in-flight work, and
the compatibility matrix across ChatGPT models, clients, accounts, and rollout
states.
