Skip to content

Commit f604507

Browse files
gabrimaticdedrisian-oaietraut-openai
authored
fix(core): load custom prompts from symlinked Markdown files (openai#3643)
- Discover prompts via fs::metadata to follow symlinks - Add Unix-only symlink test in custom_prompts.rs - Update docs/prompts.md to mention symlinks Fixes openai#3637 --------- Signed-off-by: Soroush Yousefpour <[email protected]> Co-authored-by: dedrisian-oai <[email protected]> Co-authored-by: Eric Traut <[email protected]>
1 parent 66c9d5f commit f604507

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

codex-rs/core/src/custom_prompts.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,11 @@ pub async fn discover_prompts_in_excluding(
3232

3333
while let Ok(Some(entry)) = entries.next_entry().await {
3434
let path = entry.path();
35-
let is_file = entry
36-
.file_type()
35+
let is_file_like = fs::metadata(&path)
3736
.await
38-
.map(|ft| ft.is_file())
37+
.map(|m| m.is_file())
3938
.unwrap_or(false);
40-
if !is_file {
39+
if !is_file_like {
4140
continue;
4241
}
4342
// Only include Markdown files with a .md extension.
@@ -197,6 +196,25 @@ mod tests {
197196
assert_eq!(names, vec!["good"]);
198197
}
199198

199+
#[tokio::test]
200+
#[cfg(unix)]
201+
async fn discovers_symlinked_md_files() {
202+
let tmp = tempdir().expect("create TempDir");
203+
let dir = tmp.path();
204+
205+
// Create a real file
206+
fs::write(dir.join("real.md"), b"real content").unwrap();
207+
208+
// Create a symlink to the real file
209+
std::os::unix::fs::symlink(dir.join("real.md"), dir.join("link.md")).unwrap();
210+
211+
let found = discover_prompts_in(dir).await;
212+
let names: Vec<String> = found.into_iter().map(|e| e.name).collect();
213+
214+
// Both real and link should be discovered, sorted alphabetically
215+
assert_eq!(names, vec!["link", "real"]);
216+
}
217+
200218
#[tokio::test]
201219
async fn parses_frontmatter_and_strips_from_body() {
202220
let tmp = tempdir().expect("create TempDir");

docs/prompts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Custom prompts turn your repeatable instructions into reusable slash commands, s
55
### Where prompts live
66

77
- Location: store prompts in `$CODEX_HOME/prompts/` (defaults to `~/.codex/prompts/`). Set `CODEX_HOME` if you want to use a different folder.
8-
- File type: Codex only loads `.md` files. Non-Markdown files are ignored.
8+
- File type: Codex only loads `.md` files. Non-Markdown files are ignored. Both regular files and symlinks to Markdown files are supported.
99
- Naming: The filename (without `.md`) becomes the prompt name. A file called `review.md` registers the prompt `review`.
1010
- Refresh: Prompts are loaded when a session starts. Restart Codex (or start a new session) after adding or editing files.
1111
- Conflicts: Files whose names collide with built-in commands (like `init`) stay hidden in the slash popup, but you can still invoke them with `/prompts:<name>`.

0 commit comments

Comments
 (0)