Skip to content

[codex] Support marketplace plugin manifest fallback#28789

Merged
charlesgong-openai merged 3 commits into
mainfrom
dev/charlesgong/marketplace-manifest-from-index
Jun 18, 2026
Merged

[codex] Support marketplace plugin manifest fallback#28789
charlesgong-openai merged 3 commits into
mainfrom
dev/charlesgong/marketplace-manifest-from-index

Conversation

@charlesgong-openai

@charlesgong-openai charlesgong-openai commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Support marketplace plugins whose source directory does not include a discoverable plugin manifest. Metadata-rich marketplace.json entries now act as fallback plugin manifests for listing, local detail reads, install, and non-curated cache refresh.

The fallback preserves marketplace-entry plugin fields wholesale, then adds the small Codex-facing compatibility bridge for presentation metadata. A real source plugin.json always wins when present.

Details

  • Capture flattened marketplace-entry fields into MarketplacePluginManifestFallback, preserving fields such as version, description, skills, mcpServers, apps, hooks, agents, commands, strict, author, and future manifest fields without a per-field translation list.
  • Bridge Claude-style top-level displayName, author.name, homepage, and marketplace category into Codex's nested interface fields only when the nested values are absent.
  • Treat fallback metadata as installable only when the marketplace entry contributes metadata beyond bare name and source; existing missing-manifest behavior remains for metadata-free entries.
  • Read local plugin details from the already parsed fallback manifest, including fallback-declared app and MCP paths, instead of rereading only an on-disk manifest.
  • Pass fallback contents into PluginStore, which validates them and injects .codex-plugin/plugin.json into Store's existing atomic copy. Local marketplace source directories are never mutated, and the fallback path no longer needs an additional staging directory.
  • Keep Git source materialization unchanged; Git clones still use the existing marketplace source staging area before Store installation.

@charlesgong-openai charlesgong-openai force-pushed the dev/charlesgong/marketplace-manifest-from-index branch 4 times, most recently from ee33893 to d177c44 Compare June 18, 2026 17:12

@charlesgong-openai charlesgong-openai left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline walkthrough of the rebuilt marketplace-manifest fallback diff.

pub display_name: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq)]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value carries the synthesized plugin manifest alongside the resolved marketplace entry. has_metadata deliberately distinguishes metadata-rich entries from bare name/source entries, so a marketplace entry does not silently become installable unless it actually supplies plugin metadata.

plugin_root.join(".codex-plugin/plugin.json")
}

fn marketplace_plugin_manifest_fallback(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the compatibility boundary. Flattened marketplace fields are preserved wholesale, including skills arrays, commands, agents, strict, and future manifest fields. The helper below only bridges Claude-style top-level presentation fields into Codex interface fields when the nested value is absent.

}

plugin_sources.insert(plugin_key, plugin.source);
let manifest_fallback = find_marketplace_plugin(&marketplace.path, &plugin.name)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-curated cache refresh now retains fallback JSON with each source. That matters because refresh runs later than marketplace discovery and otherwise loses the metadata needed to compute the fallback version and reinstall a manifest-less plugin.

};
let store = self.store.clone();
let codex_home = self.codex_home.clone();
let manifest_fallback_contents = resolved

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Install passes fallback contents directly into PluginStore. There is no prepare-source copy here anymore; Store owns validation and injection inside its existing atomic cache copy, while the four match arms preserve explicit-version and inferred-version behavior.

plugin_version_for_install_manifest(source_path, manifest)
}

fn resolve_install_manifest<'a>(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This centralizes precedence: an on-disk plugin.json always wins, including when it is malformed. The fallback is only selected when no supported manifest path exists, matching the previous behavior and avoiding accidental override of a plugin-owned manifest.

.replace('\\', "/");
assert_eq!(logs.matches("ignoring interface.defaultPrompt").count(), 8);
assert_eq!(logs.matches("gmail/.codex-plugin/plugin.json").count(), 4);
assert_eq!(logs.matches("ignoring interface.defaultPrompt").count(), 4);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected warning counts are halved because app and MCP detail loading no longer performs a second manifest read. The test still guards the original invariant: marketplace discovery is not reloaded per plugin.

}

#[test]
fn find_marketplace_plugin_builds_manifest_fallback_from_entry() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This broad fixture is the compatibility contract. It verifies parsed Codex behavior and raw JSON preservation separately, including skills arrays, MCP objects, URL spelling, author, agents, commands, strict, homepage, and category.

}

#[tokio::test]
async fn install_plugin_writes_marketplace_manifest_fallback_when_missing_plugin_json() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This end-to-end install test proves three ownership guarantees together: the source receives no plugin.json, no extra fallback staging root is created, and the installed cache receives a usable synthesized manifest.

}

#[tokio::test]
async fn read_plugin_for_config_uses_marketplace_manifest_fallback_paths_for_local_source() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the regression test for the local detail-read gap. It uses a non-default app path and inline MCP declaration so both would disappear if any loader reread only an on-disk manifest.


#[test]
fn install_uses_manifest_version_when_present() {
fn install_prefers_on_disk_manifest_version_over_fallback() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This existing version test now supplies a conflicting fallback version. Keeping the installed path at 1.2.3-beta+7 proves real on-disk manifest precedence over fallback metadata.

@charlesgong-openai charlesgong-openai force-pushed the dev/charlesgong/marketplace-manifest-from-index branch 2 times, most recently from a9c17a5 to 9e6d728 Compare June 18, 2026 20:15
@charlesgong-openai charlesgong-openai marked this pull request as ready for review June 18, 2026 20:45

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e6d728ae3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread codex-rs/core-plugins/src/manager.rs Outdated
Comment thread codex-rs/core-plugins/src/manager.rs Outdated
Comment thread codex-rs/core-plugins/src/marketplace.rs
@charlesgong-openai charlesgong-openai force-pushed the dev/charlesgong/marketplace-manifest-from-index branch from e453af0 to 13e476c Compare June 18, 2026 21:53
@charlesgong-openai charlesgong-openai merged commit 772c5c5 into main Jun 18, 2026
31 checks passed
@charlesgong-openai charlesgong-openai deleted the dev/charlesgong/marketplace-manifest-from-index branch June 18, 2026 22:49
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 18, 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