Skip to content

Commit 5776801

Browse files
committed
feat: support disable skills by name.
1 parent 7754dd1 commit 5776801

26 files changed

+1068
-140
lines changed

codex-rs/app-server-protocol/schema/json/ClientRequest.json

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,13 +2343,27 @@
23432343
"enabled": {
23442344
"type": "boolean"
23452345
},
2346+
"name": {
2347+
"description": "Name-based selector.",
2348+
"type": [
2349+
"string",
2350+
"null"
2351+
]
2352+
},
23462353
"path": {
2347-
"type": "string"
2354+
"anyOf": [
2355+
{
2356+
"$ref": "#/definitions/AbsolutePathBuf"
2357+
},
2358+
{
2359+
"type": "null"
2360+
}
2361+
],
2362+
"description": "Path-based selector."
23482363
}
23492364
},
23502365
"required": [
2351-
"enabled",
2352-
"path"
2366+
"enabled"
23532367
],
23542368
"type": "object"
23552369
},

codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11323,6 +11323,9 @@
1132311323
"description": {
1132411324
"type": "string"
1132511325
},
11326+
"enabled": {
11327+
"type": "boolean"
11328+
},
1132611329
"interface": {
1132711330
"anyOf": [
1132811331
{
@@ -11348,6 +11351,7 @@
1134811351
},
1134911352
"required": [
1135011353
"description",
11354+
"enabled",
1135111355
"name",
1135211356
"path"
1135311357
],
@@ -11404,13 +11408,27 @@
1140411408
"enabled": {
1140511409
"type": "boolean"
1140611410
},
11411+
"name": {
11412+
"description": "Name-based selector.",
11413+
"type": [
11414+
"string",
11415+
"null"
11416+
]
11417+
},
1140711418
"path": {
11408-
"type": "string"
11419+
"anyOf": [
11420+
{
11421+
"$ref": "#/definitions/v2/AbsolutePathBuf"
11422+
},
11423+
{
11424+
"type": "null"
11425+
}
11426+
],
11427+
"description": "Path-based selector."
1140911428
}
1141011429
},
1141111430
"required": [
11412-
"enabled",
11413-
"path"
11431+
"enabled"
1141411432
],
1141511433
"title": "SkillsConfigWriteParams",
1141611434
"type": "object"

codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9083,6 +9083,9 @@
90839083
"description": {
90849084
"type": "string"
90859085
},
9086+
"enabled": {
9087+
"type": "boolean"
9088+
},
90869089
"interface": {
90879090
"anyOf": [
90889091
{
@@ -9108,6 +9111,7 @@
91089111
},
91099112
"required": [
91109113
"description",
9114+
"enabled",
91119115
"name",
91129116
"path"
91139117
],
@@ -9164,13 +9168,27 @@
91649168
"enabled": {
91659169
"type": "boolean"
91669170
},
9171+
"name": {
9172+
"description": "Name-based selector.",
9173+
"type": [
9174+
"string",
9175+
"null"
9176+
]
9177+
},
91679178
"path": {
9168-
"type": "string"
9179+
"anyOf": [
9180+
{
9181+
"$ref": "#/definitions/AbsolutePathBuf"
9182+
},
9183+
{
9184+
"type": "null"
9185+
}
9186+
],
9187+
"description": "Path-based selector."
91699188
}
91709189
},
91719190
"required": [
9172-
"enabled",
9173-
"path"
9191+
"enabled"
91749192
],
91759193
"title": "SkillsConfigWriteParams",
91769194
"type": "object"

codex-rs/app-server-protocol/schema/json/v2/PluginReadResponse.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@
318318
"description": {
319319
"type": "string"
320320
},
321+
"enabled": {
322+
"type": "boolean"
323+
},
321324
"interface": {
322325
"anyOf": [
323326
{
@@ -343,6 +346,7 @@
343346
},
344347
"required": [
345348
"description",
349+
"enabled",
346350
"name",
347351
"path"
348352
],

codex-rs/app-server-protocol/schema/json/v2/SkillsConfigWriteParams.json

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,36 @@
11
{
22
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"definitions": {
4+
"AbsolutePathBuf": {
5+
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
6+
"type": "string"
7+
}
8+
},
39
"properties": {
410
"enabled": {
511
"type": "boolean"
612
},
13+
"name": {
14+
"description": "Name-based selector.",
15+
"type": [
16+
"string",
17+
"null"
18+
]
19+
},
720
"path": {
8-
"type": "string"
21+
"anyOf": [
22+
{
23+
"$ref": "#/definitions/AbsolutePathBuf"
24+
},
25+
{
26+
"type": "null"
27+
}
28+
],
29+
"description": "Path-based selector."
930
}
1031
},
1132
"required": [
12-
"enabled",
13-
"path"
33+
"enabled"
1434
],
1535
"title": "SkillsConfigWriteParams",
1636
"type": "object"

codex-rs/app-server-protocol/schema/typescript/v2/SkillSummary.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
44
import type { SkillInterface } from "./SkillInterface";
55

6-
export type SkillSummary = { name: string, description: string, shortDescription: string | null, interface: SkillInterface | null, path: string, };
6+
export type SkillSummary = { name: string, description: string, shortDescription: string | null, interface: SkillInterface | null, path: string, enabled: boolean, };
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
// GENERATED CODE! DO NOT MODIFY BY HAND!
22

33
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
4+
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
45

5-
export type SkillsConfigWriteParams = { path: string, enabled: boolean, };
6+
export type SkillsConfigWriteParams = {
7+
/**
8+
* Path-based selector.
9+
*/
10+
path?: AbsolutePathBuf | null,
11+
/**
12+
* Name-based selector.
13+
*/
14+
name?: string | null, enabled: boolean, };

codex-rs/app-server-protocol/src/protocol/v2.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3310,6 +3310,7 @@ pub struct SkillSummary {
33103310
pub short_description: Option<String>,
33113311
pub interface: Option<SkillInterface>,
33123312
pub path: PathBuf,
3313+
pub enabled: bool,
33133314
}
33143315

33153316
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
@@ -3348,7 +3349,12 @@ pub enum PluginSource {
33483349
#[serde(rename_all = "camelCase")]
33493350
#[ts(export_to = "v2/")]
33503351
pub struct SkillsConfigWriteParams {
3351-
pub path: PathBuf,
3352+
/// Path-based selector.
3353+
#[ts(optional = nullable)]
3354+
pub path: Option<AbsolutePathBuf>,
3355+
/// Name-based selector.
3356+
#[ts(optional = nullable)]
3357+
pub name: Option<String>,
33523358
pub enabled: bool,
33533359
}
33543360

codex-rs/app-server/README.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,10 @@ Example with notification opt-out:
164164
- `collaborationMode/list` — list available collaboration mode presets (experimental, no pagination). This response omits built-in developer instructions; clients should either pass `settings.developer_instructions: null` when setting a mode to use Codex's built-in instructions, or provide their own instructions explicitly.
165165
- `skills/list` — list skills for one or more `cwd` values (optional `forceReload`).
166166
- `plugin/list` — list discovered plugin marketplaces and plugin state, including effective marketplace install/auth policy metadata and best-effort `featuredPluginIds` for the official curated marketplace. `interface.category` uses the marketplace category when present; otherwise it falls back to the plugin manifest category. Pass `forceRemoteSync: true` to refresh curated plugin state before listing (**under development; do not call from production clients yet**).
167-
- `plugin/read` — read one plugin by `marketplacePath` plus `pluginName`, returning marketplace info, a list-style `summary`, manifest descriptions/interface metadata, and bundled skills/apps/MCP server names. Plugin app summaries also include `needsAuth` when the server can determine connector accessibility (**under development; do not call from production clients yet**).
167+
- `plugin/read` — read one plugin by `marketplacePath` plus `pluginName`, returning marketplace info, a list-style `summary`, manifest descriptions/interface metadata, and bundled skills/apps/MCP server names. Returned plugin skills include their current `enabled` state after local config filtering. Plugin app summaries also include `needsAuth` when the server can determine connector accessibility (**under development; do not call from production clients yet**).
168168
- `skills/changed` — notification emitted when watched local skill files change.
169169
- `app/list` — list available apps.
170-
- `skills/config/write` — write user-level skill config by path.
170+
- `skills/config/write` — write user-level skill config by name or absolute path.
171171
- `plugin/install` — install a plugin from a discovered marketplace entry, rejecting marketplace entries marked unavailable for install, install MCPs if any, and return the effective plugin auth policy plus any apps that still need auth (**under development; do not call from production clients yet**).
172172
- `plugin/uninstall` — uninstall a plugin by id by removing its cached files and clearing its user-level config entry (**under development; do not call from production clients yet**).
173173
- `mcpServer/oauth/login` — start an OAuth login for a configured MCP server; returns an `authorization_url` and later emits `mcpServer/oauthLogin/completed` once the browser flow finishes.
@@ -1141,14 +1141,29 @@ The server also emits `skills/changed` notifications when watched local skill fi
11411141
}
11421142
```
11431143

1144-
To enable or disable a skill by path:
1144+
To enable or disable a skill by absolute path:
11451145

11461146
```json
11471147
{
11481148
"method": "skills/config/write",
11491149
"id": 26,
11501150
"params": {
1151-
"path": "/Users/me/.codex/skills/skill-creator/SKILL.md",
1151+
"path": "/Users/alice/.codex/skills/skill-creator/SKILL.md",
1152+
"name": null,
1153+
"enabled": false
1154+
}
1155+
}
1156+
```
1157+
1158+
To enable or disable a skill by name:
1159+
1160+
```json
1161+
{
1162+
"method": "skills/config/write",
1163+
"id": 27,
1164+
"params": {
1165+
"path": null,
1166+
"name": "github:yeet",
11521167
"enabled": false
11531168
}
11541169
}

codex-rs/app-server/src/codex_message_processor.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5670,7 +5670,7 @@ impl CodexMessageProcessor {
56705670
interface: outcome.plugin.interface.map(plugin_interface_to_info),
56715671
},
56725672
description: outcome.plugin.description,
5673-
skills: plugin_skills_to_info(&visible_skills),
5673+
skills: plugin_skills_to_info(&visible_skills, &outcome.plugin.disabled_skill_paths),
56745674
apps: app_summaries,
56755675
mcp_servers: outcome.plugin.mcp_server_names,
56765676
};
@@ -5685,15 +5685,38 @@ impl CodexMessageProcessor {
56855685
request_id: ConnectionRequestId,
56865686
params: SkillsConfigWriteParams,
56875687
) {
5688-
let SkillsConfigWriteParams { path, enabled } = params;
5689-
let edits = vec![ConfigEdit::SetSkillConfig { path, enabled }];
5688+
let SkillsConfigWriteParams {
5689+
path,
5690+
name,
5691+
enabled,
5692+
} = params;
5693+
let edit = match (path, name) {
5694+
(Some(path), None) => ConfigEdit::SetSkillConfig {
5695+
path: path.into_path_buf(),
5696+
enabled,
5697+
},
5698+
(None, Some(name)) if !name.trim().is_empty() => {
5699+
ConfigEdit::SetSkillConfigByName { name, enabled }
5700+
}
5701+
_ => {
5702+
let error = JSONRPCErrorError {
5703+
code: INVALID_PARAMS_ERROR_CODE,
5704+
message: "skills/config/write requires exactly one of path or name".to_string(),
5705+
data: None,
5706+
};
5707+
self.outgoing.send_error(request_id, error).await;
5708+
return;
5709+
}
5710+
};
5711+
let edits = vec![edit];
56905712
let result = ConfigEditsBuilder::new(&self.config.codex_home)
56915713
.with_edits(edits)
56925714
.apply()
56935715
.await;
56945716

56955717
match result {
56965718
Ok(()) => {
5719+
self.thread_manager.plugins_manager().clear_cache();
56975720
self.thread_manager.skills_manager().clear_cache();
56985721
self.outgoing
56995722
.send_response(
@@ -7634,7 +7657,10 @@ fn skills_to_info(
76347657
.collect()
76357658
}
76367659

7637-
fn plugin_skills_to_info(skills: &[codex_core::skills::SkillMetadata]) -> Vec<SkillSummary> {
7660+
fn plugin_skills_to_info(
7661+
skills: &[codex_core::skills::SkillMetadata],
7662+
disabled_skill_paths: &std::collections::HashSet<PathBuf>,
7663+
) -> Vec<SkillSummary> {
76387664
skills
76397665
.iter()
76407666
.map(|skill| SkillSummary {
@@ -7652,6 +7678,7 @@ fn plugin_skills_to_info(skills: &[codex_core::skills::SkillMetadata]) -> Vec<Sk
76527678
}
76537679
}),
76547680
path: skill.path_to_skills_md.clone(),
7681+
enabled: !disabled_skill_paths.contains(&skill.path_to_skills_md),
76557682
})
76567683
.collect()
76577684
}

0 commit comments

Comments
 (0)