relmio 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/README.md +40 -16
- package/docs/architecture.md +21 -9
- package/docs/local-endpoints-spec.md +101 -13
- package/docs/local-endpoints.md +101 -30
- package/docs/security.md +40 -15
- package/package.json +1 -1
- package/src/domain/local-endpoints.js +187 -14
- package/src/gateway/codex-chat.js +754 -0
- package/src/services/codex-login.js +11 -3
- package/src/services/local-installer.js +859 -20
- package/src/ui/local.css +140 -2
- package/src/ui/local.html +89 -9
- package/src/ui/local.js +157 -37
- package/src/web/server.js +247 -18
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,57 @@ checks the registry separately after publication.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## [0.6.0] - 2026-08-15
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Add an experimental loopback-only Codex Chat Adapter for trusted local
|
|
15
|
+
backends and development servers, with bearer authentication, multi-turn
|
|
16
|
+
conversation IDs, strict resource bounds, and a small Relmio-specific
|
|
17
|
+
`POST /chat` contract.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Make Codex device sign-in target-aware so the experimental Relmio `/chat`
|
|
22
|
+
adapter and native App Server retain isolated, persistent ChatGPT credentials;
|
|
23
|
+
a Platform API key powers neither target and remains reserved for the generic
|
|
24
|
+
OpenAI-compatible `/v1` endpoint.
|
|
25
|
+
|
|
26
|
+
### Security
|
|
27
|
+
|
|
28
|
+
- Reject browser-origin adapter requests, keep the adapter separate from
|
|
29
|
+
Platform-key-backed generic OpenAI-compatible `/v1` semantics, explicitly deny
|
|
30
|
+
model turns access to the private Codex credential store, run chat turns
|
|
31
|
+
read-only without network access, and preserve loopback-only publication plus
|
|
32
|
+
credential rotation.
|
|
33
|
+
|
|
34
|
+
## [0.5.0] - 2026-08-15
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- Add a **Rotate client credential** action for installed local endpoints that
|
|
39
|
+
shows the replacement capability before activation and preserves the upstream
|
|
40
|
+
Platform key or Codex credential/workspace volumes.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- Keep System, Light, and Dark appearance controls plus Ko-fi, GitHub stars, and
|
|
45
|
+
the current package version available throughout the local install wizard.
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Install operating-system CA certificates in the isolated Codex image so the
|
|
50
|
+
official ChatGPT device-code sign-in can establish its trusted TLS connection.
|
|
51
|
+
- Wrap local safety and error notifications instead of clipping longer text.
|
|
52
|
+
|
|
53
|
+
### Security
|
|
54
|
+
|
|
55
|
+
- Verify the generated Codex capability with a strict authenticated WebSocket
|
|
56
|
+
upgrade before reporting installation or rotation success.
|
|
57
|
+
- Serialize installation, sign-in, restart, and credential rotation across
|
|
58
|
+
Relmio processes, with attested stale-lock recovery and fail-closed rollback
|
|
59
|
+
that restores the prior verifier and re-attests endpoint readiness.
|
|
60
|
+
|
|
10
61
|
## [0.4.1] - 2026-08-14
|
|
11
62
|
|
|
12
63
|
### Changed
|
package/README.md
CHANGED
|
@@ -47,8 +47,9 @@ Relmio is a local browser wizard with separate setup paths. Its existing
|
|
|
47
47
|
VPS/n8n path installs a private
|
|
48
48
|
[openai-oauth](https://github.com/EvanZhouDev/openai-oauth) Docker sidecar
|
|
49
49
|
beside an existing self-hosted n8n instance. Its local Docker path can install
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
an OpenAI-compatible gateway backed by a Platform API key, the official Codex
|
|
51
|
+
App Server, or a small server-side Codex chat adapter backed by ChatGPT
|
|
52
|
+
sign-in.
|
|
52
53
|
|
|
53
54
|
The existing n8n image, Compose file, container, and workflows stay untouched.
|
|
54
55
|
|
|
@@ -101,7 +102,8 @@ On desktop, the local wizard keeps progress and sidecar-only safety notes in a
|
|
|
101
102
|
persistent rail beside the active task; its compact fixed-screen shell avoids
|
|
102
103
|
document scrolling on common laptop screens. On narrow phones, it switches to
|
|
103
104
|
a horizontal progress strip and keeps task scrolling inside the active panel.
|
|
104
|
-
|
|
105
|
+
Both the hosted site and local wizard keep Ko-fi support, GitHub stars, and the
|
|
106
|
+
current Relmio version visible beside the appearance control.
|
|
105
107
|
|
|
106
108
|
## Local Docker endpoints
|
|
107
109
|
|
|
@@ -117,29 +119,51 @@ The existing VPS/n8n wizard remains available from native Windows.
|
|
|
117
119
|
|---|---|---|---|
|
|
118
120
|
| **OpenAI API: compatible clients** | `http://127.0.0.1:12435/v1` by default | Server-side OpenAI Platform API key only | Private local app, SDK, or same-owner development web app |
|
|
119
121
|
| **Codex with ChatGPT: agent clients** | `ws://127.0.0.1:14500` by default | ChatGPT sign-in through Codex | Trusted native Codex/App Server client |
|
|
122
|
+
| **Codex Chat Adapter: development backends** | `http://127.0.0.1:14501/chat` by default | ChatGPT sign-in through Codex | Trusted local backend or development server |
|
|
123
|
+
|
|
124
|
+
The Chat Adapter starts each model turn with network access disabled and an
|
|
125
|
+
explicit filesystem policy that permits only Codex's minimal runtime files and
|
|
126
|
+
the empty private workspace. The model-accessible sandbox denies
|
|
127
|
+
`/home/node/.codex`, where the official Codex client keeps its ChatGPT session.
|
|
128
|
+
The adapter bearer must stay in your server-side development environment,
|
|
129
|
+
never browser code.
|
|
120
130
|
|
|
121
131
|
The OpenAI-compatible `/v1` endpoint is powered only by a Platform API key,
|
|
122
132
|
which the wizard seeds over stdin into a private, labeled Docker volume; it
|
|
123
133
|
does not create a host key file. Your app uses a
|
|
124
134
|
separate Relmio capability that the wizard displays once.
|
|
125
|
-
The bearer remains valid until it is rotated.
|
|
135
|
+
The bearer remains valid until it is rotated. After installation, use
|
|
136
|
+
**Rotate client credential** on the Ready screen to replace only that local
|
|
137
|
+
capability. Relmio shows the new one-time credential before activation, verifies
|
|
138
|
+
the replacement endpoint, and preserves the upstream Platform API key or Codex
|
|
139
|
+
credential/workspace volumes. If replacement cannot be verified, Relmio attempts
|
|
140
|
+
to restore the previous verifier and re-attest service readiness. It does not
|
|
141
|
+
retain the previous raw client credential to replay it during rollback. If
|
|
142
|
+
rollback cannot be confirmed, it targets only the exact managed service for
|
|
143
|
+
shutdown and reports whether that stopped state could be verified. Browser requests
|
|
126
144
|
must come from an exact origin entered during setup; wildcards are not allowed,
|
|
127
145
|
and the capability must never be embedded in a public frontend bundle. Platform
|
|
128
146
|
requests use that API project's billing, credits, limits, and permissions, not
|
|
129
147
|
a ChatGPT subscription.
|
|
130
148
|
|
|
131
|
-
ChatGPT sign-in powers
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
and
|
|
141
|
-
|
|
142
|
-
|
|
149
|
+
ChatGPT sign-in powers Codex, not the OpenAI Platform API. The native target
|
|
150
|
+
keeps the official experimental App Server JSON-RPC protocol. The separate
|
|
151
|
+
adapter offers only Relmio's `POST /chat` request and returns a conversation ID
|
|
152
|
+
plus final text; it is not `/v1/chat/completions`, `/v1/responses`, or an
|
|
153
|
+
OpenAI SDK replacement. A local backend can keep its Relmio bearer secret while
|
|
154
|
+
a browser calls that backend. Direct browser-origin requests to both Codex
|
|
155
|
+
targets are rejected.
|
|
156
|
+
|
|
157
|
+
OpenAI documents the underlying App Server WebSocket transport as experimental
|
|
158
|
+
and unsupported for production. The raw App Server capability is especially
|
|
159
|
+
high-trust because it can operate the signed-in Codex session and files inside
|
|
160
|
+
the isolated container workspace. Keep either target loopback-only, same-owner,
|
|
161
|
+
and limited to local development.
|
|
162
|
+
|
|
163
|
+
All three services bind exactly to `127.0.0.1`, require the generated capability,
|
|
164
|
+
and mount no host directory or Docker socket. Each Codex target gets its own
|
|
165
|
+
private named credential and workspace volumes. This local path does not
|
|
166
|
+
connect to a VPS or modify n8n.
|
|
143
167
|
|
|
144
168
|
Read the complete [Local Docker endpoints
|
|
145
169
|
guide](https://github.com/Demonbane18/relmio/blob/main/docs/local-endpoints.md)
|
package/docs/architecture.md
CHANGED
|
@@ -29,28 +29,37 @@ flowchart LR
|
|
|
29
29
|
W --> D["Local Docker Engine"]
|
|
30
30
|
D --> G["OpenAI-compatible gateway<br>127.0.0.1:12435/v1"]
|
|
31
31
|
D --> A["Codex App Server<br>127.0.0.1:14500"]
|
|
32
|
+
D --> H["Codex Chat Adapter<br>127.0.0.1:14501/chat"]
|
|
32
33
|
G -->|"Platform API key"| P["OpenAI Platform API"]
|
|
33
34
|
A -->|"Official Codex sign-in"| C["ChatGPT/Codex service"]
|
|
35
|
+
H -->|"Official App Server lifecycle"| C
|
|
34
36
|
```
|
|
35
37
|
|
|
36
|
-
The
|
|
38
|
+
The three services are intentionally not interchangeable:
|
|
37
39
|
|
|
38
40
|
| Target | Wire protocol | Upstream credential |
|
|
39
41
|
|---|---|---|
|
|
40
42
|
| `openai-api` | OpenAI-compatible HTTP `/v1` | OpenAI Platform API key |
|
|
41
43
|
| `codex-chatgpt` | Official Codex App Server JSON-RPC | ChatGPT sign-in managed by Codex |
|
|
44
|
+
| `codex-chat` | Relmio-specific HTTP `POST /chat` | ChatGPT sign-in managed by Codex |
|
|
42
45
|
|
|
43
46
|
Relmio never adapts a ChatGPT/Codex credential into the local `/v1` gateway.
|
|
44
47
|
The OpenAI gateway replaces the caller's Relmio capability with the
|
|
45
|
-
protected Platform key only at the upstream boundary. The Codex service
|
|
46
|
-
the
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
protected Platform key only at the upstream boundary. The native Codex service
|
|
49
|
+
keeps the initialization, thread, turn, approval, and event protocol. The
|
|
50
|
+
adapter invokes that same official lifecycle behind a bounded, read-only
|
|
51
|
+
conversational contract without claiming OpenAI API compatibility. Its model
|
|
52
|
+
sandbox denies network access and uses a root-deny filesystem policy with only
|
|
53
|
+
minimal runtime paths plus `/workspace` readable; `/home/node/.codex` is
|
|
54
|
+
explicitly denied so a model turn cannot read the persisted ChatGPT session.
|
|
55
|
+
|
|
56
|
+
Each project publishes exactly one literal `127.0.0.1` binding and requires a
|
|
49
57
|
generated bearer capability. Their managed roots are
|
|
50
|
-
`~/.relmio/local/openai-api
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
`~/.relmio/local/openai-api`, `~/.relmio/local/codex-chatgpt`, and
|
|
59
|
+
`~/.relmio/local/codex-chat`. The Codex credentials and workspaces use
|
|
60
|
+
target-specific private named Docker volumes; no host directory or Docker
|
|
61
|
+
socket is mounted. See [Local Docker endpoints](local-endpoints.md) for setup
|
|
62
|
+
and trust limitations.
|
|
54
63
|
|
|
55
64
|
Before installation, Relmio resolves the selected Docker context to a local
|
|
56
65
|
Unix socket and pins that exact socket on every later Docker command. Remote
|
|
@@ -182,3 +191,6 @@ sidecar authenticates upstream with the mounted OAuth file.
|
|
|
182
191
|
or mismatched managed identity blocks local mutation.
|
|
183
192
|
- A Codex login failure returns a sanitized status without returning App
|
|
184
193
|
Server output or ChatGPT tokens.
|
|
194
|
+
- A chat adapter request with a browser Origin, invalid bearer, malformed body,
|
|
195
|
+
protocol overflow, timeout, or failed turn is rejected with a sanitized
|
|
196
|
+
response and its App Server helper is terminated.
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## Status
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Originally approved on 2026-08-13 and extended for the additive
|
|
6
|
+
`codex/local-codex-chat-adapter` target on 2026-08-15.
|
|
6
7
|
|
|
7
8
|
This spec is product and engineering guidance based on the current official
|
|
8
9
|
OpenAI documentation. It is not a legal opinion. Relmio must not claim that
|
|
@@ -13,16 +14,19 @@ OpenAI has endorsed, certified, or pre-approved the project.
|
|
|
13
14
|
Add a local Docker installation path to the Relmio browser wizard without
|
|
14
15
|
weakening the existing VPS/n8n safety boundary.
|
|
15
16
|
|
|
16
|
-
Relmio offers
|
|
17
|
+
Relmio offers three intentionally different local client contracts:
|
|
17
18
|
|
|
18
19
|
1. `openai-api` is an OpenAI-compatible HTTP gateway backed by the user's
|
|
19
20
|
OpenAI Platform API key.
|
|
20
21
|
2. `codex-chatgpt` is the official Codex App Server protocol backed by the
|
|
21
22
|
user's ChatGPT/Codex sign-in.
|
|
23
|
+
3. `codex-chat` is a small Relmio-specific HTTP chat adapter backed by the
|
|
24
|
+
same official App Server lifecycle and ChatGPT/Codex sign-in.
|
|
22
25
|
|
|
23
26
|
Relmio must never exchange, translate, or present a ChatGPT/Codex credential as
|
|
24
|
-
a general OpenAI API bearer credential.
|
|
25
|
-
OpenAI-shaped `/v1` compatibility surface.
|
|
27
|
+
a general OpenAI API bearer credential. Neither Codex target may expose an
|
|
28
|
+
OpenAI-shaped `/v1` compatibility surface. The adapter owns only its narrow
|
|
29
|
+
`POST /chat` contract.
|
|
26
30
|
|
|
27
31
|
## Official-source boundary
|
|
28
32
|
|
|
@@ -53,7 +57,7 @@ The existing VPS/n8n wizard remains a separate legacy setup path. The wizard
|
|
|
53
57
|
landing experience adds a prominent **Local endpoints** option which opens a
|
|
54
58
|
dedicated local installer.
|
|
55
59
|
|
|
56
|
-
The local installer starts with
|
|
60
|
+
The local installer starts with three provider cards:
|
|
57
61
|
|
|
58
62
|
### OpenAI API
|
|
59
63
|
|
|
@@ -81,7 +85,21 @@ The local installer starts with two provider cards:
|
|
|
81
85
|
- An explicit statement that this is Codex JSON-RPC, not OpenAI `/v1`
|
|
82
86
|
- An explicit experimental/non-production notice
|
|
83
87
|
|
|
84
|
-
|
|
88
|
+
### Codex Chat Adapter
|
|
89
|
+
|
|
90
|
+
- Label: **Codex Chat Adapter — development backends**
|
|
91
|
+
- Default HTTP port: `14501`
|
|
92
|
+
- Uses the same pinned official Codex CLI and official device-code sign-in.
|
|
93
|
+
- Result:
|
|
94
|
+
- Endpoint: `http://127.0.0.1:<port>`
|
|
95
|
+
- A newly generated Relmio bearer token, displayed once
|
|
96
|
+
- A device-code sign-in action
|
|
97
|
+
- An explicit server-side-only statement
|
|
98
|
+
- An explicit statement that `POST /chat` is Relmio-specific, not OpenAI
|
|
99
|
+
`/v1`
|
|
100
|
+
- An explicit experimental/non-production notice
|
|
101
|
+
|
|
102
|
+
All three flows show a review screen and require a final confirmation before any
|
|
85
103
|
filesystem or Docker write.
|
|
86
104
|
|
|
87
105
|
This release supports macOS, Linux, and Linux under WSL2. Native Windows is
|
|
@@ -143,7 +161,9 @@ is released in a `finally` path after both success and failure.
|
|
|
143
161
|
### `POST /api/local/codex/login`
|
|
144
162
|
|
|
145
163
|
Starts an official Codex App Server device-code login through a one-shot stdio
|
|
146
|
-
App Server process attached to the
|
|
164
|
+
App Server process attached to the selected Codex target's persistent home
|
|
165
|
+
volume. The request identifies either `codex-chatgpt` or `codex-chat`;
|
|
166
|
+
every other target is rejected before process construction.
|
|
147
167
|
|
|
148
168
|
Every login attempt resolves the managed Codex directory and attests its
|
|
149
169
|
schema-2 marker and matching Docker resources, even in a fresh wizard process.
|
|
@@ -249,12 +269,77 @@ The host mapping is exactly `127.0.0.1:<selected-port>:4500`.
|
|
|
249
269
|
The capability is therefore password-equivalent and limited to a trusted,
|
|
250
270
|
same-owner native client.
|
|
251
271
|
|
|
272
|
+
## Codex Chat Adapter contract
|
|
273
|
+
|
|
274
|
+
The adapter container starts a dependency-free Node HTTP service and launches
|
|
275
|
+
the pinned official `codex app-server --strict-config --stdio` process only
|
|
276
|
+
for a bounded chat operation. It uses the target's private Codex home and
|
|
277
|
+
workspace volumes and never exposes the App Server transport on the host.
|
|
278
|
+
|
|
279
|
+
### Listener and authentication
|
|
280
|
+
|
|
281
|
+
- Container listener: `0.0.0.0:14501`
|
|
282
|
+
- Host publication: `127.0.0.1:<selected-port>:14501`
|
|
283
|
+
- `GET /health` is the only unauthenticated, non-forwarding route.
|
|
284
|
+
- Every route except `GET /health` requires exactly one
|
|
285
|
+
`Authorization: Bearer <Relmio capability>` header.
|
|
286
|
+
- Only the SHA-256 verifier is persisted and comparison is constant-time.
|
|
287
|
+
- Requests with an `Origin` header are rejected and no CORS permission is
|
|
288
|
+
emitted.
|
|
289
|
+
|
|
290
|
+
### Request and response
|
|
291
|
+
|
|
292
|
+
The accepted JSON object contains only:
|
|
293
|
+
|
|
294
|
+
```json
|
|
295
|
+
{
|
|
296
|
+
"input": "Required nonempty conversational input",
|
|
297
|
+
"conversationId": "Optional App Server thread ID"
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The successful response contains only:
|
|
302
|
+
|
|
303
|
+
```json
|
|
304
|
+
{
|
|
305
|
+
"conversationId": "The started or resumed thread ID",
|
|
306
|
+
"output": "The authoritative final agent message"
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
The adapter performs `initialize`, `initialized`, `thread/start` or
|
|
311
|
+
`thread/resume`, and `turn/start`. The turn is constrained to the empty
|
|
312
|
+
private workspace with a read-only sandbox. Its filesystem policy denies root
|
|
313
|
+
by default, permits only Codex's minimal runtime paths and `/workspace`, and
|
|
314
|
+
explicitly denies `/home/node/.codex`; turn network access is disabled. The
|
|
315
|
+
instruction not to inspect or modify files, run commands, call tools, or access
|
|
316
|
+
external resources remains defense in depth, not the credential boundary.
|
|
317
|
+
`item/completed` agent-message text is authoritative; bounded deltas are kept
|
|
318
|
+
separate by `itemId`, with only the most recent item's text used as a
|
|
319
|
+
compatibility fallback. Success requires `turn/completed` with
|
|
320
|
+
`status: completed`.
|
|
321
|
+
|
|
322
|
+
### Resource and failure bounds
|
|
323
|
+
|
|
324
|
+
- Header, body, input, conversation ID, stdout, stderr, line, and output sizes
|
|
325
|
+
are bounded.
|
|
326
|
+
- Concurrent chats, turn duration, child-process termination grace, and the
|
|
327
|
+
final wait for an unreaped process are bounded. The concurrency slot remains
|
|
328
|
+
occupied until the helper closes or that final bound expires.
|
|
329
|
+
- Client disconnect, timeout, malformed protocol, overflow, and failed turns
|
|
330
|
+
terminate the helper.
|
|
331
|
+
- HTTP errors are generic and never include App Server output, process errors,
|
|
332
|
+
ChatGPT credentials, or stderr.
|
|
333
|
+
- Installation and credential rotation verify readiness/authentication without
|
|
334
|
+
starting a model turn or requiring sign-in before the device-code step.
|
|
335
|
+
|
|
252
336
|
## Local filesystem and process boundary
|
|
253
337
|
|
|
254
338
|
Managed roots:
|
|
255
339
|
|
|
256
340
|
- `~/.relmio/local/openai-api`
|
|
257
341
|
- `~/.relmio/local/codex-chatgpt`
|
|
342
|
+
- `~/.relmio/local/codex-chat`
|
|
258
343
|
|
|
259
344
|
`RELMIO_HOME` may replace `~/.relmio` for testing or advanced use, but it must
|
|
260
345
|
be an absolute path whose final component is `.relmio`.
|
|
@@ -282,7 +367,7 @@ Controls:
|
|
|
282
367
|
|
|
283
368
|
## Container hardening
|
|
284
369
|
|
|
285
|
-
|
|
370
|
+
All three long-running endpoint services:
|
|
286
371
|
|
|
287
372
|
- run as a non-root user;
|
|
288
373
|
- set `no-new-privileges`;
|
|
@@ -326,26 +411,29 @@ gateway; it is removed immediately after seeding.
|
|
|
326
411
|
| LAN/public exposure | literal `127.0.0.1` Compose binding plus template and runtime inspection tests |
|
|
327
412
|
| Local cross-site request | bearer capability, exact Origin allowlist, strict preflight, Host validation |
|
|
328
413
|
| Upstream key disclosure | separate local/upstream credentials, stdin-seeded private named volume, redacted errors, no body logging |
|
|
329
|
-
| ChatGPT token repurposing | official App Server only; no `/v1`
|
|
414
|
+
| ChatGPT token repurposing | official App Server lifecycle only; the adapter is Relmio-specific and exposes no `/v1` route |
|
|
330
415
|
| Command injection | validated scalar values, spawn argument arrays, no shell |
|
|
331
416
|
| Managed-path takeover | refuse unmanaged roots and every symlinked component |
|
|
332
417
|
| Streaming resource exhaustion | header/body/concurrency/time bounds and backpressure |
|
|
333
418
|
| Docker privilege compromise | document Docker control as a privileged local boundary; mount no Docker socket into services |
|
|
334
419
|
| Secret recovery from UI | show capabilities once; never use browser storage; rotate on reinstall |
|
|
335
|
-
| Codex capability compromise | explicit
|
|
420
|
+
| Codex capability compromise | explicit trust warning; target-specific least-privilege interfaces, private container volumes, no host mounts, and server-side-only adapter use |
|
|
421
|
+
| Model-induced credential read | root-deny model filesystem profile, minimal runtime read allowlist, explicit `/home/node/.codex` deny, empty private workspace, and no turn network access |
|
|
336
422
|
|
|
337
423
|
## Acceptance criteria
|
|
338
424
|
|
|
339
|
-
- The browser wizard visibly offers
|
|
425
|
+
- The browser wizard visibly offers all three local contracts and the legacy VPS
|
|
340
426
|
path remains separate.
|
|
341
|
-
- Platform keys are accepted only by `openai-api`;
|
|
342
|
-
|
|
427
|
+
- Platform keys are accepted only by `openai-api`; both Codex targets use only
|
|
428
|
+
official App Server-backed ChatGPT authentication.
|
|
343
429
|
- Generated Compose files publish only literal loopback bindings.
|
|
344
430
|
- Every non-health gateway operation that can reach OpenAI and every App Server
|
|
345
431
|
WebSocket handshake is capability-authenticated; exact-origin CORS preflight
|
|
346
432
|
is a non-forwarding metadata exception.
|
|
347
433
|
- Gateway unit/integration tests cover auth, origins, Host validation,
|
|
348
434
|
streaming, cancellation, upstream errors, and secret redaction.
|
|
435
|
+
- Adapter tests cover auth, Origin rejection, request/protocol validation,
|
|
436
|
+
process cleanup, bounds, concurrency, final-output selection, and redaction.
|
|
349
437
|
- Local installer tests prove confirmation, unmanaged-root refusal, symlink
|
|
350
438
|
refusal, port collision behavior, exact Docker arguments, file modes, and
|
|
351
439
|
absence of n8n commands.
|
package/docs/local-endpoints.md
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
# Local Docker endpoints
|
|
2
2
|
|
|
3
3
|
Relmio can install a provider endpoint in Docker on the same computer as your
|
|
4
|
-
app. The local installer
|
|
5
|
-
different authentication methods:
|
|
4
|
+
app. The local installer keeps three explicit client contracts across two
|
|
5
|
+
different provider authentication methods:
|
|
6
6
|
|
|
7
7
|
| Wizard option | Local interface | Upstream sign-in | Intended client |
|
|
8
8
|
|---|---|---|---|
|
|
9
9
|
| **OpenAI API: compatible clients** | OpenAI-compatible HTTP under `/v1` | Server-side OpenAI Platform API key only | A private local app, SDK, or same-owner development web app |
|
|
10
10
|
| **Codex with ChatGPT: agent clients** | Official Codex App Server JSON-RPC over WebSocket | ChatGPT sign-in through Codex | A trusted native Codex/App Server client owned by the same person |
|
|
11
|
+
| **Codex Chat Adapter: development backends** | Relmio-specific HTTP `POST /chat` | ChatGPT sign-in through Codex | A trusted local backend or development server owned by the same person |
|
|
11
12
|
|
|
12
13
|
Relmio does not exchange or translate a ChatGPT OAuth/session credential into
|
|
13
|
-
an OpenAI-compatible `/v1` bearer credential. The Codex option keeps
|
|
14
|
-
thread, turn, approval, and streamed-event semantics
|
|
15
|
-
|
|
14
|
+
an OpenAI-compatible `/v1` bearer credential. The native Codex option keeps
|
|
15
|
+
Codex's thread, turn, approval, and streamed-event semantics. The adapter
|
|
16
|
+
translates only a small Relmio-owned `/chat` contract into that official
|
|
17
|
+
protocol; it does not imitate the OpenAI API.
|
|
16
18
|
|
|
17
19
|
This is a documentation-backed engineering boundary, not legal advice or a
|
|
18
20
|
guarantee that a particular account or use case is permitted. Review the
|
|
@@ -24,10 +26,11 @@ agreements and policies that apply to your account.
|
|
|
24
26
|
this release depends on POSIX owner-only directory and file permissions for
|
|
25
27
|
local credentials.
|
|
26
28
|
- Docker Engine or Docker Desktop with Docker Compose v2 on the local computer
|
|
27
|
-
- A free loopback port (`12435`
|
|
29
|
+
- A free loopback port (`12435` for OpenAI API, `14500` for native Codex,
|
|
30
|
+
or `14501` for the Codex Chat Adapter by default)
|
|
28
31
|
- One of these provider credentials:
|
|
29
32
|
- an OpenAI Platform API key for the OpenAI-compatible endpoint; or
|
|
30
|
-
- a ChatGPT account eligible for Codex for
|
|
33
|
+
- a ChatGPT account eligible for Codex for either Codex target
|
|
31
34
|
- A trusted local app that can keep the Relmio capability secret
|
|
32
35
|
|
|
33
36
|
The local path does not need a VPS or SSH access and does not modify the
|
|
@@ -45,8 +48,8 @@ project on the local computer.
|
|
|
45
48
|
|
|
46
49
|
2. Open the one-time local wizard URL printed in the terminal and choose
|
|
47
50
|
**Local endpoints**.
|
|
48
|
-
3. Choose **OpenAI API: compatible clients
|
|
49
|
-
clients**.
|
|
51
|
+
3. Choose **OpenAI API: compatible clients**, **Codex with ChatGPT: agent
|
|
52
|
+
clients**, or **Codex Chat Adapter: development backends**.
|
|
50
53
|
4. Keep the default port or select another unused local port. For the OpenAI
|
|
51
54
|
API option, add any browser origins that must be allowed and enter your
|
|
52
55
|
Platform API key.
|
|
@@ -64,6 +67,7 @@ inside its managed path. Its local files live under:
|
|
|
64
67
|
```text
|
|
65
68
|
~/.relmio/local/openai-api
|
|
66
69
|
~/.relmio/local/codex-chatgpt
|
|
70
|
+
~/.relmio/local/codex-chat
|
|
67
71
|
```
|
|
68
72
|
|
|
69
73
|
Advanced or test environments can set `RELMIO_HOME` before starting the
|
|
@@ -77,19 +81,29 @@ Engine.
|
|
|
77
81
|
|
|
78
82
|
## Safe updates and credential rotation
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
84
|
+
To replace only the credential used by your local client, select **Rotate client
|
|
85
|
+
credential** on the installed endpoint's Ready screen. Relmio first stages and
|
|
86
|
+
shows the new one-time capability while the previous capability remains active.
|
|
87
|
+
It then updates and validates the managed Compose configuration, recreates only
|
|
88
|
+
the attested service, and verifies the new bearer against `/v1/models`, the
|
|
89
|
+
authenticated Codex WebSocket handshake, or the adapter's authenticated probe
|
|
90
|
+
before reporting success.
|
|
91
|
+
|
|
92
|
+
This client-only rotation preserves the upstream Platform API key in its private
|
|
93
|
+
named volume and preserves the Codex home and workspace volumes. If activation
|
|
94
|
+
or verification fails, Relmio restores the previous verifier and re-attests its
|
|
95
|
+
health and loopback publication. Relmio does not retain the previous raw client
|
|
96
|
+
credential, so rollback does not replay an authenticated request with it. If
|
|
97
|
+
that rollback cannot be confirmed, Relmio attempts to stop only the exact
|
|
98
|
+
managed service and reports whether the stopped state could be verified.
|
|
99
|
+
|
|
100
|
+
Rerun the browser wizard with the same target and port when you need a complete
|
|
101
|
+
managed update. Relmio verifies the marker and Docker resource ownership and
|
|
102
|
+
reuses the installation's unique Compose identity. For `openai-api`, provide the
|
|
103
|
+
current or replacement Platform API key during that full update; Relmio reseeds
|
|
104
|
+
its private named volume independently from the local client capability. A full
|
|
105
|
+
`codex-chatgpt` or `codex-chat` update retains the private Codex home and
|
|
106
|
+
workspace volumes unless you explicitly delete them.
|
|
93
107
|
|
|
94
108
|
Do not hand-edit the marker, Compose file, credential volume, or verifier. If
|
|
95
109
|
the marker or resource labels do not attest as one Relmio installation, the
|
|
@@ -196,9 +210,61 @@ workspace and credential volume. The service receives no host directory,
|
|
|
196
210
|
Docker socket, SSH key, browser profile, or host home-directory mount. This
|
|
197
211
|
reduces host exposure; it does not make an untrusted App Server client safe.
|
|
198
212
|
|
|
213
|
+
## Codex Chat Adapter: development backends
|
|
214
|
+
|
|
215
|
+
The adapter result screen provides:
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
Endpoint: http://127.0.0.1:14501
|
|
219
|
+
Authorization: Bearer <the Relmio capability shown once by the wizard>
|
|
220
|
+
Protocol: Relmio Codex Chat HTTP
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
After completing the same official Codex device-code sign-in, a local backend
|
|
224
|
+
can start a conversation with:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
export RELMIO_CODEX_CHAT_KEY="<capability shown once by the wizard>"
|
|
228
|
+
curl http://127.0.0.1:14501/chat \
|
|
229
|
+
-H "Authorization: Bearer $RELMIO_CODEX_CHAT_KEY" \
|
|
230
|
+
-H "Content-Type: application/json" \
|
|
231
|
+
--data '{"input":"Reply with a short hello."}'
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The response contains only the App Server thread ID and final conversational
|
|
235
|
+
text:
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{
|
|
239
|
+
"conversationId": "thread-id-from-the-first-response",
|
|
240
|
+
"output": "Hello!"
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Send that `conversationId` with the next `input` to continue the same
|
|
245
|
+
conversation. The adapter initializes the official App Server, starts or
|
|
246
|
+
resumes the thread, runs a read-only conversational turn, and returns the
|
|
247
|
+
authoritative final agent message. The model sandbox has no network access and
|
|
248
|
+
uses a root-deny filesystem policy that reads only Codex's minimal runtime
|
|
249
|
+
paths and the empty private workspace. It explicitly denies
|
|
250
|
+
`/home/node/.codex`, the private volume containing the ChatGPT session.
|
|
251
|
+
|
|
252
|
+
This route is deliberately not `/v1/chat/completions` or `/v1/responses`.
|
|
253
|
+
OpenAI SDKs and tools that require those schemas still need the Platform-backed
|
|
254
|
+
OpenAI API target. The adapter rejects every request carrying an `Origin`
|
|
255
|
+
header and sends no CORS permission, so browser JavaScript must not call it
|
|
256
|
+
directly. Keep the bearer in a trusted local backend or development server and
|
|
257
|
+
let the browser call that server's own session-aware route.
|
|
258
|
+
|
|
259
|
+
The adapter is experimental because it depends on the experimental App Server
|
|
260
|
+
interface. It is loopback-only, single-owner development tooling, not a hosted,
|
|
261
|
+
LAN, multi-user, or production service. It enforces bounded request bodies,
|
|
262
|
+
output, concurrency, process lifetime, and sanitized failures, but those
|
|
263
|
+
controls do not create a general-purpose API entitlement.
|
|
264
|
+
|
|
199
265
|
## Network and container boundary
|
|
200
266
|
|
|
201
|
-
|
|
267
|
+
Every local Compose project publishes exactly one host mapping:
|
|
202
268
|
|
|
203
269
|
```text
|
|
204
270
|
127.0.0.1:<selected-port>:<container-port>
|
|
@@ -207,12 +273,13 @@ Both local Compose projects publish exactly one host mapping:
|
|
|
207
273
|
They are not available through the computer's LAN address. Each long-running
|
|
208
274
|
service runs as a non-root user, drops Linux capabilities, sets
|
|
209
275
|
`no-new-privileges`, uses a read-only root filesystem, and has bounded
|
|
210
|
-
temporary storage and resource limits.
|
|
276
|
+
temporary storage and resource limits. None of the services mounts the Docker
|
|
211
277
|
socket or a general host directory. The one-shot OpenAI seed helper has no
|
|
212
278
|
network, port, or logs and retains only `CHOWN` while running as root long
|
|
213
279
|
enough to atomically set ownership on the volume entry.
|
|
214
280
|
The OpenAI gateway receives only its private API-key named volume, mounted
|
|
215
|
-
read-only; Codex
|
|
281
|
+
read-only; both Codex targets receive no host path and use target-specific
|
|
282
|
+
private named volumes.
|
|
216
283
|
|
|
217
284
|
The loopback binding and capability are complementary controls. Other
|
|
218
285
|
processes running as the same local user may still be able to reach a loopback
|
|
@@ -235,7 +302,8 @@ literal values only after confirming all of these conditions:
|
|
|
235
302
|
In every example, manually replace each angle-bracket placeholder with the
|
|
236
303
|
already-validated literal. Do not use `eval`, source the JSON, or construct a
|
|
237
304
|
Docker command from unvalidated marker text. The only valid service name is
|
|
238
|
-
`gateway` for `openai-api
|
|
305
|
+
`gateway` for `openai-api`, `codex` for `codex-chatgpt`, or `codex-chat`
|
|
306
|
+
for `codex-chat`.
|
|
239
307
|
|
|
240
308
|
### Recover from a failed install
|
|
241
309
|
|
|
@@ -276,7 +344,7 @@ service:
|
|
|
276
344
|
docker --host <dockerHost> compose \
|
|
277
345
|
--project-name <projectName> \
|
|
278
346
|
--file <absolute-managed-compose> \
|
|
279
|
-
rm --stop --force <gateway-or-codex>
|
|
347
|
+
rm --stop --force <gateway-or-codex-or-codex-chat>
|
|
280
348
|
```
|
|
281
349
|
|
|
282
350
|
This recovery command does not target other services, remove the project
|
|
@@ -335,7 +403,8 @@ docker --host <dockerHost> compose \
|
|
|
335
403
|
`--volumes` irreversibly deletes the managed Codex home and workspace volumes,
|
|
336
404
|
including the container's ChatGPT credentials. After Docker confirms the
|
|
337
405
|
matching resources are gone, you may remove only the exact
|
|
338
|
-
`~/.relmio/local/codex-chatgpt`
|
|
406
|
+
`~/.relmio/local/codex-chatgpt` or `~/.relmio/local/codex-chat` managed
|
|
407
|
+
directory for the target you verified through your file manager.
|
|
339
408
|
|
|
340
409
|
## Troubleshooting
|
|
341
410
|
|
|
@@ -349,8 +418,9 @@ matching resources are gone, you may remove only the exact
|
|
|
349
418
|
- **Browser request rejected:** enter the exact page origin, including scheme
|
|
350
419
|
and port, then update the managed endpoint. Wildcards are intentionally not
|
|
351
420
|
supported.
|
|
352
|
-
- **Browser cannot connect to Codex:** this is expected.
|
|
353
|
-
|
|
421
|
+
- **Browser cannot connect to Codex:** this is expected. Both Codex targets
|
|
422
|
+
reject browser-origin requests. Use the raw App Server from a trusted native
|
|
423
|
+
client or keep the Chat Adapter bearer in a local backend.
|
|
354
424
|
- **Codex reports signed out:** repeat the device-code sign-in in the local
|
|
355
425
|
wizard. Never copy a Codex credential file between users.
|
|
356
426
|
- **Native Windows:** this local Docker feature is unsupported. Run Relmio in a
|
|
@@ -364,6 +434,7 @@ credentials and Codex/ChatGPT authentication:
|
|
|
364
434
|
|
|
365
435
|
- [OpenAI API authentication](https://developers.openai.com/api/reference/overview#authentication)
|
|
366
436
|
- [Codex authentication](https://learn.chatgpt.com/docs/auth)
|
|
437
|
+
- [Codex permission profiles](https://learn.chatgpt.com/docs/permissions)
|
|
367
438
|
- [Codex App Server protocol and WebSocket limitations](https://learn.chatgpt.com/docs/app-server)
|
|
368
439
|
- [Codex for Open Source program terms](https://learn.chatgpt.com/docs/codex-for-oss-terms)
|
|
369
440
|
|