# Secured local Company OS deployment

This path runs native Company OS agents against company tasks and memory in
one local Docker Compose installation. OpenRouter credentials live in a
separate gateway container. The Company OS API receives a local gateway token,
not the OpenRouter key.

The mode is `openrouter-gateway-v1`. It is intentionally narrower than the
general development runtime: shell, filesystem, arbitrary HTTP, dynamic
external tool dispatch, vendor CLI backends, and BYO provider credentials are
refused. It is not a packaged desktop or unattended multi-tenant hosting
release. The broader release gate remains independent.

## What runs

```text
Browser on this computer
    → Console / Company OS API (published on loopback only)
        → Postgres: tasks, memory, approvals, runs, spend, receipts
        → credential-gateway (private)
            → https://openrouter.ai/api/v1
```

The API, Console, bootstrap, and Postgres use an internal Docker network.
Only the credential gateway joins an outbound network. It routes exactly
`POST /api/v1/chat/completions` and `GET /api/v1/models`. It rejects redirects,
alternate destinations, unsupported paths, missing authentication, and
requests exceeding its limits. It does not provide a generic HTTP proxy.

The real provider key is a private read-only secret mount belonging only to
the gateway. No host home, Docker socket, or provider secret directory is
mounted into the API. The local gateway token authorizes inference and must
still be protected; Company OS continues to own tool admission, budgets,
approvals, and receipts.

The canonical production Compose contract runs the API, Console, and
bootstrap with a read-only root filesystem, all Linux capabilities dropped,
`no-new-privileges`, finite CPU/memory/PID ceilings, and a bounded `/tmp`
tmpfs. API data and logs remain the only writable persistent mounts. The API
also forces strict chat safety and the no-network Docker shell boundary;
model-authored code execution additionally requires server-derived human
approval. If that dedicated Docker boundary is unavailable, shell execution
fails closed rather than inheriting the API container as an implicit sandbox.

This isolates the OpenRouter key. The API still holds the database and API
credentials it needs to operate. The gateway, the host administrator, and the
provider are trusted with the upstream key; response filtering removes literal
key echoes and is not a defense against a malicious provider encoding a key.

## Install

Prerequisites: Docker Engine/Desktop with Compose v2 or later, a release image
that contains the gateway and runtime admission checks, an OpenRouter key in
a private file owned by the installing user, and an explicitly chosen model.
Do not paste the key into a command, `.env`, a task, or a chat message.

From a checkout containing this implementation:

```bash
chmod 600 /absolute/path/to/openrouter-key
DEFAULT_LLM_MODEL='your-selected-model-id' \
bash install.sh --profile full --credential-gateway \
  --provider-key-file /absolute/path/to/openrouter-key \
  --dir /absolute/path/to/company-os-install \
  --image ghcr.io/permutationresearch/company-os@sha256:YOUR_RELEASE_DIGEST \
  --no-open
```

Use the digest of an image built from the same reviewed source revision.
An older image does not gain runtime enforcement merely because a newer
Compose file sets the mode. `--no-start` prepares configuration without
requiring a running daemon and requires an immutable image digest.

The installer preserves the existing companion path. Use a fresh directory
for this secured path; enabling it over an existing direct-credential
installation requires an explicit migration and is refused. Existing
provider keys in that installation's database or files are not silently
deleted, moved, or rotated.

Each secured installation has its own saved Compose project name and data
volumes. If another installation already uses the default loopback ports, set
`COMPANY_OS_API_PORT`, `COMPANY_OS_CONSOLE_PORT`, and
`COMPANY_OS_POSTGRES_PORT` to unused ports for the first install. Subsequent
installer runs use the saved configuration; ambient shell variables cannot
replace its credentials or selected runtime profile.

## Supported work

Native agents may list, create, and update tasks; search and append company
memory; and request human attention. Existing Company OS permissions still
apply to every operation. Unsupported tools are absent from model discovery
and are refused on direct dispatch. Unsupported worker backends are refused
before a run starts, including when recovering an older run.

The secured Console selects `hsm_native_worker` for its default agent work.
An explicitly selected unsupported backend is still refused.

Use a bounded first task such as summarizing known company tasks and saving
an approved summary to company memory. Confirm the final task status, run,
tool receipts, and memory readback in the Console. An HTTP health response
alone is not evidence that an agent task completed.

## Verification

Source checks:

```bash
node --test services/company-os-credential-gateway/*.test.mjs
node --test scripts/company-os-credential-install.test.mjs
node --test scripts/company-os-companion-install.test.mjs
bash scripts/company-os-infra-contracts.sh
bash scripts/cargo-reliable.sh test -p company-os-core credential_boundary
bash scripts/cargo-reliable.sh check --lib
bash scripts/cargo-reliable.sh test --lib credential_boundary
bash scripts/company-os-credential-boundary-proof.sh --dir /absolute/path/to/company-os-install
```

Gateway tests use a synthetic local upstream, never a real provider key.
They verify authentication substitution, refusal paths, response handling,
limits, and streaming. Installer checks resolve the real Compose model and
verify secret mounts, environment, and networks; they do not establish
container isolation at runtime.

The credential-boundary CI workflow runs the gateway and installer checks on
relevant pull requests. Image builds depend on those checks. The image workflow
also installs the exact image digest with a synthetic provider credential and
runs the isolation proof; that job does not contact a real model or prove task
completion.

Before calling a release operationally supported, run its exact image digest
on an isolated installation and record all of the following:

1. Postgres and API are healthy; bootstrap completed; Console is reachable.
2. The gateway is healthy and has no published port.
3. API containers have no provider secret mount or direct internet route.
4. A native task completes through the gateway with run and tool receipts.
5. A prohibited tool/backend is refused, with the matching refusal evidence.
6. Gateway restart or upstream failure produces a visible bounded error, and
   recovery retains the supported backend and credential mode.

Do not print `docker inspect`, `.env`, secret files, or full resolved Compose
configuration into shared logs: infrastructure and local gateway tokens
remain sensitive even though the upstream key is absent from API containers.

## Upgrade, recovery, and rollback

Keep the installation directory and database backup together in protected
storage. Back up both private gateway files along with the existing Company
OS infrastructure credentials. Re-running the installer must reuse the
existing local token and upstream key; it must not regenerate credentials
behind a running installation.

Upgrade only to another reviewed image digest containing the same boundary
contract. Keep the previous digest and a database backup before applying
migrations. An image rollback alone is not a database downgrade.

If the gateway is unhealthy, inspect its safe status logs and verify private
file ownership and permissions. If inference returns an upstream error,
verify the provider account/model separately without printing credentials.
Do not recover by adding the real key to the API environment or disabling
the boundary. Stop only this installation's Compose project when needed;
retain its database volumes. Restore from the verified backup if a schema
change prevents returning to the previous release.

To stop this installation without deleting its data, use
`bash install.sh --dir /absolute/path/to/company-os-install --uninstall`.
Keep its `.env` when restoring: it contains the stable Compose project identity
as well as the infrastructure credentials.

## Evidence status

Local verification on 2026-09-07 passed the gateway HTTP suite, secured and
companion installer suites, resolved Compose contracts, shell syntax, and
workflow YAML parsing. Core boundary configuration tests passed (3 tests), and
an earlier `cargo check --bin hsm_console` passed.

The later `cargo-reliable.sh check --lib` failed writing an artifact with
`No space left on device`. The new root ToolRegistry refusal regression test
and database-backed dispatch/recovery checks have not passed in this session.
The root test helper's disk guard was not overridden.

There was no running Docker daemon. An isolated Colima attempt failed while
expanding its VM image with `No space left on device`; the owned failed
instance and downloaded cache were removed. No secured stack, real model
task, or new image workflow has been run. Operational support remains pending
the exact-image release proof above.
