# How Impeccable's Skill Prefixing Uses Regex Pattern Matching to Rename Commands

> Discover Impeccable skill prefixing: learn how regex pattern matching renames commands like /audit to /i-audit safely using lookahead and case-insensitive patterns.

- Repository: [Paul Bakaus/impeccable](https://github.com/pbakaus/impeccable)
- Tags: deep-dive
- Published: 2026-03-09

---

**Impeccable prefixes skill references by applying two targeted regular expressions—one with a lookahead assertion for command slashes and another case-insensitive pattern for prose references—to safely rename invocations like `/audit` to `/i-audit` without breaking partial matches.**

Impeccable's build system optionally adds prefixes (such as `i-`) to every user-invokable skill name, enabling prefixed and un-prefixed bundles to coexist without collision. This Impeccable skill prefixing regex pattern matching logic resides primarily in [`scripts/lib/utils.js`](https://github.com/pbakaus/impeccable/blob/main/scripts/lib/utils.js) and is executed by each provider-specific transformer. The implementation relies on precise regular expressions to distinguish between command-style invocations and natural-language references while avoiding accidental partial replacements.

## The Core Algorithm in [`scripts/lib/utils.js`](https://github.com/pbakaus/impeccable/blob/main/scripts/lib/utils.js)

The `prefixSkillReferences` function exported from [`scripts/lib/utils.js`](https://github.com/pbakaus/impeccable/blob/main/scripts/lib/utils.js) implements the regex-based replacement strategy. It accepts the skill content, a prefix string, and an array of skill names, then returns the transformed content with all references updated.

```javascript
export function prefixSkillReferences(content, prefix, skillNames) {
  if (!prefix || !skillNames || skillNames.length === 0) return content;

  let result = content;
  // Sort longest names first → prevents "teach-impeccable" being split inside "teach"
  const sorted = [...skillNames].sort((a, b) => b.length - a.length);

  for (const name of sorted) {
    const prefixed = `${prefix}${name}`;

    // ① Replace "/skillname" command invocations
    result = result.replace(
      new RegExp(`\\/(?=${escapeRegex(name)}(?:[^a-zA-Z0-9_-]|$))`, 'g'),
      `/${prefix}`
    );

    // ② Replace natural-language references "the skillname skill"
    result = result.replace(
      new RegExp(`the ${escapeRegex(name)} skill`, 'gi'),
      `the ${prefixed} skill`
    );
  }

  return result;
}

```

### Sorting Skills by Length to Prevent Partial Matches

Before applying any regex, the function sorts the skill names array in descending order by length using `[...skillNames].sort((a, b) => b.length - a.length)`. This ensures that longer skill names containing shorter substrings are processed first. For example, `teach-impeccable` is handled before `teach`, preventing the shorter pattern from incorrectly matching inside the longer name.

### Regex Pattern 1: Command-Style References with Lookahead

The first regex targets command invocations using a pattern with a positive lookahead: `\\/(?=${escapeRegex(name)}(?:[^a-zA-Z0-9_-]|$))`.

- `\\/` matches the literal forward slash starting a command.
- `(?=...)` is a **positive lookahead** that checks the slash is followed by the exact skill name (`escapeRegex(name)`) and then either a non-identifier character or the end of the string (`(?:[^a-zA-Z0-9_-]|$)`).
- Only the slash itself is replaced with `/${prefix}`, transforming `/audit` into `/i-audit` while leaving `/audit-extra` untouched because the lookahead fails on the hyphen.

### Regex Pattern 2: Natural-Language References

The second pattern handles prose references: `the ${escapeRegex(name)} skill` with the `gi` flags for **global, case-insensitive** matching. This transforms phrases like "the audit skill" into "the i-audit skill" throughout documentation and instruction blocks, ensuring consistent naming in natural language contexts.

## Integration Across Provider Transformers

Every provider-specific transformer—including Cursor, Claude Code, Gemini, Codex, Agents, and Kiro—invokes `prefixSkillReferences` after expanding placeholders. In [`scripts/lib/transformers/cursor.js`](https://github.com/pbakaus/impeccable/blob/main/scripts/lib/transformers/cursor.js) (lines 38-41), the implementation follows this pattern:

```javascript
let skillBody = replacePlaceholders(skill.body, 'cursor', commandNames);
if (prefix) skillBody = prefixSkillReferences(skillBody, prefix, allSkillNames);

```

The same invocation appears in [`transformers/gemini.js`](https://github.com/pbakaus/impeccable/blob/main/transformers/gemini.js), [`transformers/claude-code.js`](https://github.com/pbakaus/impeccable/blob/main/transformers/claude-code.js), [`transformers/codex.js`](https://github.com/pbakaus/impeccable/blob/main/transformers/codex.js), [`transformers/agents.js`](https://github.com/pbakaus/impeccable/blob/main/transformers/agents.js), and [`transformers/kiro.js`](https://github.com/pbakaus/impeccable/blob/main/transformers/kiro.js), ensuring consistent prefixing across all output formats.

## Build-Time Orchestration and Output

The [`scripts/build.js`](https://github.com/pbakaus/impeccable/blob/main/scripts/build.js) file orchestrates the prefixed bundle generation by passing `prefixOptions` to each transformer:

```javascript
const prefixOptions = { prefix: 'i-', outputSuffix: '-prefixed' };
transformCursor(skills, DIST_DIR, patterns, prefixOptions);
// ... other transformers
assembleUniversal(DIST_DIR, '-prefixed');

```

When `prefixOptions.prefix` is non-empty, the regex transformations generate files like [`dist/cursor-prefixed/.cursor/skills/i-audit/SKILL.md`](https://github.com/pbakaus/impeccable/blob/main/dist/cursor-prefixed/.cursor/skills/i-audit/SKILL.md), containing both prefixed command names (`/i-audit`) and natural-language mentions ("the i-audit skill").

## Summary

- Impeccable's skill prefixing relies on `prefixSkillReferences` in [`scripts/lib/utils.js`](https://github.com/pbakaus/impeccable/blob/main/scripts/lib/utils.js) to inject prefixes like `i-` into skill references.
- Two regex patterns handle distinct contexts: a lookahead-based pattern for command slashes and a case-insensitive pattern for prose references.
- Skill names are sorted by length descending to prevent shorter names from matching inside longer ones.
- Provider transformers in `scripts/lib/transformers/` apply this logic uniformly across Cursor, Claude Code, Gemini, Codex, Agents, and Kiro outputs.
- The `escapeRegex` utility sanitizes skill names to prevent regex meta-character injection.

## Frequently Asked Questions

### What regex pattern does Impeccable use to detect command invocations?

Impeccable uses the pattern `\\/(?=${escapeRegex(name)}(?:[^a-zA-Z0-9_-]|$))` to detect command invocations. This regex matches a literal forward slash only when followed by the exact skill name and a non-identifier character or end of string, ensuring precise boundary detection without consuming the skill name itself.

### Why does Impeccable sort skill names by length before applying regex replacements?

Impeccable sorts skill names by length in descending order (`b.length - a.length`) to prevent partial matches. This guarantees that longer skill names containing shorter substrings—such as `teach-impeccable` containing `teach`—are processed first, avoiding incorrect replacements inside compound names.

### How does the escapeRegex function prevent injection attacks in skill names?

The `escapeRegex` function escapes regex meta-characters that could appear in skill names, such as dots, brackets, or quantifiers. This sanitization ensures that user-defined skill names are treated as literal strings within the regex patterns, preventing unintended pattern matching behavior or ReDoS vulnerabilities.

### Which files in the Impeccable repository handle the prefixing logic?

The core logic resides in [`scripts/lib/utils.js`](https://github.com/pbakaus/impeccable/blob/main/scripts/lib/utils.js) within the `prefixSkillReferences` function. This utility is called by each provider transformer located in `scripts/lib/transformers/` (including [`cursor.js`](https://github.com/pbakaus/impeccable/blob/main/cursor.js), [`claude-code.js`](https://github.com/pbakaus/impeccable/blob/main/claude-code.js), [`gemini.js`](https://github.com/pbakaus/impeccable/blob/main/gemini.js), [`codex.js`](https://github.com/pbakaus/impeccable/blob/main/codex.js), [`agents.js`](https://github.com/pbakaus/impeccable/blob/main/agents.js), and [`kiro.js`](https://github.com/pbakaus/impeccable/blob/main/kiro.js)). The build orchestration in [`scripts/build.js`](https://github.com/pbakaus/impeccable/blob/main/scripts/build.js) initiates the prefixed build process, while [`public/app.js`](https://github.com/pbakaus/impeccable/blob/main/public/app.js) provides the UI toggle for downloading prefixed bundles.