Skip to content

Instantly share code, notes, and snippets.

@Maxiviper117
Last active December 15, 2025 12:16
Show Gist options
  • Select an option

  • Save Maxiviper117/7372b1833fded0a1347e22edd48c475e to your computer and use it in GitHub Desktop.

Select an option

Save Maxiviper117/7372b1833fded0a1347e22edd48c475e to your computer and use it in GitHub Desktop.
Use Skills in VSCode Copilot.
// list-codex-skills.js - List all discovered Codex skills with metadata
const fs = require('fs');
const path = require('path');
const os = require('os');
// Only look for skills in the terminal working directory's `.codex/skills`
// (i.e., process.cwd()). Do not consult env vars or user home.
const skillsDir = path.join(process.cwd(), '.codex', 'skills');
function extractMetadata(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
// Support both LF and CRLF line endings.
const yamlMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
if (!yamlMatch) return null;
const lines = yamlMatch[1].split(/\r?\n/);
let name = 'Unknown';
let description = 'No description';
lines.forEach(line => {
if (line.startsWith('name:')) name = line.slice(5).trim().replace(/^['"]|['"]$/g, '');
if (line.startsWith('description:')) description = line.slice(12).trim().replace(/^['"]|['"]$/g, '');
});
return { name, description, file: filePath };
}
function findSkills(dir) {
let skills = [];
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const fullPath = path.join(dir, item.name);
if (item.isDirectory()) {
skills = skills.concat(findSkills(fullPath));
} else if (item.name === 'SKILL.md') {
const meta = extractMetadata(fullPath);
if (meta) skills.push(meta);
}
}
return skills;
}
(function main() {
// Simple CLI: support --search / -s to filter skills using keyword and fuzzy matching
const argv = process.argv.slice(2);
let searchTerm = null;
let maxResults = null;
for (let i = 0; i < argv.length; i++) {
const a = argv[i];
if (a === '--help' || a === '-h') {
console.log('Usage: node list-codex-skills.js [--search "term"] [--max N]');
console.log('\nIf --search is provided, the script prints matching skills using case-insensitive substring and a simple fuzzy score.');
console.log('Use --max/-m to limit the number of search results shown.');
return;
}
if (a === '--search' || a === '-s') {
searchTerm = argv[i+1] || '';
i++; // skip value
continue;
}
if (a.startsWith('--search=')) {
searchTerm = a.split('=')[1];
continue;
}
if (a.startsWith('-s=')) {
searchTerm = a.split('=')[1];
continue;
}
if (a === '--max' || a === '-m') {
const val = argv[i+1];
if (val !== undefined) {
const parsed = parseInt(val, 10);
if (!Number.isNaN(parsed) && parsed > 0) maxResults = parsed;
}
i++; // skip value
continue;
}
if (a.startsWith('--max=')) {
const parsed = parseInt(a.split('=')[1], 10);
if (!Number.isNaN(parsed) && parsed > 0) maxResults = parsed;
continue;
}
if (a.startsWith('-m=')) {
const parsed = parseInt(a.split('=')[1], 10);
if (!Number.isNaN(parsed) && parsed > 0) maxResults = parsed;
continue;
}
}
if (!fs.existsSync(skillsDir)) {
console.log('No skills directory found at: ' + skillsDir);
console.log('Create `.codex/skills` in your current working directory and add SKILL.md files.');
return;
}
const skills = findSkills(skillsDir);
if (skills.length === 0) {
console.log('No skills found.');
return;
}
// Helper: normalize strings
function norm(str) {
return String(str || '').toLowerCase();
}
// Levenshtein distance (small, simple implementation)
function levenshtein(a, b) {
a = String(a || ''); b = String(b || '');
const m = a.length, n = b.length;
if (m === 0) return n;
if (n === 0) return m;
const dp = Array.from({length: m+1}, () => new Array(n+1));
for (let i = 0; i <= m; i++) dp[i][0] = i;
for (let j = 0; j <= n; j++) dp[0][j] = j;
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
const cost = a[i-1] === b[j-1] ? 0 : 1;
dp[i][j] = Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + cost);
}
}
return dp[m][n];
}
function scoreMatch(skill, term) {
term = norm(term);
if (!term) return 1.0;
const name = norm(skill.name);
const desc = norm(skill.description);
const file = norm(skill.file);
// Exact substring checks get a high base score
if (name.includes(term)) return 1.0;
if (desc.includes(term)) return 0.9;
if (file.includes(term)) return 0.7;
// Token presence: all tokens present => decent score
const tokens = term.split(/\s+/).filter(Boolean);
let tokenMatches = 0;
tokens.forEach(t => {
if (name.includes(t) || desc.includes(t) || file.includes(t)) tokenMatches++;
});
if (tokenMatches === tokens.length && tokens.length > 0) return 0.6 + (tokens.length * 0.01);
// Fuzzy comparison: use smallest normalized levenshtein distance across fields
const candidates = [name, desc, file].filter(Boolean);
let best = Infinity;
for (const c of candidates) {
// compare term against c and against each word in c
best = Math.min(best, levenshtein(term, c));
c.split(/\W+/).forEach(w => { if (w) best = Math.min(best, levenshtein(term, w)); });
}
// Normalize by length: smaller distance relative to term length is better
const normDist = best / Math.max(1, term.length);
// Map to score in (0,0.5]
const fuzzyScore = Math.max(0, 0.5 - (normDist * 0.5));
return fuzzyScore;
}
if (searchTerm) {
let matches = skills.map(s => ({skill: s, score: scoreMatch(s, searchTerm)}))
.filter(x => x.score > 0.05) // threshold to avoid noise
.sort((a,b) => b.score - a.score);
if (maxResults && maxResults > 0) {
matches = matches.slice(0, maxResults);
}
if (matches.length === 0) {
console.log(`No matching skills found for: "${searchTerm}"`);
return;
}
console.log(`## Matching Skills for "${searchTerm}"\n`);
matches.forEach(m => {
const s = m.skill;
console.log(`- ${s.name}: ${s.description} (file: ${s.file}) [score=${m.score.toFixed(3)}]`);
});
return;
}
console.log('## Available Skills\n');
skills.forEach(s => {
console.log(`- ${s.name}: ${s.description} (file: ${s.file})`);
});
})();
description agent
Help me create a new Codex-style skill (with or without CLI-style scripts)
agent

Create a New Codex Skill

You are an expert at building reusable, high-quality skills for OpenAI's experimental Codex CLI skills system.

Skills are stored in ~/.codex/skills/ (or ./.codex/skills/ in project contexts).
Each skill is a folder containing:

  • A required SKILL.md file (with YAML frontmatter and detailed Markdown instructions)
  • Optional supporting files: scripts, templates, data files, etc.

Some skills are purely instructional (no scripts). Others include executable scripts that act as tools.

Your Task

When I request a new skill, follow these steps:

  1. Propose a clear, concise skill name (folder name in kebab-case, display name in title case)
  2. Decide whether a script is needed:
    • Yes → if the task involves external data, computation, file processing, API calls, etc.
    • No → if it's guidelines, templates, best practices, or prompt engineering
  3. Output the full folder structure and complete file contents
  4. Ensure the skill is self-contained, reusable, and easy to invoke

SKILL.md Template (Always Use This Exact Structure)

---
name: Display Name of the Skill
description: One-sentence summary of purpose and when to use it (under 500 chars, no newlines).
---
# Full Skill Title

[Detailed explanation and context]

## How to Use
[Clear step-by-step instructions, especially how to run any script]

## Examples
[1–3 concrete usage examples with commands]

## Notes (optional)
[Dependencies, limitations, tips]

Strict Rules for Scripts (When Included)

All scripts must be designed as proper CLI tools following these conventions:

  • Accept input via command-line arguments (use process.argv in Node.js, sys.argv in Python, $@ in Bash)
  • Never prompt interactively — all input must come from args or stdin
  • Print structured output (preferably JSON on stdout) for easy parsing
  • Print errors to stderr and exit with non-zero code on failure
  • Include a clear usage message if args are missing or invalid
  • Be idempotent and stateless where possible
  • Use shebangs (e.g., #!/usr/bin/env node or #!/usr/bin/env python3) and be executable-friendly
  • Keep dependencies minimal (use only widely available runtimes: Node.js, Python 3, Bash)

Example (Node.js):

#!/usr/bin/env node
// Always include usage check
if (process.argv.length < 3) {
  console.error("Usage: node script.js <argument>");
  process.exit(1);
}
// Output JSON on success
console.log(JSON.stringify(result, null, 2));

In SKILL.md:

  • Clearly document exact command syntax
  • Provide example commands
  • Treat the script as a black box — do not explain internal code

Example Requests

  • "Create a skill to fetch and summarize a webpage from URL"
  • "Skill for generating conventional commit messages from git diff"
  • "Skill for converting Markdown to clean HTML"
  • "Pure instruction skill for writing better documentation"

Wait for my specific skill idea and build it following these rules perfectly — especially ensuring any script is a well-behaved CLI tool.

**Do not read any existing skills in the system for reference; create everything from scratch based on the instructions above and my requests.

description agent
Discover and use my custom Codex skills via CLI tool — execute scripts only, never read them
agent

Discover Codex Skills

You have access to a collection of reusable custom skills stored in ./.codex/skills/. These follow the same experimental format as OpenAI's Codex CLI skills.

Each skill is a folder containing:

  • A required SKILL.md file (with name, short description, and detailed usage instructions)
  • Optional supporting resources, such as scripts (e.g., .js, .py, .sh), templates, or data files

Important: The list of available skills can change over time.

To get the up-to-date list of all discovered skills (names, descriptions, and file paths), run this command:

node ./.codex/list-codex-skills.js

Searching for skills

The list-codex-skills.js script now supports keyword and fuzzy searching. Use the --search (or -s) option to find relevant skills by name, description, or file path. The search performs case-insensitive substring matches first and falls back to a simple fuzzy match (Levenshtein-based) when needed. You can also cap the number of results with --max (or -m).

Examples:

node ./.codex/list-codex-skills.js --search "weather"
node ./.codex/list-codex-skills.js -s "refactor templates"
node ./.codex/list-codex-skills.js --search="image resize" --max 5

Notes:

  • Substring matches are scored highest (exact name match > description > file path).

  • If no exact substring match exists, the script computes a fuzzy score and returns the best matches above a small threshold.

  • Use --max / -m to adjust how many matches are shown when searching. Increase it if you suspect useful matches are being clipped; lower it if results are noisy.

  • Use --help or -h for a short usage message.

  • If a search returns no matches or otherwise does not provide sufficient/relevant results, first try adjusting --max to broaden or narrow results. If that still isn’t helpful, fall back to listing all skills by running the script without --search (i.e., node ./.codex/list-codex-skills.js). This ensures the agent can still discover available skills when fuzzy search doesn't find a close match.

Strict Instructions for You (the Agent)

: Always run skills using the runSubagent tool to ensure isolated agent processing.

  1. At the start of any session where skills might be relevant (e.g., user asks about weather, refactoring, data processing, tools, etc.), first run:

    node ./.codex/list-codex-skills.js

    This outputs the current list of available skills.

  2. Use that output to determine which skill (if any) applies to the user's request.

  3. If a skill matches:

    • Announce: "Applying skill: "
    • Read only the SKILL.md file at the provided path (you have file-reading capability)
    • Follow the instructions in SKILL.md exactly
  4. Critical Rule: Never read or inspect script files directly
    Do not open or display the contents of any script (e.g., get-weather.js, helper.py, etc.).
    This wastes context and is unnecessary — the usage instructions are already in SKILL.md.

  5. Only execute scripts when explicitly instructed in the SKILL.md

    • Run them exactly as described (e.g., node ./.codex/skills/weather-fetcher/get-weather.js "Berlin")
    • Trust that the script works as documented in the skill
    • Parse and present the output appropriately

Example Flow

User: "What's the weather in Tokyo?"

You:

  • Run node ./.codex/list-codex-skills.js
  • See "Weather Fetcher" skill
  • Read ./.codex/skills/weather-fetcher/SKILL.md → it says to run node get-weather.js "Tokyo"
  • Do NOT read get-weather.js itself
  • Execute: node ./.codex/skills/weather-fetcher/get-weather.js "Tokyo"
  • Parse the JSON output and present a clean, user-friendly summary

Always discover skills dynamically using the CLI tool.
Never assume a fixed list.
Never waste tokens reading script source code — rely solely on SKILL.md for guidance.

This keeps context efficient and behavior consistent with best practices.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment