Deployment Cookbook: Agent OS Cloud Deployment Authority

August 31, 2026 · View on GitHub

This cookbook is the F1 deployment authority delivered by Epic #11720. It describes the current Agent OS deployment baseline, the D0-decided target topology, and the post-MVP residual map that remains outside the shipped MVP.

This is not the day-0 tutorial. The executable first-run path lives in Day-0 Cloud Deployment Tutorial. For the older shared-KB/MC background and threat model, see Shared Deployment MVP. For the cloud topology decision record, see ADR 0014.

Section 1: Current Baseline vs Target Topology

The current reference compose file in deploy/cloud/ is a profile-structured Agent OS stack. The default profile starts the MCP baseline: chroma, kb-server, and mc-server. The cloud profile adds the cloud-safe orchestrator; the ingress profile adds the Caddy reverse proxy; the optional fleet profile adds the request-time-authenticated Fleet control service; the optional local-model profile adds a self-hosted OpenAI-compatible provider runtime without changing the default external-provider posture.

Service / profileCurrent baselineD0 target
default profilechroma, kb-server, and mc-server; all three declare per-service deploy.resources.limits and Docker readiness gates. Chroma uses a TCP probe; KB and MC use an MCP /mcp healthcheck tool call.Keep as the baseline MCP stack: Chroma as the unified vector-store primitive and KB/MC as separate request-serving MCP containers with production readiness semantics.
cloud profileAdds the orchestrator service with NEO_AI_DEPLOYMENT_MODE=cloud, shared SQLite volume access, its own resource envelope, and startup gated on healthy KB/MC services.Keep as the Agent OS maintenance control-plane container, running only the cloud-safe scheduler lanes from ADR 0014 after the MCP substrate is ready.
ingress profileAdds the Caddy reverse proxy for TLS termination and public /kb/* / /mc/* path routing while KB and MC remain internal-only via expose.Keep as the public boundary for auth/header stripping and MCP URL routing.
fleet profileAdds fleet-server on the internal network with exact /fleet + /fleet/probe ingress routes, a Fleet-owned named volume, and identity-bearing readiness. It is omitted from headless deployments.Keep Fleet as its own authenticated service boundary; consume graph/mailbox facts only through registered APIs, never another service's private volume.
local-model profileAdds a disabled-by-default local-model service using the configurable NEO_LOCAL_MODEL_IMAGE image, persistent model volume, healthcheck, and resource envelope.Optional self-hosted provider variant. Operators must opt KB/MC/orchestrator consumers into openAiCompatible; external provider endpoints remain the MVP default.

The service boundary is intentional: KB and MC serve MCP requests, Chroma stores vectors, and the orchestrator owns background Agent OS maintenance. Do not collapse them into a mono-container unless a later ADR explicitly changes the resource-isolation model.

Section 2: Scheduler Taxonomy and Cloud Profile

ADR 0014 classifies every orchestrator scheduler lane before the orchestrator is placed into a cloud container:

Lane setCloud profile behavior
summary, backup, dream, golden-pathCloud-deployable maintenance lanes. They need reachable model/provider and storage substrates, but no local maintainer checkout.
kbSyncContainer-plane lane. It scans the Neo repo's own corpus, which the container image carries at its built revision — so it runs in a cloud deployment rather than being disabled. It is never re-pointed at tenant content; that is tenant-repo-sync's lane.
bridgeDaemon, mlx, primary-dev-syncHost-edge lanes. They need the maintainer's checkout or desktop harness and must be disabled in a tenant cloud deployment.
chromaShared primitive. Compose or the platform owns the Chroma process in cloud; the orchestrator does not supervise it.

Sub A (#11722) delivered the config-level deployment-mode surface. A cloud orchestrator profile sets NEO_AI_DEPLOYMENT_MODE=cloud; the config resolver then disables host-edge lanes unless an operator explicitly opts a narrower lane back in. The explicit env overrides are:

Env varCloud default intent
NEO_ORCHESTRATOR_PRIMARY_DEV_SYNC_ENABLED=falsePrevents git fetch / git pull, worktree discovery, .sync-metadata.json resets, and local KB-sync cascades.
NEO_ORCHESTRATOR_BRIDGE_DAEMON_ENABLED=falsePrevents desktop wake delivery through osascript / tmux. A2A message storage remains Memory Core behavior.
NEO_ORCHESTRATOR_GOLDEN_PATH_REPO_ENRICHMENT_ENABLED=falseKeeps tenant deployments from emitting Neo-maintainer repo backlog/PR enrichment sections.
NEO_ORCHESTRATOR_MLX_ENABLED=falseKeeps Apple-Silicon local inference out of the cloud profile; the local-model profile is a separate provider service, not an orchestrator child process.
NEO_MAILBOX_DEFAULT_REPLY_POLICY=blockedKeeps cloud A2A message writes tenant-bound through the Memory Core CAN_REPLY_TO / reachable-counterparty policy; local wake delivery remains disabled by the orchestrator bridge toggle.

NEO_ORCHESTRATOR_KB_SYNC_ENABLED is deliberately absent from that table. kbSyncEnabled lives in the cloudOnly config group, where null means "use the deployment-profile default" — cloud enables, local disables — so the cloud default is already the value you want. Do not pin it in your Compose file: mcpHealthcheck.spec.mjs refuses a compose that restates this variable, because a deployment restating an AiConfig default silently freezes today's value. Disabling kbSync would leave the shared Neo corpus with no producer at all.

Sub D (#11725) owns the CI-safe negative proof that the cloud profile cannot run the forbidden host-edge behavior. The current unit substrate already asserts that cloud-mode default resolution disables primary-dev-sync, bridgeDaemon, and Golden Path repo enrichment unless an operator explicitly opts a lane back in.

Section 3: Container Packaging

Use per-service containers. Sub B (#11723) delivered the profile-structured compose baseline: default MCP stack, cloud orchestrator profile, ingress/local-model profile slots, and per-service resource limits. Sub C (#11724) added the reference ingress and redeploy-safe backup volume wiring. Sub D (#11725) delivered KB/MC container readiness semantics and gates the cloud orchestrator on those MCP server healthchecks. Post-MVP residual #11734 turns the local-model slot into an opt-in service profile while preserving the external-provider default.

Required production-profile properties:

Delivered by Sub B:

  • Dedicated containers for chroma, kb-server, mc-server, and cloud-safe orchestrator.
  • Resource envelopes for each declared service.
  • Default, cloud, ingress, and local-model compose profile structure.

Delivered by Sub C / Sub D:

  • Reverse proxy / TLS ingress and public MCP URL wiring.
  • Volumes for backup bundles that survive container rebuilds.
  • Healthcheck/readiness semantics for KB and MC, plus cloud-orchestrator startup gating on healthy MCP server containers.

Delivered by follow-up persistence hardening:

  • A dedicated orchestrator-state named volume, explicitly bound through NEO_AI_ORCHESTRATOR_DIR, so scheduler, tenant-ingestion, recovery, and diagnostic continuity survives orchestrator-container recreation.

Still owned by follow-up deployment hardening:

  • Optional platform variants for Kubernetes, managed Chroma, managed SQL, and external model providers without changing the logical service model.

Section 4: Reverse Proxy and Auth Boundary

The reverse proxy is the public security boundary. It terminates TLS, enforces OAuth/OIDC or equivalent identity, strips spoofable client identity headers, and injects the trusted identity headers consumed by the MCP servers.

The current internal compose ports are:

ServiceInternal port
kb-server3000
mc-server3001
fleet-server (fleet profile)8083

Sub C (#11724) owns the production ingress wiring. A path-routed deployment can publish /kb/* and /mc/* on one hostname, or the operator can use separate hostnames. In either shape, set each server's NEO_PUBLIC_URL to the canonical public MCP URL that agents will use.

Fleet is not an MCP route. Its public surface exact-matches /fleet and /fleet/probe without prefix stripping, and its own AuthService boundary validates every request before JSON parsing. When the fleet profile is absent, ingress maps only that missing upstream to 404; KB/MC upstream failures remain 502. The Fleet service is intentionally absent from ingress depends_on.

The downloadable fleet profile selects github-pat authentication by default. Set the provider bearer in NEO_MCP_HEALTHCHECK_TOKEN before creating the stack: Compose mounts that value as one secret file used for both the pre-listen provider-subject bootstrap and the authenticated readiness probe; the value never appears in rendered Compose. A public-client OIDC deployment can instead set NEO_AUTH_MODE=oidc plus NEO_AUTH_ISSUER_URL (or the host/port/realm form) and NEO_OAUTH_CLIENT_ID. Confidential-client OIDC requires a secret-aware operator overlay; the reference file deliberately does not interpolate NEO_OAUTH_CLIENT_SECRET.

Header rule: the proxy must remove any incoming X-PREFERRED-USERNAME or X-AUTH-REQUEST-PREFERRED-USERNAME header before injecting its own verified value. With proxy-auth mode enabled, set NEO_AUTH_TRUST_PROXY_IDENTITY=true. For direct OIDC mode, configure the issuer/client values instead of trusting the proxy header path.

Section 5: Persistence, Backups, and Provider Profile

The deployment substrates have different recovery properties:

  • Chroma data is shared by KB and MC but collection-scoped by substrate.
  • KB content is a cache/index over Neo's curated corpus plus tenant-pushed repo content. A KB wipe is recoverable by re-sync/re-push, but the operational cost scales with tenant count.
  • Memory Core graph/session data is a primary store. A wipe between backups is data loss.
  • Orchestrator runtime continuity lives on the orchestrator-state named volume at /app/.neo-ai-data/orchestrator-daemon. It survives a container recreate when the Compose project name stays stable. This includes task cadence, tenant-repo revision/backoff state, recovery ledgers, and logs. Persisted PID and lease files are process-epoch artifacts; boot reconciliation safely reclaims dead owners instead of deleting the continuity directory.
  • Backup bundles persist via a host bind-mount on the cloud-profile orchestrator, whose host source is NEO_HOST_BACKUP_ROOT (default ${HOME}/.neo-ai/backups). The default deliberately does not derive from the Compose project/checkout path — an earlier project-directory-relative default put bundles inside the git working tree, where git clean -x removes them because .neo-ai-data is gitignored. That is the extent of the guarantee: an explicit override is unconstrained, and a checkout placed under the default path would still be reachable, so set the override explicitly if either applies. The container target is NEO_BACKUP_PATH (/app/.neo-ai-data/backups); the two are separate contracts and must not be collapsed into one value. Off-site copy or a managed-object-storage target is the disaster-recovery layer above that.

A named volume is container-recreation durability, not disaster recovery. The current backup bundle does not copy orchestrator-state; include that volume in an explicit off-host backup policy before claiming host-loss recovery.

The canonical Compose file has one deployment identity: NEO_DEPLOY_PROJECT_NAME (default neo-agent-os). Its top-level name creates the Docker project labels and named-volume namespace; the same value configures the orchestrator's constrained runtime-access lookup. Set it once before the first startup and reuse it for inspection, self-heal, and every redeploy. Do not pass a conflicting -p / --project-name value on individual commands.

The orchestrator consumes model-provider endpoints for summary, dream, and similar lanes. External provider endpoints are the MVP default. A self-hosted provider container is a profile variant and should not be coupled to the orchestrator container.

Optional local-model profile

The local-model profile starts an internal OpenAI-compatible provider runtime on local-model:11434. It is inactive unless the operator explicitly includes --profile local-model; merely running the default or cloud profiles does not switch KB, MC, or the orchestrator away from external providers.

Use this profile in two phases so model provisioning failures are easy to separate from Agent OS startup failures:

NEO_LOCAL_MODEL_KEEP_ALIVE=-1 \
NEO_LOCAL_MODEL_CONTEXT_LENGTH=131072 \
NEO_LOCAL_MODEL_NUM_PARALLEL=1 \
NEO_LOCAL_MODEL_MAX_LOADED_MODELS=2 \
NEO_LOCAL_MODEL_MEMORY_LIMIT=32g \
docker compose -f deploy/cloud/docker-compose.yml --profile local-model up -d local-model
docker compose -f deploy/cloud/docker-compose.yml --profile local-model exec local-model ollama pull <chat-model>
docker compose -f deploy/cloud/docker-compose.yml --profile local-model exec local-model ollama pull <embedding-model>

Then start the Agent OS stack with explicit provider env:

NEO_MODEL_PROVIDER=openAiCompatible \
NEO_EMBEDDING_PROVIDER=openAiCompatible \
NEO_OPENAI_COMPATIBLE_HOST=http://local-model:11434 \
NEO_OPENAI_COMPATIBLE_MODEL=<chat-model> \
NEO_OPENAI_COMPATIBLE_EMBEDDING_MODEL=<embedding-model> \
NEO_OPENAI_COMPATIBLE_KEEP_ALIVE=-1 \
NEO_OPENAI_COMPATIBLE_REQUIRE_PARALLEL_MODELS=2 \
docker compose -f deploy/cloud/docker-compose.yml --profile cloud --profile local-model up --build

The requireParallelModels setting is Neo's observable contract for local providers: the chat and embedding model must fit resident at the same time. The orchestrator warns when the configured graph provider only reports one loaded model or is missing either configured model name. For native Ollama deployments, set the provider process environment to at least the same count:

OLLAMA_KEEP_ALIVE=-1 \
OLLAMA_CONTEXT_LENGTH=131072 \
OLLAMA_NUM_PARALLEL=1 \
OLLAMA_MAX_LOADED_MODELS=2 \
ollama serve

For OpenAI-compatible providers, use the provider's own loaded-model cap or pre-load setting (for example LM Studio's loaded-model/JIT setting) and verify GET /v1/models lists both configured model ids before running Sandman.

The expected failure signatures are:

  • Missing model: provider calls fail with model-not-found / pull-required errors while the local-model container healthcheck can still be healthy.
  • Provider not started or not on the compose network: KB/MC/orchestrator provider calls fail to connect to local-model:11434.
  • Resource pressure: the local-model container restarts or fails its healthcheck; tune NEO_LOCAL_MODEL_NUM_PARALLEL, NEO_LOCAL_MODEL_CONTEXT_LENGTH, NEO_LOCAL_MODEL_MAX_LOADED_MODELS, NEO_LOCAL_MODEL_MEMORY_LIMIT, NEO_LOCAL_MODEL_CPU_LIMIT, or the chosen model before treating Agent OS services as faulty.

Section 6: Environment Variable Inventory

Supply these values per service/profile as needed:

VariableTargetPurpose
NEO_TRANSPORT=streamable-httpKB, MCStreamable HTTP transport for deployed MCP servers.
MCP_HTTP_PORTKB, MCInternal listener port. Current baseline: KB 3000, MC 3001.
NEO_PUBLIC_URLKB, MC, FleetCanonical public service URL used for advertised endpoints, auth callbacks, and Fleet resource identity.
NEO_CHROMA_HOSTKB, MC, OrchestratorInternal Chroma host, for example chroma.
NEO_CHROMA_PORTKB, MC, OrchestratorChroma port, normally 8000.
NEO_MEMORY_DB_PATHKB, MC, OrchestratorShared SQLite graph path or mounted graph-store path.
NEO_AUTH_MODEFleetAuthentication installer selector. The downloadable profile defaults to github-pat; set oidc only with a complete endpoint/client configuration.
NEO_AUTH_ISSUER_URL, NEO_AUTH_HOST, NEO_AUTH_PORT, NEO_AUTH_REALM, NEO_OAUTH_CLIENT_IDKB, MC, FleetNon-secret direct OIDC/OAuth inputs. Fleet confidential-client secrets require a secret-aware operator overlay and are never interpolated by the reference Compose file.
NEO_AUTH_GITHUB_API_BASE_URL, NEO_AUTH_GITLAB_API_BASE_URL, NEO_AUTH_PAT_CACHE_TTL_SECONDS, NEO_AUTH_PAT_VALIDATION_TIMEOUT_MS, NEO_AUTH_ALLOWED_USERS, NEO_AUTH_ALLOWED_CLIENT_IDSFleetProvider-PAT validation endpoints and bounded admission controls.
NEO_AUTH_TRUST_PROXY_IDENTITY=trueKB, MCEnables the trusted reverse-proxy identity-header path. Fleet readiness is bearer-based and does not select this compatibility posture.
NEO_MAILBOX_DEFAULT_REPLY_POLICY=blockedMCEnables the strict A2A reply policy for multi-tenant deployments.
NEO_AI_DEPLOYMENT_MODE=cloudOrchestratorSelects the cloud maintenance profile.
NEO_ORCHESTRATOR_PRIMARY_DEV_SYNC_ENABLED=falseOrchestratorDisables local maintainer checkout sync.
NEO_ORCHESTRATOR_BRIDGE_DAEMON_ENABLED=falseOrchestratorDisables desktop wake delivery.
NEO_ORCHESTRATOR_GOLDEN_PATH_REPO_ENRICHMENT_ENABLED=falseOrchestratorDisables Neo-maintainer repo enrichment sections.
NEO_ORCHESTRATOR_MLX_ENABLED=falseOrchestratorKeeps local MLX supervision disabled.
NEO_ORCHESTRATOR_TENANT_REPO_SYNC_ENABLEDOrchestratorMaster toggle for the tenant-repo-sync pull lane. Cloud profile default-on when tenantRepos[] is configured; local profile default-off. Set explicitly to override the deployment-profile default.
NEO_ORCHESTRATOR_TENANT_REPO_SYNC_INTERVAL_MSOrchestratorSweep cadence for the periodic pull lane. Default 1800000 (30 min).
NEO_TENANT_REPO_MIRROR_ROOTOrchestratorParent directory under which the GitMirror primitive stores tenant-repos/<tenant>/<repo> mirrors. Per-repo tenantRepos[].mirrorRoot overrides this Tier-1 default. Canonical compose value /app/.neo-ai-data.
NEO_MODEL_PROVIDERMC, OrchestratorSummary/dream/model-consumer provider selector. Defaults to openAiCompatible (the local OpenAI-compatible route — configure host/model via the rows below); set NEO_MODEL_PROVIDER=gemini for the cloud opt-in (billed remote API). Unset no longer means cloud Gemini.
NEO_EMBEDDING_PROVIDERKB, MCServer-side embedding provider selector. Defaults to openAiCompatible (the local OpenAI-compatible route); set NEO_EMBEDDING_PROVIDER=gemini for cloud embedding generation.
NEO_OPENAI_COMPATIBLE_HOST=http://local-model:11434KB, MC, OrchestratorInternal compose-network URL for the local-model service when the optional profile is enabled.
NEO_OPENAI_COMPATIBLE_MODEL, NEO_OPENAI_COMPATIBLE_EMBEDDING_MODELKB, MC, OrchestratorChat and embedding model names already present in the local-model runtime.
NEO_OPENAI_COMPATIBLE_API_KEYKB, MC, OrchestratorOptional bearer token for OpenAI-compatible providers that require one; normally empty for the local compose service.
NEO_OLLAMA_KEEP_ALIVE, NEO_OPENAI_COMPATIBLE_KEEP_ALIVEKB, MC, OrchestratorProvider request keep-alive override. Default -1 keeps the selected local model resident unless the operator explicitly pins a shorter retention window or 0 unload control.
NEO_OLLAMA_REQUIRE_PARALLEL_MODELS, NEO_OPENAI_COMPATIBLE_REQUIRE_PARALLEL_MODELSKB, MC, OrchestratorLocal-provider residency expectation for chat + embedding coexistence. Default 2; the provider-readiness check warns if the selected graph provider cannot observe that count and both configured model names.
NEO_LOCAL_MODEL_IMAGE, NEO_LOCAL_MODEL_KEEP_ALIVE, NEO_LOCAL_MODEL_CONTEXT_LENGTH, NEO_LOCAL_MODEL_NUM_PARALLEL, NEO_LOCAL_MODEL_MAX_LOADED_MODELS, NEO_LOCAL_MODEL_MEMORY_LIMIT, NEO_LOCAL_MODEL_CPU_LIMITlocal-modelOptional image/runtime/resource overrides for the self-hosted provider container. Defaults keep the model resident (-1), request 131072 context with one parallel request, allow two loaded models for chat + embedding residency, and reserve a 32g memory envelope unless the operator explicitly tunes down.
NEO_AUTO_SYNC=falseKBPrevents one-shot local KB sync during server startup.
NEO_KB_AUTO_START_DATABASE=falseKBPrevents the KB server from starting a local Chroma process.
NEO_MEM_AUTO_START_DATABASE=falseMCPrevents the MC server from starting a local Chroma process.
NEO_MEM_AUTO_START_INFERENCE=falseMCPrevents the MC server from starting local inference.
NEO_AUTO_SUMMARIZE, NEO_AUTO_DREAM, NEO_AUTO_GOLDEN_PATH, NEO_REAL_TIME_MEMORY_PARSING, NEO_AUTO_INGEST_FSMCLocal/server startup toggles; leave disabled unless the deployment owns those daemon behaviors explicitly.
NEO_MCP_HEALTHCHECK_URLHealthcheck CLIOptional override for npm run ai:mcp-healthcheck; compose passes explicit internal URLs instead.
NEO_MCP_HEALTHCHECK_IDENTITYHealthcheck CLITrusted proxy identity value used by the MCP healthcheck probe when proxy-header auth is enabled.
NEO_MCP_HEALTHCHECK_TOKEN_ENV / NEO_MCP_HEALTHCHECK_TOKENHealthcheck CLIOptional bearer-token slot for direct OIDC/OAuth protected MCP healthchecks.
NEO_FLEET_DATA_DIRFleetFleet-owned durable root. The reference service fixes it to /app/.neo-ai-data/fleet on one named volume.
NEO_FLEET_HEALTHCHECK_URLFleet healthcheck CLIOptional override for the exact authenticated /fleet/probe URL.
NEO_MCP_HEALTHCHECK_TOKENGeneric Fleet Compose secret sourceProvider bearer supplied to Docker Compose; only the secret carrier name appears in rendered configuration.
NEO_MCP_HEALTHCHECK_TOKEN_FILEFleet container + healthcheck CLIRequired in-container secret-file bearer carrier; the Fleet probe never accepts the credential on argv.
NEO_AUTH_PAT_DISK_CACHE_PATHPAT-auth MCP/Fleet servicesOptional restart-durable admission-cache file (hash-keyed, no token material). Empty (default) keeps the tier off; when set, each service MUST own a distinct path — one writer per file — on durable storage, so a redeploy during a provider outage admits previously-validated identities instead of locking every seat out.

The top-level AI config template is ai/config.template.mjs. The cloud-ingestion tenant config guide is Configuration.

Section 7: Local-Only Orchestrator Appendix

This section is for Neo maintainer machines only. It is not part of a tenant cloud deployment.

The local orchestrator can sync multiple local Neo checkouts through the primary-dev-sync lane without committing machine-specific paths. Precedence is:

  1. NEO_ORCHESTRATOR_DEV_SYNC_ROOTS
  2. ai/config.mjs orchestrator.devSyncRoots
  3. unset single owning-checkout behavior

For a durable local setup, edit the gitignored ai/config.mjs file. On a fresh clone, npm run prepare auto-creates ai/config.mjs as a copy of ai/config.template.mjs, so it always exists after install — edit the relevant block (e.g. orchestrator.devSyncRoots) and leave the rest at template defaults:

// In your local ai/config.mjs (gitignored; copy of ai/config.template.mjs):
const defaultConfig = {
    // ... preserved template defaults ...
    orchestrator: {
        // ... preserved fields ...
        devSyncRoots: [
            '/absolute/path/to/neo-gpt/neo',
            '/absolute/path/to/neo-gemini/neo',
            '/absolute/path/to/neo-opus-ada/neo'
        ]
    }
};

If the template evolves and your local file falls out of shape-parity, the prepare script warns with the missing imports/exports. Run npm run prepare -- --migrate-config to refresh ai/config.mjs from the template (drops local edits — re-apply them afterward).

Note that npm install deliberately does NOT populate the Knowledge Base: the release artifact carries pre-computed embedding vectors and weighs hundreds of MB, so fetching it is an explicit opt-in. Run npm --prefix cloud run ai:download-kb once (release artifact, no re-embedding) or npm --prefix cloud run ai:sync-kb (build the corpus locally) before relying on ask_knowledge_base-class tools — an empty collection answers with exactly this pointer.

Then start the machine-local orchestrator:

npm run ai:host-edge

This resolves the complete host-edge posture — the host-edge role, deploymentMode=local, a state root outside every checkout, and the lane closure — from src/composition/orchestrator/hostEdgeProfile.mjs. It needs no installer and runs anywhere Node runs; the macOS LaunchAgent is optional supervision over the same command, and the platform matrix lives in ai/scripts/lifecycle/local-agent-os/README.md.

npm --prefix cloud run ai:orchestrator is a different thing and will refuse outside its deployment profile. It starts the same daemon with no role declared, and since #16229 a role is declared, never inherited. Before the Docker cutover that command was correct; afterwards it resolved container-plane — the role the container already owns — so the refusal is what makes a duplicate authority claim visible instead of silent. Declare a role explicitly if you need that entrypoint directly.

For one-off process-manager overrides, keep using the env var — every posture key yields to an explicit value, so this composes rather than conflicts:

NEO_ORCHESTRATOR_DEV_SYNC_ROOTS='["/absolute/path/to/neo-gpt/neo","/absolute/path/to/neo-gemini/neo","/absolute/path/to/neo-opus-ada/neo"]' npm run ai:host-edge

Do not add real local clone paths to package.json or ai/config.template.mjs; the template default remains orchestrator.devSyncRoots: [].

Section 8: Healthcheck and Journey Proof

Deployed proof uses MCP tool calls, not a direct HTTP /healthcheck route. The production compose file runs node ./buildScripts/ai/mcpHealthcheck.mjs inside the KB and MC containers. That script opens a StreamableHTTP client against the local /mcp endpoint, calls the existing healthcheck tool, and exits non-zero unless the payload reports the expected status. Operators can run the same probe manually with npm run ai:mcp-healthcheck.

The Docker readiness contract is:

  • Chroma is ready when its TCP listener is reachable.
  • KB is ready when healthcheck succeeds over http://127.0.0.1:3000/mcp.
  • MC is ready when healthcheck succeeds over http://127.0.0.1:3001/mcp.
  • Fleet, when the fleet profile is selected, is ready only when authenticated GET /fleet/probe returns a non-empty provider identity and the exact configured /app/.neo-ai-data/fleet root.
  • The cloud orchestrator profile starts only after Chroma, KB, and MC are healthy via compose condition: service_healthy; it and ingress deliberately do not hard-depend on optional Fleet.

For public deployed proof, call each server's healthcheck tool over its /mcp endpoint through the same public URL and auth path used by real agents.

Operator verification anchors:

  • identity.source === "proxy-header" confirms the reverse proxy is injecting trusted identity headers and the server is reading them.
  • database.connection.connected === true against the configured engines.chroma coordinate confirms the shared Chroma instance is reachable (the topology is permanently unified by config — there is no separate runtime topology field).
  • Provider fields confirm the selected embedding/summary provider profile.
  • The Memory Core healthcheck remains the schema authority for MC provider/auth details; see Memory Core.

For the local Dockerized fixture, run npm run test-integration-unified. The integration harness builds deploy/cloud/docker-compose.test.yml, waits for Chroma, KB, and MC readiness, then calls the KB and MC healthcheck tools over /mcp. Sub D (#11725) extended the proof to the cloud-safe orchestrator profile and negative local-only behavior assertions.

Section 9: Tenant Repo Ingestion Boundary

Tenant KB content enters through the cloud-native ingestion facades, not through the kbSync scheduler lane — kbSync owns the shared Neo corpus only. Use the Cloud-Native KB Ingestion guide tree for:

  • per-tenant identity and visibility rules;
  • ingest_source_files and bulk CLI hook wiring;
  • custom parser/source registration;
  • tenant config persistence.

Runnable ingestion examples live in ai/examples/cloud-deployment/. They are ingestion-contract demonstrations, not production deployment profiles. The linear first-run operator path is Day-0 Cloud Deployment Tutorial.

Server-side pull mode (tenant-repo-sync lane)

For deployments that prefer the deployment to refresh tenant content autonomously (instead of waiting on a tenant push hook), the additive pull mode is documented in Server-Side Pull Mode. The cloud profile MUST add a tenant-repo-mirrors named volume mounted at <NEO_TENANT_REPO_MIRROR_ROOT>/tenant-repos (canonical compose: /app/.neo-ai-data/tenant-repos) so the GitMirror primitive has a persistent clone target. The env-bound Tier-1 default NEO_TENANT_REPO_MIRROR_ROOT=/app/.neo-ai-data names the parent of tenant-repos/; the helper deriveTenantRepoMirrorPath appends the tenant-repos/<tenant>/<repo> segment. Per-repo lastIngestedRev persistence lives in the orchestrator state dir (<NEO_AI_ORCHESTRATOR_DIR>/tenant-repo-sync-revisions.json), so it survives a container restart on the dedicated orchestrator-state named volume. This is not an off-host backup claim: the mirror cache itself is reproducible from upstream git, while operators who require host-loss recovery for revision continuity must back up the orchestrator-state volume separately.

The tenant-repo-sync lane is gated by NEO_ORCHESTRATOR_TENANT_REPO_SYNC_ENABLED (cloud profile default-on; local maintainer profile default-off) and runs on a 30-minute default cadence (NEO_ORCHESTRATOR_TENANT_REPO_SYNC_INTERVAL_MS). Manual sweep: node ./ai/scripts/maintenance/syncTenantRepos.mjs.

Section 10: Delivered MVP and Residual Owner Map

The #11720 deployment-readiness MVP is complete. The items below are retained as traceability anchors, not active implementation gaps:

  • #11723 - Sub B production container topology.
  • #11724 - Sub C reference compose/profile, ingress, persistence, and provider wiring.
  • #11725 - Sub D healthcheck, journey proof, and negative cloud-profile assertions.
  • #11728 - Sub F2 day-0 tutorial plus Docker-capable fresh-run validation.

Post-MVP residual work is tracked separately under:

  • #11730 - Post-MVP residual architecture after the #11720 closeout.
  • #11731 - server-side repo-clone ingestion exploration, only if push-based tenant ingestion proves insufficient.
  • #11732 - graph-store evolution beyond the SQLite + mounted-volume MVP baseline. Resolved by ADR 0015: keep SQLite + WAL for now; reopen networked SQL only on graph-specific multi-writer, scale, HA, or storage-platform evidence.
  • #11733 - downstream external deployment-pipeline wiring. Delivered post-MVP — see Downstream Pipeline Wiring.
  • #11734 - optional local-model runtime container profile.
  • #11735 - tenant-source inventory deepening beyond the day-0 proof path.
  • #11736 - broader deployment guide/security hardening outside the F1 MVP cleanup; see Security for the first post-MVP hardening ledger.

Related boundary item closed separately:

  • #11719 / PR #11748 - Separate narrow Markdown table rendering fix for the old Section 6. This rewrite removes the old table from the cookbook and intentionally does not use #11719 as a close target.

Completed baseline inputs for this cookbook:

  • #11721 / PR #11738 - D0 ADR 0014 topology and scheduler taxonomy.
  • #11722 / PR #11739 - top-level AI deployment/maintenance config.
  • #11726 / PR #11737 - tenant repo ingestion operational model.