Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ platform/architecture companion artifacts beside the ZIP. Convax verifies their
size and SHA-256 into host-owned storage, so users do not install a sidecar through
`PATH` and executables still never enter a Plugin package.

`convax.plugin/5` additionally declares an LLM provider as bounded provider/model
metadata. The verified sidecar supplies a random, Main-only loopback gateway at
runtime; manifests and service projections never contain upstream URLs, Cookies,
headers, or credentials.

`convax.plugin/4` adds Plugin-owned Skills. A v4 Plugin declares
`contributes.skills`, and the packer injects each referenced standard Skill
workspace into the Plugin ZIP. Convax may show that Skill in its catalog, but its
Expand Down
24 changes: 24 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ STORE method. Thus identical source bytes produce identical SHA-256 digests acro
machines. Uncompressed storage is intentional: packages are already size-bounded,
and avoiding compressor-version drift makes releases reproducible.

A headless `convax.plugin/2`, `convax.plugin/3`, or `convax.plugin/4` Tool Plugin may contain only `manifest.json` and a
A headless `convax.plugin/2` through `convax.plugin/5` Tool Plugin may contain only `manifest.json` and a
license notice. Its generation and/or service contribution uses one declared
`mcp-stdio` executable that is a separate distributable and
must never appear anywhere below `package/`; validation and packing do not install,
Expand Down
47 changes: 41 additions & 6 deletions docs/plugin-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ served through a private protocol and mounted in an iframe with exactly
`sandbox="allow-scripts"`. It has an opaque origin: it cannot inspect the parent
DOM, use browser storage as shared application state, or access Node/Electron.

`convax.plugin/2`, `convax.plugin/3`, and `convax.plugin/4` may instead be headless
`convax.plugin/2` through `convax.plugin/5` may instead be headless
executable Tool Plugins. New executable Plugins should use v3, or v4 when they own
Skills. Their ZIP still contains no executable code: the manifest names a separately distributed bare
Skills; use v5 only when they contribute an LLM provider. Their ZIP still contains no executable code: the manifest names a separately distributed bare
`mcp-stdio` command for generation and/or fixed service actions. The Registry may
bind that command to verified platform artifacts that Convax installs into
host-owned storage. Explicit Plugin install/update authorizes that exact binding;
Expand All @@ -16,13 +16,14 @@ later tool calls do not add another local-command prompt.
## Manifest

`package/manifest.json` uses `convax.plugin/1`, `convax.plugin/2`,
`convax.plugin/3`, or `convax.plugin/4`. Only
`convax.plugin/3`, `convax.plugin/4`, or `convax.plugin/5`. Only
documented fields are accepted. Source metadata must use the matching pair:

- `convax.plugin/1` with `convax.plugin-host/1`;
- `convax.plugin/2` with `convax.plugin-host/2`;
- `convax.plugin/3` with `convax.plugin-host/3`.
- `convax.plugin/4` with `convax.plugin-host/4`.
- `convax.plugin/5` with `convax.plugin-capability/1`.

The v1 schema is static-only:

Expand Down Expand Up @@ -182,15 +183,15 @@ closed and require reinstall. The Plugin manifest never contains build paths,
vendor credentials, or a fallback download URL, and the user does not need to copy
the executable into `PATH`.

A v2, v3, or v4 Web surface that calls installed generation tools requests
A v2 through v5 Web surface that calls installed generation tools requests
`generation.execute` and uses an ordinary `entry` plus Canvas contribution. It may
omit `runtime` and `contributes.generation`. Declaring a runtime does not grant the
Web surface caller authority, and granting `generation.execute` does not let the
iframe start processes or send arbitrary MCP requests.

## Plugin service contribution

A v2, v3, or v4 executable Plugin may expose bounded account/service state through the same
A v2 through v5 executable Plugin may expose bounded account/service state through the same
verified sidecar process used by generation. The manifest declares only which
fixed host actions are meaningful; it cannot choose MCP method names or attach an
action payload:
Expand Down Expand Up @@ -235,11 +236,45 @@ to the matching authorization generation, never return it through MCP, and clear
it on sign-out. Mode `0600` is best-effort isolation from other OS users; it does
not protect against processes already running as the same OS account.

## LLM provider contribution

`convax.plugin/5` may contribute one OpenAI-compatible provider through the same
verified sidecar lifecycle. The manifest contains display and selection metadata
only:

```json
{
"contributes": {
"llm": {
"provider": { "id": "example-llm", "name": "Example LLM" },
"models": [{ "id": "example-main", "name": "Example Main" }]
}
}
}
```

The sidecar must expose the fixed, empty-input MCP tool `llm.gateway.start`. Its
Main-only `structuredContent` is exactly `{schema, base_url, api_key}` with schema
`convax.llm-gateway/1`, an ephemeral `http://127.0.0.1:<port>/v1` URL, and a random
process-lifetime key. The gateway accepts only authenticated OpenAI-compatible
requests for declared models. It owns upstream URLs, headers, credentials, Cookies,
streaming, cancellation, and vendor error adaptation; none of those values belongs
in the manifest, renderer, service status, or durable OpenCode config.

Hosts namespace provider ids by Plugin identity, verify the installed executable
before starting it, and discard the gateway when that exact Plugin runtime changes.
An unavailable or invalid gateway is omitted rather than weakening loopback or
executable verification.

The v5 compatibility pair deliberately uses the independently versioned
`convax.plugin-capability/1` broker. It does not extend the legacy iframe
`convax.plugin-host/N` sequence.

## Host connection

Convax transfers one fresh `MessagePort` to each mounted Plugin node. Accept it only
from `window.parent`, for the host protocol matching the manifest major (`/1`,
`/2`, `/3`, or `/4`), the exact Plugin id, and only once:
`/2`, `/3`, `/4`, or `/5`), the exact Plugin id, and only once:

```js
const PROTOCOL = "convax.plugin-host/1";
Expand Down
5 changes: 3 additions & 2 deletions docs/registry-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ catalog-changing release or yanking deployment. `revision` is the lowercase, ful

Every item contains `kind`, `id`, `name`, `description`, `version`,
`compatibility`, `artifact`, and `yanked`, plus a complete `manifest` for Plugin items.
A `convax.plugin/2`, `convax.plugin/3`, or `convax.plugin/4` item with a generation and/or service external runtime may additionally contain
A `convax.plugin/2` through `convax.plugin/5` item with an external runtime may additionally contain
`companions`; no other item may contain it.
The duplicated Plugin identity fields must equal the manifest so the management UI
can render and filter without downloading ZIPs. Skill items have no `manifest`.
Expand Down Expand Up @@ -49,7 +49,8 @@ complete validated manifest. Plugin compatibility accepts exactly one
version-matched pair: `convax.plugin/1` + `convax.plugin-host/1`,
`convax.plugin/2` + `convax.plugin-host/2`,
`convax.plugin/3` + `convax.plugin-host/3`, or
`convax.plugin/4` + `convax.plugin-host/4`. The embedded manifest schema must match
`convax.plugin/4` + `convax.plugin-host/4`, or
`convax.plugin/5` + `convax.plugin-capability/1`. The embedded manifest schema must match
that pair. Crossed pairs and a v1 compatibility envelope around a v2 manifest are
rejected. Skill compatibility is exactly `{"skillSchema":"opencode.skill/1"}`.
Artifact objects contain only `url`, `size`, and lowercase hex `sha256`; URLs always
Expand Down
28 changes: 28 additions & 0 deletions packages/plugins/codex-service/convax-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"schema": "convax.package/1",
"kind": "plugin",
"id": "codex-service",
"name": "Codex",
"description": "Binds an existing local Codex installation and account to Convax for GPT-5.6, GPT-5.5, and GPT Image 2 without copying Codex credentials.",
"version": "0.1.1",
"license": "MIT",
"compatibility": {
"pluginSchema": "convax.plugin/5",
"pluginHost": "convax.plugin-capability/1"
},
"companions": [
{
"command": "convax-codex-mcp",
"version": "0.1.1",
"source": "packages/tools/codex-mcp",
"targets": [
{
"platform": "darwin",
"arch": "arm64",
"path": "dist/darwin-arm64/convax-codex-mcp"
}
]
}
],
"yanked": false
}
13 changes: 13 additions & 0 deletions packages/plugins/codex-service/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@microvoid/convax-plugin-codex-service",
"version": "0.1.1",
"private": true,
"type": "module",
"dependencies": {
"@microvoid/convax-codex-mcp": "workspace:*"
},
"scripts": {
"validate": "bun ../../../tooling/validate.mjs --kind plugin --id codex-service",
"pack": "bun ../../../tooling/pack.mjs --kind plugin --id codex-service"
}
}
21 changes: 21 additions & 0 deletions packages/plugins/codex-service/package/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Microvoid contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
39 changes: 39 additions & 0 deletions packages/plugins/codex-service/package/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"schema": "convax.plugin/5",
"id": "codex-service",
"name": "Codex",
"description": "Binds an existing local Codex installation and account to Convax for GPT-5.6, GPT-5.5, and GPT Image 2 without copying Codex credentials.",
"version": "0.1.1",
"contributes": {
"generation": {
"models": [
{ "tool": "image.gpt-image-2", "name": "GPT Image 2" }
],
"tools": [
{
"id": "image.gpt-image-2",
"title": "Codex · GPT Image 2",
"description": "Generate or edit an image through the bound local Codex account and its built-in GPT Image 2 capability.",
"output": "image",
"acceptedInputs": ["reference_image"]
}
]
},
"llm": {
"provider": { "id": "codex", "name": "Codex" },
"models": [
{ "id": "gpt-5.6-sol", "name": "GPT-5.6-Sol" },
{ "id": "gpt-5.6-terra", "name": "GPT-5.6-Terra" },
{ "id": "gpt-5.6-luna", "name": "GPT-5.6-Luna" },
{ "id": "gpt-5.5", "name": "GPT-5.5" }
]
},
"service": {
"actions": ["authorize", "reauthorize"]
}
},
"runtime": {
"type": "mcp-stdio",
"command": "convax-codex-mcp"
}
}
1 change: 1 addition & 0 deletions packages/tools/codex-mcp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/
36 changes: 36 additions & 0 deletions packages/tools/codex-mcp/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Local Codex companion contract

This directory owns the separately installed `convax-codex-mcp` companion for
the `codex-service` Plugin. The executable is not part of the Plugin ZIP.

- Bind only to a user-installed Codex executable and its documented app-server
protocol. Never read, copy, return, or persist Codex tokens, cookies, config,
rollout files, or SQLite state directly.
- Keep the Codex child on stdio. The only network listener is the random-key,
loopback-only OpenAI-compatible gateway returned to Convax Main by
`llm.gateway.start`.
- Service status may use only `account/read`, `account/rateLimits/read`,
`model/list`, and `modelProvider/capabilities/read`. Return unavailable fields
honestly and never expose native paths, raw Codex errors, or full rate-limit
payloads through MCP.
- `service.authorize` and `service.reauthorize` only re-probe the existing local
Codex binding. They never log the user in, log the user out, open a browser, or
mutate Codex configuration.
- Accept only the declared GPT-5.6 and GPT-5.5 model ids at the gateway and verify
that the bound Codex catalog currently exposes the requested model.
- Translate caller tools through Codex dynamic tools. Never execute them in the
companion. Interrupt the ephemeral Codex turn after capturing a tool call and
return that call to the OpenAI-compatible caller.
- GPT Image 2 generation uses Codex's built-in `imageGeneration` capability. Read
only host-staged reference-image paths and write final artifacts only beneath
the supplied `output_directory`.
- Bound handshake, metadata, and individual protocol requests. Once an LLM or
image turn starts, keep it alive until completion, explicit failure, child exit,
or caller cancellation; do not impose an arbitrary overall deadline.
- Human diagnostics go only to stderr and must not include credentials, account
email addresses, native paths, prompts, model output, or raw upstream bodies.
- The release build writes only `dist/darwin-arm64/convax-codex-mcp`; it must never
be copied under the Plugin package directory.

Run `bun run typecheck`, `bun test`, `bun run build`, and
`bun run build:release:darwin-arm64` before handoff.
16 changes: 16 additions & 0 deletions packages/tools/codex-mcp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Convax Codex companion

`convax-codex-mcp` binds the Convax Codex Plugin to an existing local Codex
installation. It starts Codex app-server over stdio, reuses Codex-managed login
state without reading credentials, and exposes only the fixed Convax MCP tools.

Supported catalog entries are `gpt-5.6-sol`, `gpt-5.6-terra`,
`gpt-5.6-luna`, `gpt-5.5`, and the built-in GPT Image 2 generation capability.
The actual model and image capability are checked against the bound Codex process
at runtime. Account and quota display degrades to unavailable when Codex does not
provide the corresponding metadata.

The first release target is macOS arm64. The locator checks official application
bundle locations and a real executable named `codex` on the absolute host `PATH`;
it validates `codex --version` before starting app-server. Configure or reconnect
means re-probing that local installation. Login and logout remain owned by Codex.
21 changes: 21 additions & 0 deletions packages/tools/codex-mcp/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@microvoid/convax-codex-mcp",
"version": "0.1.1",
"private": true,
"license": "MIT",
"type": "module",
"bin": {
"convax-codex-mcp": "dist/convax-codex-mcp"
},
"scripts": {
"build": "bun build --compile --minify --outfile dist/convax-codex-mcp src/index.ts",
"build:release:darwin-arm64": "bun build --compile --minify --target=bun-darwin-arm64 --outfile dist/darwin-arm64/convax-codex-mcp src/index.ts",
"clean": "rm -rf dist",
"test": "bun test",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@types/bun": "1.3.14",
"typescript": "5.9.3"
}
}
Loading