Skip to content

[codex-core-plugins] Remote Plugin ID Persisted to File#27669

Merged
jameswt-oai merged 2 commits into
mainfrom
jameswt/persist-remote-plugin-identity
Jun 22, 2026
Merged

[codex-core-plugins] Remote Plugin ID Persisted to File#27669
jameswt-oai merged 2 commits into
mainfrom
jameswt/persist-remote-plugin-identity

Conversation

@jameswt-oai

@jameswt-oai jameswt-oai commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

This PR

Remote plugin analytics cannot rely only on the in-memory installed-plugin snapshot because that snapshot is refreshed asynchronously after startup. This PR persists the authoritative backend identity alongside each cached remote plugin bundle so later consumers can resolve it without a network request.

Behavior

  • Store Codex-owned remote installation metadata in an atomic .codex-remote-plugin-install.json sidecar under the plugin cache root.

  • Use a versioned, snake_case schema:

    {
      "schema_version": 1,
      "remote_plugin_id": "plugins~Plugin_..."
    }
  • Write the metadata during remote bundle installation.

  • Backfill it when bundle sync finds an already-current cached bundle.

  • Clear it when a generic/local install replaces the cache.

  • Let existing uninstall and stale-cache removal delete it with the plugin cache root.

  • Reject unsupported schema versions rather than silently misreading future formats.

This PR does not change analytics serialization or event behavior.

Review surface

The implementation is limited to four codex-core-plugins files:

  • store.rs: owns the versioned sidecar read/write/remove lifecycle.
  • remote_bundle.rs: persists the backend ID after a remote bundle install.
  • remote/remote_installed_plugin_sync.rs: backfills metadata for an already-current cached bundle.
  • Tests cover the storage lifecycle and both remote write paths.

Testing / Validation

Automated

  • just test -p codex-core-plugins (268 tests passed)
  • just fix -p codex-core-plugins passes with one pre-existing large_enum_variant warning in manifest.rs.
  • Coverage verifies the exact filename and JSON schema, identity replacement, local reinstall clearing, uninstall cleanup, remote bundle installation, unsupported schema rejection, and installed-plugin sync backfill.

Live manual validation

Validated the production app-server RPC path with an isolated temporary CODEX_HOME and the PR-built Codex binary. The app-server communicated over stdio and did not bind a port.

Test plugin: plugins~Plugin_b80dd84519148191a409cde181c9b3d6 (build-macos-apps@openai-curated-remote).

  1. Confirmed plugin/read initially reported the plugin uninstalled.

  2. Installed it through plugin/install and confirmed version 0.1.4 was cached.

  3. Verified $CODEX_HOME/plugins/cache/openai-curated-remote/build-macos-apps/.codex-remote-plugin-install.json was created beside the 0.1.4/ bundle directory with mode 0600 and the expected contents:

    {
      "schema_version": 1,
      "remote_plugin_id": "plugins~Plugin_b80dd84519148191a409cde181c9b3d6"
    }
  4. Deleted only the sidecar, restarted the app-server, and confirmed installed-plugin startup sync recreated it with the same contents.

  5. Uninstalled through plugin/uninstall, confirmed plugin/read returned installed: false, and verified the local plugin cache root was removed.

  6. Restored the account's original uninstalled state and removed the isolated home and copied credentials.

Split Overview

main
├── #27093  Debug analytics capture                     merged
│   └── #27099  Non-mutating plugin smoke               merged
│       └── #27100  Remote install/uninstall smoke      merged
└── #27102  Plugin telemetry metadata refactor          merged
    └── #27669  Persist remote plugin identity           ← this PR

Next:
└── Final PR: add explicit local and remote IDs to plugin analytics

This PR is based directly on main; prerequisite #27102 has merged. The original combined #26281 remains the aggregate reference until the final replacement PR is published.

@jameswt-oai jameswt-oai changed the title Persist remote plugin identities with cached bundles [codex-core-plugins] Persist remote plugin identities with cached bundles Jun 11, 2026
@jameswt-oai jameswt-oai changed the title [codex-core-plugins] Persist remote plugin identities with cached bundles [codex-core-plugins] Remote Plugin ID Persisted to File Jun 11, 2026
jameswt-oai added a commit that referenced this pull request Jun 22, 2026
This PR moves construction of `PluginTelemetryMetadata` from loader and
model helpers into `PluginsManager`, which already owns installed plugin
state and will eventually perform remote identity enrichment. The
metadata type remains in `codex-plugin`, and serialized analytics events
remain unchanged.

## Before

```mermaid
flowchart LR
    subgraph Events["Analytics event paths"]
        direction TB
        Lifecycle["Local install / uninstall"]
        Config["Enable / disable"]
        Remote["Remote install"]
        Used["Plugin used"]
    end

    subgraph Construction["Metadata construction"]
        direction TB
        Loader["Loader telemetry helpers"]
        Summary["PluginCapabilitySummary::telemetry_metadata"]
        Override["Caller adds remote_plugin_id"]
    end

    Metadata["PluginTelemetryMetadata"]

    Lifecycle --> Loader
    Config --> Loader
    Remote --> Loader
    Loader -->|"local events"| Metadata
    Loader -->|"remote install"| Override
    Override --> Metadata
    Used --> Summary
    Summary --> Metadata
```

Telemetry metadata was constructed through loader helpers, a
capability-summary method, and a remote-install call-site override.

## After

```mermaid
flowchart LR
    subgraph Events["Analytics event paths"]
        direction TB
        Lifecycle["Local install / uninstall"]
        Config["Enable / disable"]
        Remote["Remote install"]
        Used["Plugin used"]
    end

    Manager["PluginsManager — single construction owner"]
    Metadata["PluginTelemetryMetadata"]

    Lifecycle --> Manager
    Config --> Manager
    Remote -->|"authoritative remote ID"| Manager
    Used -->|"capability summary"| Manager
    Manager --> Metadata
```

Every analytics path delegates metadata construction to
`PluginsManager`. Remote install still supplies its authoritative
backend ID explicitly.

## What Changes

- Make loader code return a focused plugin capability summary instead of
constructing analytics metadata.
- Centralize immutable plugin telemetry metadata construction in
`PluginsManager`.
- Route local install/uninstall, remote install, enable/disable, and
plugin-used emitters through the manager.
- Preserve the current serialized analytics contract exactly.

Normal metadata still has no remote override. Remote install continues
to provide its authoritative backend ID explicitly, so the existing
serializer continues reporting that ID through `plugin_id`.
Snapshot-based enrichment is intentionally deferred to the final PR.

## Testing

- `just test -p codex-core-plugins` (238 tests passed)
- `just test -p codex-plugin` (3 tests passed)
- Scoped Clippy/compile checks passed for `codex-plugin`,
`codex-core-plugins`, `codex-app-server`, and `codex-core`.

## Split Overview

```text
main
├── #27093  Debug analytics capture                 (merged)
├── #27099  Non-mutating plugin smoke               (merged)
├── #27100  Remote install/uninstall smoke          (merged)
└── #27102  Plugin telemetry metadata refactor      ← you are here
    └── #27669  Persist remote plugin identity

After #27102 and #27669 merge:
└── Final PR: add explicit local and remote IDs to plugin analytics
```

Review order and dependencies:

1. [#27093 Add debug-only analytics event
capture](#27093) (merged)
2. [#27099 Add a plugin analytics smoke
workflow](#27099) (merged)
3. [#27100 Add a remote plugin analytics mutation smoke
workflow](#27100) (merged)
4. This metadata refactor, independent and based on `main`
5. [#27669 Persist remote plugin
identity](#27669), stacked on this
PR
6. Final remote-ID behavior PR, created after the prerequisites merge

The original [#26281](#26281)
remains open as the aggregate reference until the final replacement PR
is published.
Base automatically changed from jameswt/plugin-telemetry-metadata-refactor to main June 22, 2026 17:27
@jameswt-oai jameswt-oai force-pushed the jameswt/persist-remote-plugin-identity branch from ce0b03e to bcc3551 Compare June 22, 2026 17:38
@jameswt-oai jameswt-oai force-pushed the jameswt/persist-remote-plugin-identity branch from bcc3551 to 14a18bd Compare June 22, 2026 17:39
@jameswt-oai jameswt-oai marked this pull request as ready for review June 22, 2026 17:39
@jameswt-oai

Copy link
Copy Markdown
Contributor Author

/merge

@jameswt-oai jameswt-oai merged commit a72433d into main Jun 22, 2026
31 checks passed
@jameswt-oai jameswt-oai deleted the jameswt/persist-remote-plugin-identity branch June 22, 2026 21:28
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants