OceanCode
15 · Platform mode (PlungeAI connectivity)
oceancode ships in two builds. The default build is the standalone coding agent and contains
no platform code at all. The platform build is produced with
cargo build --release -p ocean-cli --features platformand adds the three PlungeAI couplings: the OceanTunnel daemon (crates/ocean-app/src/oceantunnel.rs),
the enrich resolver (crates/ocean-agent/src/systemcontext/remote.rs) and the per-step remote
capability packs (crates/ocean-agent/src/systemcontext/capability.rs). Everything the ocean
config section describes below is inert in the default build.
The platform cargo feature is declared on three crates — ocean-agent, ocean-app and
ocean-cli — and is off by default. The OceanInfo schema itself (every ocean.* key)
stays in the leaf crate ocean-config in both builds, so an oceancode.json with an ocean
section parses either way; only the code that acts on it is gated.
Which build do I have?
node scripts/gates/check-platform-boundary.mjs --no-build scans the two release binaries for three
byte-literal markers after a release build and reports markers_local=0 markers_platform=3 when the
boundary holds; a routine ./check.sh proves the same boundary on debug builds (--debug, which
builds target/debug/oceancode under both feature sets and scans between the builds — no release
build needed). At runtime, oceancode inspect reports a platform row: compiled in on a platform
build, not compiled in on the default build.
The "platform: not compiled in" notice
A default build that finds ocean.mode = "platform" or a non-empty ocean.endpoint in
oceancode.json prints once at boot and in oceancode inspect:
platform: not compiled in (ocean.mode or ocean.endpoint is set; rebuild with --features platform)It is a single warning, not an error: the agent still runs, exactly as it does for any user with no
ocean section. Rebuild with --features platform to make the section take effect. A config without
an ocean section prints nothing.
Config keys
The ocean.* keys are serde-only and present in both builds; they take effect only in the platform
build (crates/ocean-config/src/ocean.rs:15-88).
| Key | Meaning | Default |
|---|---|---|
mode | local or platform. The only switch that selects platform behaviour. | local |
endpoint | Enrich URL (GET ?agent=<name>&directory=<dir> → {baseline, version}). | empty |
headers | Headers sent on every platform request (auth lives here). | none |
ttl_seconds | How often a session re-checks the enrich endpoint (0 → 300). | 300 |
agents | Platform-resolved agent names; empty defaults to ocean-build, ocean-plan. | ocean-build, ocean-plan |
mcp_url | Auto-registers the platform MCP gateway as a remote MCP server named ocean. | empty |
capability_endpoint | Per-step capability pack endpoint. | empty |
gateway_base_url | The inference gateway a provider baseURL should point at: the bare host or its /v1 root, both work. | https://api.plungeai.com/v1 in platform mode |
tunnel_url | OceanTunnel dial-out URL; with a token, runs the tunnel daemon. | empty |
tunnel_token | Inline OceanTunnel session token. | empty |
tunnel_token_file | File holding the tunnel token (~/ expands against $HOME). | empty |
tunnel_agent | Local agent name registered with the tunnel. | oceancode |
The switch is config-only. No environment variable selects platform mode; ocean.mode in
oceancode.json is the only switch — there is no OCEANCODE_MODE / OC_MODE. Two platform-related
environment variables the binary reads never turn platform mode on by themselves:
OC_TUNNEL_TOKEN— the tunnel session token, read at the highest priority (above the deprecatedOCEAN_TUNNEL_TOKEN, thentunnel_token_file, then the inlinetunnel_token).OCEAN_TUNNEL_TOKENis still read as a legacy fallback and logs one deprecation warning per process.OC_SSO_TOKEN— a per-request gateway SSO session token. When set, oceancode attaches it as theX-Ocean-SSO-Tokenheader (noBearerprefix) on requests to the configured https gateway host only — never a direct-provider host, never over plaintext — and never onAuthorization(the wallet bearer, yourozk_key, stays intact). Read at runtime, never persisted. Server-side reader is a pending platform handoff: until the inference gateway readsX-Ocean-SSO-Token, the header is ignored (harmless).
Every variable also has a row in 02 · Configuration.
Per-step capabilities
In platform mode the local <available_skills> catalog is replaced by a capability pack sized to
the plan row the model is working. At each step boundary the resolver asks the capability endpoint for
a pack (eager skill bodies within a 24 KiB budget, a deferred index, and a version); 304 when the
pack is unchanged, so the retained prefix — and the provider's prompt cache — never changes because a
skill changed. Deferred bodies cost nothing until pulled:
load_capabilitytool — a platform-build tool that pulls a deferred capability body by id (load_capability {id}) into the transcript as a normal tool result, never a file on disk. It is registered only in the platform build and refuses any id the platform never offered.capabilitypermission — the permission family that governsload_capability. It asks by default in the read-only agent families (ask,explore,security-review) and is allowed for thebuild,planandgeneralfamilies.- Registry skills — platform mode can also discover skills straight from the registry with no local
files; they surface with the provenance
platform:<id>(tierplatform, bound tool idskill_platform_<id>) and load with no base-directory line.
Model routing and the wallet
Signing in. On a platform build, oceancode login --provider ocean (alias plungeai) signs you in
through the browser and stores your account key. It opens the dashboard's
https://dashboard.plungeai.com/api/cli/authorize page with a loopback port, you sign in with any method
the dashboard offers, the dashboard hands a one-time code back to http://127.0.0.1:<port>/callback, and
oceancode trades that code for your ozk_ account key and stores it in auth.json under ocean — the
entry oceancode key ocean writes and platform mode uses first. The key never appears in a browser URL.
--no-browser prints the link without opening it; the sign-in gives up after three minutes;
oceancode logout ocean removes the key.
With an ozk_ platform key stored — oceancode key ocean ozk_… (it lands in auth.json), or a credential
under the ocean integration — platform mode synthesizes an ocean provider whose baseURL is the
gateway's /v1 root (https://api.plungeai.com/v1 unless gateway_base_url says otherwise), so every model
call routes through the inference gateway. A legacy sk-ocean- key is found the same way; when both are
stored the ozk_ key wins. A model of auto is resolved once per session from the gateway's
/v1/discovery/recommend (falling back to anthropic/claude-sonnet-4-5 if the recommend call fails).
The run --format json result envelope then carries two extra objects for a platform-routed run:
platform: { fallback_steps } (how many steps failed open to the local route) and
wallet: { balance, spent } (present only when the gateway meters). A local run omits both.
The ledger in platform mode
Two engine-owned sections in SESSION.md are fed by platform-mode durable events:
## Plan changes by user— regenerated fromtodo.updatedevents, one summary line per event that carried user-authored plan rows (the model's own edits contribute nothing).## Capabilities used— regenerated frompack.manifestevents, one| step | ids | version | hash |row per step; a fallback step lists its row with an empty id cell.
Both are bounded to the newest 20 rows and regenerated on every write, so they never crowd out model-owned sections. Plan rows also carry cross-session history: when a row that completed or was cancelled in an earlier session reappears, its projection shows how often it was seen and how often it failed.