# AbstractGateway

> Durable Run Gateway host for AbstractRuntime and the control plane of AbstractFramework: start runs + append durable commands; clients replay/stream the durable ledger (replay-first); operators manage users, providers, models, local engines, browser apps and network exposure from the web console, the terminal console, the CLI or the desktop tray.

This repository contains the `abstractgateway` Python package (CLI + FastAPI server + durable stores + runner worker + web console + desktop tray helper).
This file is also the documentation corpus the console's docs assistant answers from, so the key facts below are deliberately detailed.
The main HTTP surface is `/api/gateway/*` (FastAPI routes in `src/abstractgateway/routes/gateway.py`).
The live HTTP contract is the runtime OpenAPI schema: `GET /openapi.json` (Swagger UI: `GET /docs`).

Format note: follows the [llms.txt specification](https://llmstxt.org/).

Key invariants / defaults (evidence in code):
- Security is enabled by default for `/api/gateway/*` (user principals via `ABSTRACTGATEWAY_USER_AUTH=1` or `ABSTRACTGATEWAY_AUTH_MODE=users`, a shared bearer token via `ABSTRACTGATEWAY_AUTH_TOKEN`/`ABSTRACTGATEWAY_AUTH_TOKENS`, an origin allowlist, request limits, auth lockouts, an audit log). `/api/health` is intentionally public. With no auth configured, `abstractgateway serve` binds `127.0.0.1` (or the stored network mode) and enables user auth automatically; an explicit non-loopback `--host` without auth configuration fails fast, and any explicit auth setting keeps the `0.0.0.0` default bind. When user auth is enabled it ensures `default/admin` exists and writes `<ABSTRACTGATEWAY_DATA_DIR>/auth/bootstrap-admin-token` (0600; printed on a loopback bind, `serve --print-token`/`--no-print-token` overrides) (`src/abstractgateway/security/gateway_security.py`, startup checks in `src/abstractgateway/cli.py`).
- First run (`src/abstractgateway/first_run.py`, `host_paths.py`, `os_service.py`): unset `ABSTRACTGATEWAY_DATA_DIR` resolves to `./runtime` when it exists in the working directory, else the per-user data folder (macOS `~/Library/Application Support/AbstractGateway`, Linux `$XDG_DATA_HOME/abstractgateway`, Windows `%LOCALAPPDATA%\AbstractGateway`). One-time console sign-in links (`/console#claim=<code>`, 10 minutes, single use, SHA-256 at rest under `<DATA_DIR>/auth/claims/`) come from `serve`'s banner, `abstractgateway claim` or `abstractgateway-config claim-url [--open]`, and are redeemed by `POST /api/gateway/session/claim` from a loopback peer only (no proxy headers). The console then opens a first-run guide (state: `GET/POST /api/gateway/host/first-run`). `abstractgateway service install|uninstall|enable|disable|status` registers a per-user login service (LaunchAgent, systemd user unit or XDG autostart entry, experimental Windows `HKCU\\...\\Run` entry); `enable`/`disable`/`status` share `abstractgateway.autostart` with the desktop tray's "Start AbstractGateway at login" item (states on | off | broken | other). `abstractgateway-config status --json` reports `data_dir_source`, `auth_mode`, `service`, `claim_pending`, `first_run`, `serve`. See [docs/first-run.md](./docs/first-run.md).
- Network exposure (`src/abstractgateway/network_exposure.py`, contract `gateway_network_v1`): one runtime setting chooses `localhost` (127.0.0.1), `lan` (0.0.0.0, requires user accounts) or `internet` (0.0.0.0, requires user accounts and `acknowledge_internet`), changed from the console's Network tab, the terminal console's Connection screen, the tray's Network menu or `abstractgateway network status|show|set|addresses|restart` (`GET/POST /api/gateway/network`, `POST /api/gateway/network/restart`). A mode applies at the next start (`restart_required`); `serve --host/--port` override it (`overridden_by_cli`). Refusals are HTTP 409 with `reason_code` `user_auth_required`, `auth_disabled` (started with security, write or read protection off) or `acknowledgement_required`. The same setting holds the reverse-proxy values `allowed_origins` (added to `http://localhost:*`, `http://127.0.0.1:*` and, in a network mode, the gateway's own LAN origins) and `trust_proxy`, applied to the next request; `ABSTRACTGATEWAY_ALLOWED_ORIGINS` / `ABSTRACTGATEWAY_TRUST_PROXY` in the launch environment pin them (`overridden_by_env`). The gateway does not terminate TLS. See [docs/configuration.md](./docs/configuration.md).
- Runtime settings (`<data dir>/config/runtime_config.json`, `src/abstractgateway/runtime_config.py`) are changed through the console, the terminal console, Continuum, the tray or the CLI (`abstractgateway config get|set|unset`, `abstractgateway apps config get|set`, `POST /api/gateway/admin/runtime-config`): `network`, `apps.node|ports|host|npm_registry|pypi_url`, `allow_engine_install` (default on for a loopback bind and for a caller on the gateway machine itself), `triage_repo_root` (backlog folder, default `<data dir>/backlog`), `backlog_exec_runner` (default off), `process_manager` (default off), `stop_kill_switch_s`. `serve --backlog-root PATH` and `--exec-runner on|off` override the backlog settings for one run.
- Browser apps (`src/abstractgateway/apps_manager.py`, `/api/gateway/apps/*`, `abstractgateway apps list|install|update|launch|stop|open|logs|jobs|runtime|install-tui|tui-command|config`): Flow Editor, Code, Observer, Continuum and Entity install from npm (Node.js 24 installed into the data dir when no Node.js 18+ exists), run as supervised child processes on `127.0.0.1` (usual ports Observer 3001, Continuum 3002, Code 3003, Entity 3004, Flow 3005), start again with the gateway until stopped, and open signed in through one-time handover links (`/apps/handover/{code}`). One Install also installs Code's prebuilt terminal app when one exists for the computer; "Open in Terminal" opens it signed in on the gateway machine. Apps started outside the gateway are detected on their usual ports. The desktop Assistant (`abstractassistant`) is an app card with Install and Open on the gateway's computer. Install, update, start and stop need an admin. See [docs/apps.md](./docs/apps.md).
- Desktop tray (`abstractgateway[tray]`, `src/abstractgateway/tray/`, `tray_supervisor.py`): `serve` starts a helper process on a desktop session (absent only for `missing_dependency`, `headless`, `dev_reload`, `runner_only`); it talks to the gateway over loopback with an ephemeral token and offers Open Console (signed in), Apps, Workflows, Pause/Resume, Models (eject, load), Activity window, Start at login, Network, Copy Address, Check for Updates, Restart, Quit. Host control routes: `GET /api/gateway/host/runner|tray|update|runs|metrics/live`, `POST /api/gateway/host/pause|resume|restart|shutdown|tray/show|update/check|update/start`. See [docs/tray.md](./docs/tray.md).
- Models & engines (served from AbstractCore through `core_config.py` -> Runtime `config_facade`; the gateway never detects engines or sizes models itself): `GET /api/gateway/host/profile` (`host_profile_v1`), `GET /engines?probe=1` (`engines_status_v1` + `install_allowed`/`install_policy`), `POST /engines/{id}/install {dry_run, force, location}` (admin; real installs need runtime-config `allow_engine_install`; 403 `not_allowed`, 409 `busy`; jobs pause in `needs_admin` / `needs_tools` until `POST /engines/jobs/{id}/continue`; see [docs/engines.md](./docs/engines.md)), `GET /models/catalog?q=&engine=&fits=1&hub=1&tag=` (`model_catalog_v1` with fit verdicts), `GET /models/installed?provider=` (`models_installed_v1`), `POST /models/delete {provider, artifact, dry_run, force}` (admin; 404 not installed, 409 `delete_blockers`), `GET /jobs?kind=&status=` (`host_jobs_v1`), `GET /jobs/{id}` (`host_job_v1`, 404 unknown), `POST /jobs/{id}/cancel` (admin). All jobs (downloads included) run in AbstractCore's host job registry; `cli_equivalent` names `abstractgateway`. Download jobs report `state` (queued, resolving, downloading, verifying, installing, done, failed, cancelled, stalled), bytes, speed, time left, per-file rows and `ended_reason`; `POST /models/download {"recommended": true}` returns a parent job (`grp_...`); `POST /models/download/{id}/cancel` and `GET /models/downloads/stream` (SSE) complete the surface ([docs/model-downloads.md](./docs/model-downloads.md)). An AbstractCore too old for these routes answers 501 `abstractcore_too_old`, a missing one 503. CLI twins: `abstractgateway models list|catalog|search|download|delete|jobs|cancel` and `abstractgateway engines status|install|open` (HTTP to the running gateway by default, `--local` in-process; exit 0/1/2). The web console embeds AbstractCore's screens as the **Models** (`catalog`) and **Engines** (`engines`) tabs and in the first-run guide. See [docs/api.md](./docs/api.md) and [docs/console.md](./docs/console.md).
- Token mode maps the shared Gateway bearer token to `local-admin`. That token is a server/operator token, not a browser sign-in token. With user accounts off, only admin accounts can hold a browser session (`401 user_accounts_off_admin_only`); the last enabled admin account cannot be deleted, disabled or demoted (`409 last_admin`). Hosted user-auth mode resolves Gateway user bearer tokens to principals, exposes `GET /api/gateway/me`, provides admin-only `/api/gateway/admin/users` CRUD plus retained-runtime lifecycle routes under `/api/gateway/admin/runtime-reservations`, stores user token hashes under `<ABSTRACTGATEWAY_DATA_DIR>/auth/users.json` by default, rejects duplicate runtime ids within the same tenant, reserves retained runtime ids when users are deleted, and routes each principal to a separate GatewayService data plane under `<DATA_DIR>/users/<tenant_id>/<runtime_id>/`.
- Gateway serves a built-in control-plane console at `/console` with the tabs Users & Entities, Runtimes, Workflows, Providers, Multimodal, Sandbox, Resources, Models, Engines, Apps and Network, a Technical details switch, a docs assistant and a Setup button that reopens the first-run guide. It uses Gateway browser sessions, lets admins manage user records (including optional email metadata), rotate tokens, transfer or purge retained runtime reservations, and lets signed-in users configure provider connections for OpenAI, Anthropic, OpenRouter, Portkey, LM Studio, Ollama, and custom OpenAI-compatible endpoints. Provider URLs/API keys live in the Providers tab; capability Defaults only select configured virtual providers and discovered models, without storing bearer tokens in browser storage. LLM/embedding default pickers use Core `capability_route` filters such as `input.image,output.text` and `embedding.text`; generated-media defaults use capability plugin catalogs. `input.voice` and explicit/covered `input.video` route defaults gate STT and video fallback; Gateway/Core do not silently use installed packages as hidden fallbacks.
- Browser apps should exchange Gateway user bearer tokens through `POST /api/gateway/session/login`, then use `X-AbstractGateway-Session` plus `X-AbstractGateway-CSRF` for mutating session-authenticated requests. The login response body does not expose the session id or CSRF token. Gateway stores revocable browser sessions under `<ABSTRACTGATEWAY_DATA_DIR>/auth/sessions.json` by default and invalidates them when the backing user is disabled, deleted, or token-rotated.
- Gateway browser session cookies use an HTTP-only session cookie, a separate CSRF cookie, `SameSite=Lax`, path `/`, no `Secure` flag on HTTP, and `Secure` under HTTPS. Non-remembered sessions omit `Max-Age`; remembered sessions include it. Origin checks reject untrusted origins and allow only configured hosted app origins.
- Hosted user-auth mode applies execution-host Core defaults, then the Gateway/root baseline Core config, then per-runtime Core config overrides under each user's runtime data plane. These scoped Core config files select provider/model/base URL defaults for the user's runtime without mutating other users. Gateway provider connections store reusable endpoint descriptions, provider families, base URLs, optional model allowlists, and write-only API keys; discovery exposes them as virtual providers such as `endpoint:office-vllm`, and Runtime receives only transient resolved provider/base URL/key parameters.
- A central Gateway route-family policy keeps operator/admin surfaces, model residency and weights mutations (`POST /api/gateway/models/load|unload|lock|unlock|download|delete`, `POST /api/gateway/engines/{id}/install`, `POST /api/gateway/jobs/{id}/cancel`), session-wide prompt-cache clearing (`POST /api/gateway/sessions/{session_id}/prompt_cache/clear_all`), and server-workspace file helpers admin-only. Host and residency reads (`GET /api/gateway/models/loaded`, `GET /api/gateway/models/context_estimate`, `/host/state`, `/host/metrics/*`, `GET /api/gateway/sessions/prompt_cache`) serve any authenticated principal; anonymous requests are rejected. Browser-local files should use upload routes; server workspace read/import/export routes require admin until per-user workspace grants are defined.
- Host state & model residency surface: `GET /api/gateway/host/state` is a one-call snapshot of memory, GPU, resident models, and session prompt caches with byte totals (plus a top-level `host` identity block when the runtime reports one); sections degrade independently in-band (`degraded` + `reasons`), never a 500. `GET /api/gateway/host/metrics/memory` and `/host/metrics/gpu` are the per-probe snapshots (`supported: false` with a reason when unavailable). `GET /api/gateway/models/loaded` returns raw `models` plus normalized `rows` in the additive-tolerant `model_residency_row_v1` schema (incl. `locked`/`lockable`, `modalities`, `calibrated_context_length`/`context_calibrated`, `host_id`/`host_name`; provider residency booleans outrank runtime lease booleans, state strings can confirm but never deny residency, unknown stays null). `totals.models_resident` counts only rows with `resident: true` — the truthful "N loaded" (`totals.models` counts every known row, configured/cached included). Admin-only `POST /api/gateway/models/lock|unlock` pin/release a resident model; lock requires provider-verified residency (a configured or merely-warm model refuses with `error: "model_not_resident"` — load with `lock: true` instead), unlock always works so locks are never stranded; `POST /models/unload` answers HTTP 409 with the `model_locked` refusal payload for a locked model unless the request carries `"force": true`. `GET /api/gateway/models/context_estimate?provider=&model=&context_length=` (user-level; `context_length` >= 1) relays the runtime's context/KV memory estimate with in-band `confidence` (`calibrated`|`estimated`|`unknown`), the tri-state `fits_weights`/`fits_requested_context` split, `predicted_max_context` (the context that fits beside the weights), and `budget_bytes` (basis + reserve stated in `notes`); advisory only — no load path gates on it. Discovery advertises `contracts.common.host_state`, `contracts.common.session_caches`, and `model_residency` with `row_schema`, the lock/unlock/context_estimate endpoints, and the canonical `modality_ui` color map (v1) all residency clients render with. Both consoles surface this as a Resources view (web tab; console-TUI screen 8) — reads for every authenticated user, mutations admin-gated; the web table defaults to provider-resident rows only, with configured/cached rows ("configured — not in memory") behind a counted toggle, and the TUI totals line counts resident rows apart from the row total. See [docs/api.md](./docs/api.md).
- Gateway discovery is permission-aware for those high-trust surfaces: ordinary users see admin-only workspace artifact import/export and provider prompt-cache controls marked unavailable with `admin_required` metadata. Session prompt-cache key hashes include a private principal scope so users do not collide on the same session/provider/model tuple.
- Shared/default workflows use the Gateway workflow catalog (`/api/gateway/workflow-catalog` plus admin-only `/api/gateway/admin/workflow-catalog/*`), not another user's private `/api/gateway/bundles` surface. Catalog versions are immutable, admins move default pointers and ACLs, and users start catalog workflows with explicit `registry_scope: "tenant_catalog"` so execution happens in their own runtime. Gateway signs catalog workflow policy before passing it to Runtime, and private bundle routes reject catalog-internal ids.
- Bundle mode is the only workflow source (`ABSTRACTGATEWAY_WORKFLOW_SOURCE=bundle`) and loads `.flow` bundles from `ABSTRACTGATEWAY_FLOWS_DIR` (`src/abstractgateway/service.py`, `src/abstractgateway/hosts/bundle_host.py`). VisualFlows are stored through `/api/gateway/visualflows/*` and published as `.flow` bundles.
- Stop: a `cancel` command stops the executing model call; after `stop_kill_switch_s` (runtime config / `ABSTRACTGATEWAY_STOP_KILL_SWITCH_S`, default 10, 0 disables) a still-running inference of the cancelled tree is killed in process (never the gateway process). Cancelled ledger steps have status `cancelled` (`cancelled_by` / `killed_by`). Runs accept `speculation` (MTP: `false` or a native-MTP object) on `/runs/start`, `/runs/schedule` and `/sandbox/generate`. HTTP runs reuse one gateway-owned workspace per session. See [docs/configuration.md](./docs/configuration.md).
- Both consoles carry a Workflows surface (web tab; console-TUI step 6) listing every registered workflow with its published/draft version counts, its versions and entrypoints, and a separate `Not loaded` block naming versions the gateway is not serving and why. It supports import (`POST /api/gateway/bundles/upload`), export (`GET /api/gateway/bundles/{bundle_id}/download` — original bytes plus an `X-AbstractGateway-Bundle-Sha256` header), and delete of a single version or a whole workflow.
- Writing a workflow registry requires owning it: the gateway's own bundle directory is shared by every user, so `POST /api/gateway/bundles/upload`, `DELETE /api/gateway/bundles/{bundle_id}`, `POST /api/gateway/bundles/reload`, the deprecate routes and `POST /api/gateway/visualflows/{flow_id}/publish` require an admin principal there and return `403` otherwise; under hosted user auth each principal writes its own registry freely. Reads are user-level. `DELETE` returns `409` for the boot-verified `basic-agent.flow`.
- A bundle version that misses its `metadata.min_runtime` floor or fails to compile is excluded from the runnable set and reported: `GET /api/gateway/bundles` returns a `skipped` array with the reason and on-disk path, and `POST /api/gateway/bundles/reload` reports the same. Install responses carry `loaded` (`true` served, `false` proven not served, `null` unverified because no reload was requested).
- When `ABSTRACTGATEWAY_FLOWS_DIR` is unset, Gateway serves the bundles packaged with the wheel: `basic-agent` (default chat agent), `coding-agent` (verify-gated coder; `coder` entrypoint), `deep-research`, `co-scientist`, `docs-qa`, `abstractassistant-orchestrator`, and the `react-agent`/`codeact-agent`/`memact-agent` native loops. The packaged set is the force-include list in `pyproject.toml`. See [docs/shipped-workflows.md](docs/shipped-workflows.md).
- SQLite safety invariant: when `ABSTRACTGATEWAY_STORE_BACKEND=sqlite`, the DB file (`ABSTRACTGATEWAY_DB_PATH`, default `<DATA_DIR>/gateway.sqlite3`) must be under `ABSTRACTGATEWAY_DATA_DIR` (fail-fast; prevents cross-wiring durable state) (`src/abstractgateway/config.py`).
- The system is replay-first; SSE streams are an optimization, not a source of truth (`src/abstractgateway/routes/gateway.py`).
- Two entry points, one store: AbstractCore owns capability route defaults (provider/model/base URL, the `output.text` reasoning effort, and route options), provider API keys, the `email` mail connection, and the `maintenance` triage LLM settings; Gateway surfaces them and keeps no copy, with `ABSTRACT_EMAIL_*` / `ABSTRACT_TRIAGE_LLM_*` as override rungs above the store. Every Gateway read/write of AbstractCore-owned config goes through one seam, `src/abstractgateway/core_config.py`; auth, bundles, workspaces, run policy, and integrations are Gateway-owned. `endpoint:<id>` profiles are a shared namespace where an AbstractCore `provider_profiles` entry wins over a Gateway one of the same id. See [docs/configuration.md](docs/configuration.md).
- Gateway LLM helper defaults resolve explicit request values, optional flow pins, and execution-host capability route defaults such as `output.text`. Missing provider/model is a clear config error, not a hardcoded local fallback (`src/abstractgateway/provider_defaults.py`, `src/abstractgateway/core_config.py`).
- Optional operator endpoints include account-scoped email inbox routes (`/api/gateway/email/*`) used by AbstractObserver (Inbox → Email) (`src/abstractgateway/routes/gateway.py`).

Multimodal notes:
- Capability discovery for thin clients: `GET /api/gateway/discovery/capabilities` (best-effort; reports installed optional capabilities like `voice`, `tools`, `visualflow`, `vision_fallback`, `media`, plus the versioned shared run contract including input-data/history-bundle read endpoints, direct media feature gates, voice `tts|stt|listen`, prompt-cache surfaces, and model-residency truth).
- Vision adapter discovery for thin clients: `GET /api/gateway/vision/adapters` returns compatible installed adapters for a provider/model/task combination through Runtime's public discovery facade.
- The shared artifact contract includes run artifact listing/content, session-visible artifact listing, cross-run/session/run artifact search, workspace-path import, and artifact-to-workspace export. `/api/gateway/artifacts/search` returns the row fields plus `artifact_envelope_v1`, exact stats/facets when `include_stats=true`, bounded paging, canonical descriptor filters, and a UI-oriented `artifact_kind` filter that keeps Voice, Music, Sound, and unclassified Audio distinct; single canonical kinds use Runtime catalog filters, while multi-kind unions may be Gateway post-filters until Runtime has OR filters. Browser-local files use upload; Gateway workspace paths use import.
- Generated-media artifacts projected from child runs into parent runs preserve Runtime descriptors and structured metadata. Direct STT transcript artifacts include descriptor/source refs for the source audio artifact, language/prompt hints, provider/model when available, and redacted route parameters.
- Direct Gateway voice/audio durable endpoints (when `abstractvoice` is installed on the gateway host):
  - STT: `POST /api/gateway/runs/{run_id}/audio/transcribe`
  - TTS: `POST /api/gateway/runs/{run_id}/voice/tts`
  - TTS stream: `POST /api/gateway/runs/{run_id}/voice/tts/stream` (JSON Lines; advertised through `capabilities.contracts.assistant.voice.tts.streaming`; successful streams still return a Runtime child-run artifact)
- Direct Gateway image durable endpoints:
  - image generate: `POST /api/gateway/runs/{run_id}/images/generate`
  - image edit: `POST /api/gateway/runs/{run_id}/images/edit`
  - image upscale: `POST /api/gateway/runs/{run_id}/images/upscale`
- Direct Gateway video durable endpoints:
  - text-to-video: `POST /api/gateway/runs/{run_id}/videos/generate`
  - image-to-video: `POST /api/gateway/runs/{run_id}/videos/from_image`
- Direct Gateway music durable endpoint:
  - music: `POST /api/gateway/runs/{run_id}/music/generate`
- Generated, edited, and upscaled images plus text-to-video/image-to-video are available through Runtime workflows and the direct run-scoped routes when the corresponding Runtime/Core vision backend is configured. Image, image-edit, image-upscale, text-to-video, and image-to-video direct routes expose child-run progress on the returned child run ledger as `abstract.progress`; image progress is best-effort and may be limited to start/complete for backends that do not report step progress. Image dimensions and upscaler controls are optional passthrough overrides and must not be injected as universal client defaults. Direct image/video routes also preserve task-specific batch and adapter fields: `count` / `n`, `seeds`, ordered `lora_adapters`, and video `flow_shift`, and batch responses return `image_artifacts` / `video_artifacts` plus the compatibility singular artifact field.
- Dynamic catalogs for thin clients are exposed at `GET /api/gateway/voice/voices`, `GET /api/gateway/audio/speech/models`, `GET /api/gateway/audio/transcriptions/models`, `GET /api/gateway/audio/music/providers`, `GET /api/gateway/audio/music/models`, and `GET /api/gateway/vision/provider_models`; they proxy AbstractCore Server catalog routes when configured.
- Catalog routes carry a Gateway-owned stable envelope: `catalog.contract=gateway_catalog_v1`, `catalog.version=1`, and canonical `items`, next to the lower-layer fields kept for compatibility.
- The shared client contract also exposes `common.readiness` as `gateway_surface_readiness_v1`: a compact surface-level summary derived from Gateway descriptors, media gates, memory, prompt-cache, and Runtime-backed model-residency truth.
- Gateway does not invent selected-backend or degraded-state truth; it reports what Runtime/Core expose.
- `voice.listen` is a host-capture contract for higher apps, not a server microphone socket; clients capture locally and then emit an event or upload audio for STT.
- KG memory is selected through Gateway env (`ABSTRACTGATEWAY_MEMORY_STORE_BACKEND=lancedb|memory`, plus `sqlite` when the installed AbstractMemory build exposes `SQLiteTripleStore`) and queried through `POST /api/gateway/kg/query`; store implementations remain owned by AbstractMemory, Gateway targets AbstractMemory's TripleStore API, and fresh empty stores are reported as available when the backend resolves.
- Text embeddings use the execution-host `embedding.text` capability route. Remote/provider-backed embeddings work in the base light install; local HuggingFace/sentence-transformer embeddings require `abstractgateway[embeddings]`. Gateway does not persist a separate embedding provider/model file; split deployments proxy embedding generation to the remote AbstractCore server.
- `/api/gateway/prompt_cache/*` exposes admin-only provider/model prompt-cache controls; `/api/gateway/prompt_cache/saved|save|load` are Runtime-backed host-local export/import admin aliases; `/api/gateway/sessions/{session_id}/prompt_cache/*` adds principal-scoped Gateway-owned session naming/status/prepare/clear/rebuild orchestration over those provider controls. `GET /api/gateway/sessions/prompt_cache` (user-level) enumerates the caches the runtime actually minted, with session/run/workflow/node attribution, and admin-only `POST /api/gateway/sessions/{session_id}/prompt_cache/clear_all` unloads them per session in one call — the recommended lane for observing and reclaiming session cache state.
- Docker scope ([docs/deployment.md](./docs/deployment.md)): `ghcr.io/lpalbou/abstractgateway:latest` is the release-grade lightweight base-package image; `ghcr.io/lpalbou/abstractgateway:gpu-latest` / `:<version>-gpu` installs `abstractgateway[gpu]` and is experimental/best-effort until a CUDA smoke gate exists. The container defaults to `ABSTRACTGATEWAY_USER_AUTH=1`; its entrypoint creates `default/admin` when missing and writes the first-login token under `<ABSTRACTGATEWAY_DATA_DIR>/auth/bootstrap-admin-token`. Apple/MLX inference should run natively on macOS and be reached from the Gateway container via Docker Model Runner (`http://model-runner.docker.internal/engines/v1`) or a host bridge OpenAI-compatible URL.

Regeneration:
- `python scripts/generate-llms-full.py` regenerates `llms-full.txt` from the Markdown doc links in this `llms.txt`.

## Ecosystem

- [AbstractFramework](https://github.com/lpalbou/AbstractFramework): ecosystem meta-repo (this gateway is one component)
- [AbstractRuntime](https://github.com/lpalbou/abstractruntime): durable runs + tick loop + stores (required dependency)
- [AbstractCore](https://github.com/lpalbou/abstractcore): lower-level provider/tool/media integrations consumed through Runtime facades
- [AbstractFlow](https://github.com/lpalbou/abstractflow): authoring + bundling `.flow` WorkflowBundles (optional)

## Start here

- [README.md](./README.md): install + quickstart + doc map
- [docs/README.md](./docs/README.md): docs index (what to read for each topic)
- [docs/first-run.md](./docs/first-run.md): zero-configuration local start, one-time console sign-in link, first-run guide, start at login
- [docs/getting-started.md](./docs/getting-started.md): step-by-step setup (bundle mode + file/SQLite + split API/runner)
- [docs/troubleshooting.md](./docs/troubleshooting.md): symptoms, causes and fixes (sign-in, network modes, runs, installs, downloads, tray, login service)
- [llms-full.txt](./llms-full.txt): single-file snapshot of the Markdown docs linked in this file

## Project docs

- [CHANGELOG.md](./CHANGELOG.md): release notes (human-oriented)
- [CONTRIBUTING.md](./CONTRIBUTING.md): dev setup + tests + contribution workflow
- [SECURITY.md](./SECURITY.md): responsible vulnerability reporting process
- [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md): contributor behavior and reporting
- [ACKNOWLEDGMENTS.md](./ACKNOWLEDGMENTS.md): dependency acknowledgments (see `pyproject.toml` for canonical list)

## Core docs

- [docs/getting-started.md](./docs/getting-started.md): run the gateway + choose file vs SQLite stores + split API/runner
- [docs/api.md](./docs/api.md): client contract + curl examples (replay-first ledger + durable commands)
- [docs/security.md](./docs/security.md): user accounts + sessions + origin allowlist + network exposure + limits + audit log
- [docs/configuration.md](./docs/configuration.md): runtime settings (network, reverse proxy, apps, backlog, engine installs), capability defaults, env vars, install extras, CLI flags
- [docs/console.md](./docs/console.md): the web console at `/console`, the `abstractgateway-console` terminal app (`cargo install abstractgateway-console`), and `abstractgateway models loaded|load|unload`
- [docs/apps.md](./docs/apps.md): browser and terminal apps (Flow, Code, Observer, Continuum, Entity) and the desktop Assistant, installed with one Install, started and opened signed in from the gateway; Node.js installed for you
- [docs/engines.md](./docs/engines.md): installing local engines (Ollama, LM Studio, MLX, llama.cpp) without a terminal; when the Apple tools or an administrator password are needed
- [docs/model-downloads.md](./docs/model-downloads.md): model downloads with progress, stalls, cancel, parent jobs and the event stream
- [docs/tray.md](./docs/tray.md): the desktop tray icon (apps, models, pause, start at login, network, restart, update)
- [docs/deployment.md](./docs/deployment.md): Docker/GHCR/Compose deployment profile
- [docs/architecture.md](./docs/architecture.md): components + durability model + deployment shapes (diagrams)
- [docs/shipped-workflows.md](./docs/shipped-workflows.md): the workflow bundles a fresh install serves out of the box (coder, deep research, co-scientist, basic-agent, native loops) + how to run one
- [docs/faq.md](./docs/faq.md): common questions and limits

## Key code entrypoints

- [pyproject.toml](./pyproject.toml): packaging metadata + dependency extras + CLI entrypoint
- [src/abstractgateway/app.py](./src/abstractgateway/app.py): FastAPI app + middleware + routers + health endpoint
- [src/abstractgateway/routes/gateway.py](./src/abstractgateway/routes/gateway.py): `/api/gateway/*` endpoints (runs, ledger, bundles, commands, tooling)
- [src/abstractgateway/security/gateway_security.py](./src/abstractgateway/security/gateway_security.py): auth/origin/limits/audit log middleware
- [src/abstractgateway/service.py](./src/abstractgateway/service.py): composition root (config + stores + host + runner + optional bridges)
- [src/abstractgateway/runner.py](./src/abstractgateway/runner.py): durable command inbox polling + run ticking
- [src/abstractgateway/stores.py](./src/abstractgateway/stores.py): file vs SQLite store wiring
- [src/abstractgateway/config.py](./src/abstractgateway/config.py): env var parsing + sqlite safety invariant
- [src/abstractgateway/cli.py](./src/abstractgateway/cli.py): `abstractgateway serve|runner|migrate|triage-*|...`
- [src/abstractgateway/hosts/bundle_host.py](./src/abstractgateway/hosts/bundle_host.py): `.flow` bundle loading + VisualFlow compilation + tool/LLM wiring switches

## Optional

- [docs/maintenance.md](./docs/maintenance.md): operator tooling (triage/backlog/process manager/file helpers; high trust required)
- [docs/entities.md](./docs/entities.md): summoned entities (homes, lifecycle, summoning, replay)
- [docs/deep-research.md](./docs/deep-research.md): the shipped `deep-research` workflow contract
- [docs/apple-local-gateway-flow.md](./docs/apple-local-gateway-flow.md): Apple Silicon local Gateway + Flow setup
- [scripts/generate-llms-full.py](./scripts/generate-llms-full.py): generator for `llms-full.txt`
- [tests/](./tests/): test suite (`pytest`, most tests are marked `basic`)
