#539·skills

skill-creator: init_skill.py leaves a partial skill directory behind on failure, blocking every retry

Author: dajiaohuangCreated Sep 10, 2026Updated Sep 10, 2026

Summary

init_skill.py creates the skill directory first, then fills it in. Every failure path after that first mkdir returns without removing the directory. Because the script refuses to reuse an existing directory, the leftover makes every later retry of the same skill name fail until the user deletes the directory by hand.

Reported against main at 49f948faa9258a0c61caceaf225e179651397431 (blob f90703eca8159a21a9684ed1df974c702d92f814).

Reproduction

A rejected --interface value is the shortest trigger, but any post-mkdir failure behaves the same way.

$ python skills/.system/skill-creator/scripts/init_skill.py demo-skill \
    --path /tmp/initskill --interface bogus_key=1
Initializing skill: demo-skill
   Location: /tmp/initskill
   Resources: none (create as needed)

[OK] Created skill directory: /tmp/initskill/demo-skill
[OK] Created SKILL.md
[ERROR] Unknown interface field 'bogus_key'. Allowed: brand_color, default_prompt, display_name, icon_large, icon_small, short_description
$ echo $?
1

The command failed, but the directory survives:

$ find /tmp/initskill -mindepth 1
/tmp/initskill/demo-skill
/tmp/initskill/demo-skill/SKILL.md

Now the user fixes the argument and retries — the tool has already been told to fail once with the same name:

$ python skills/.system/skill-creator/scripts/init_skill.py demo-skill --path /tmp/initskill
Initializing skill: demo-skill
   Location: /tmp/initskill
   Resources: none (create as needed)

[ERROR] Skill directory already exists: /tmp/initskill/demo-skill
$ echo $?
1

There is no flag that clears or overwrites the directory, so the only way forward is a manual rm -rf outside the tool.

Expected

A failed init_skill.py invocation leaves nothing behind, and the same command can be corrected and re-run.

Actual

The failed invocation leaves a partial skill directory, and the corrected re-run is rejected as "already exists".

Cause

init_skill.py at the reported revision:

  • 274-277 refuses when the directory exists and returns None.
  • 281 creates the directory.
  • 292-297, 299-306, and 308-314 each return None on failure without removing the directory.

So the guard at 274-277 is what turns an already-handled error into a stuck state: the first failure is reported correctly, but it poisons the name for every subsequent attempt.

The same structure is present in the skill-creator sample shipped in openai/codex (codex-rs/skills/src/assets/samples/skill-creator/scripts/init_skill.py), which also has no cleanup or rollback call — so this is not only a stale-copy artifact of the deprecated repository.

Suggested narrow fix

Remove the partially created directory on each failure path. A pre-existing directory must still be refused and never deleted.

 import argparse
 import re
+import shutil
 import sys
 from pathlib import Path

+def remove_partial_skill_dir(skill_dir):
+    """Remove a partially created skill directory so the command can be retried."""
+    try:
+        shutil.rmtree(skill_dir)
+        print(f"[INFO] Removed incomplete skill directory: {skill_dir}")
+    except OSError as e:
+        print(f"[WARNING] Could not remove incomplete directory {skill_dir}: {e}")
+
+
 def init_skill(skill_name, path, resources, include_examples, interface_overrides):

then a remove_partial_skill_dir(skill_dir) call before each of the four return None statements that follow the mkdir at 281.

Tested patch

Implemented and tested on a fork, since this repository does not accept pull requests (see below):

The patch adds remove_partial_skill_dir() and calls it on the four post-mkdir failure paths, and adds skills/.system/skill-creator/tests/test_init_skill_cleanup.py:

$ python -m unittest discover -s skills/.system/skill-creator/tests -v
test_control_existing_directory_is_still_refused ... ok
test_control_successful_init_creates_expected_tree ... ok
test_invalid_interface_key_leaves_no_directory ... ok
test_out_of_range_short_description_leaves_no_directory ... ok
test_retry_succeeds_after_rejected_interface_key ... ok

Ran 5 tests in 0.665s
OK

Both init_skill.py and the test module pass python -m py_compile, and git diff --check is clean.

The two control cases matter for review:

  1. A successful init still produces SKILL.md, agents/openai.yaml, scripts/example.py, and references/api_reference.md.
  2. A pre-existing directory is still refused, and its contents are never deleted — cleanup only ever runs on a directory this invocation created.

Run against the unpatched script, the three non-control tests fail (the retry fails with 1 != 0 : ... Skill directory already exists), so the coverage is not vacuous.

Why this is an issue and not a pull request

Pull request creation is unavailable for this repository:

$ gh pr create --repo openai/skills --base main --head dajiaohuang:fix/init-skill-partial-dir-cleanup ...
pull request create failed: GraphQL: dajiaohuang does not have the correct permissions to execute `CreatePullRequest` (createPullRequest)

$ curl -X POST .../repos/openai/skills/pulls -d '{"head":"dajiaohuang:fix/...","base":"main"}'
{"message": "Not Found", "status": "404"}

GET /repos/openai/skills/pulls also returns 404, GraphQL reports pullRequests.totalCount: 0, and the repository navigation exposes Issues and Actions but no Pull requests tab. The patch is therefore offered as a fork commit above. If there is a preferred contribution path, I am happy to resubmit through it.

Note on repository status

README.md marks this repository deprecated in favour of openai/plugins. This report is filed here because the affected file is published from this repository and still installs as a system skill. If the maintained copy now lives elsewhere, the fix is the same and the fork commit above applies to the openai/codex sample as well.


Found by an automated repository audit of openai/skills at 49f948faa9258a0c61caceaf225e179651397431. The defect was reproduced by executing the commands shown above; no repository files were modified by the audit.