Expose plugin manifest keywords in app server (#21271)

## Summary
- Add plugin manifest keywords to core plugin marketplace/detail models
- Expose keywords on app-server v2 PluginSummary and generated
schema/types
- Populate keywords in plugin/list and plugin/read responses for local
plugins

Depends on https://github.com/openai/openai/pull/891087

## Validation
- just fmt
- just write-app-server-schema
- cargo test -p codex-app-server-protocol
- cargo test -p codex-core-plugins
- cargo test -p codex-app-server
plugin_list_keeps_valid_marketplaces_when_another_marketplace_fails_to_load
- cargo test -p codex-app-server
plugin_read_returns_plugin_details_with_bundle_contents
This commit is contained in:
Abdulrahman Alfozan
2026-05-06 02:09:05 +00:00
committed by GitHub
parent 136e442e95
commit 94db03d5af
20 changed files with 140 additions and 2 deletions
+27
View File
@@ -18,6 +18,8 @@ struct RawPluginManifest {
version: Option<String>,
#[serde(default)]
description: Option<String>,
#[serde(default)]
keywords: Vec<String>,
// Keep manifest paths as raw strings so we can validate the required `./...` syntax before
// resolving them under the plugin root.
#[serde(default)]
@@ -37,6 +39,7 @@ pub struct PluginManifest {
pub name: String,
pub version: Option<String>,
pub description: Option<String>,
pub keywords: Vec<String>,
pub paths: PluginManifestPaths,
pub interface: Option<PluginManifestInterface>,
}
@@ -143,6 +146,7 @@ pub fn load_plugin_manifest(plugin_root: &Path) -> Option<PluginManifest> {
name: raw_name,
version,
description,
keywords,
skills,
mcp_servers,
apps,
@@ -232,6 +236,7 @@ pub fn load_plugin_manifest(plugin_root: &Path) -> Option<PluginManifest> {
name,
version,
description,
keywords,
paths: PluginManifestPaths {
skills: resolve_manifest_path(plugin_root, "skills", skills.as_deref()),
mcp_servers: resolve_manifest_path(
@@ -568,6 +573,28 @@ mod tests {
assert_eq!(manifest.version, Some("1.2.3-beta+7".to_string()));
}
#[test]
fn plugin_manifest_reads_keywords() {
let tmp = tempdir().expect("tempdir");
let plugin_root = tmp.path().join("demo-plugin");
fs::create_dir_all(plugin_root.join(".codex-plugin")).expect("create manifest dir");
fs::write(
plugin_root.join(".codex-plugin/plugin.json"),
r#"{
"name": "demo-plugin",
"keywords": ["api-key", "developer tools"]
}"#,
)
.expect("write manifest");
let manifest = load_manifest(&plugin_root);
assert_eq!(
manifest.keywords,
vec!["api-key".to_string(), "developer tools".to_string()]
);
}
#[test]
fn plugin_manifest_uses_alternate_discoverable_path() {
let tmp = tempdir().expect("tempdir");