Skip to content

refactor: rename slash commands tw-* → taskwing:* and MCP server → taskwing#24

Merged
josephgoksu merged 3 commits intomainfrom
refactor/rename-slash-commands-taskwing-colon
Mar 9, 2026
Merged

refactor: rename slash commands tw-* → taskwing:* and MCP server → taskwing#24
josephgoksu merged 3 commits intomainfrom
refactor/rename-slash-commands-taskwing-colon

Conversation

@josephgoksu
Copy link
Owner

@josephgoksu josephgoksu commented Mar 8, 2026

Summary

  • Rename all slash commands from tw-* to taskwing:* (e.g., /tw-next/taskwing:next)
  • Rename MCP server from taskwing-mcp to taskwing
  • No backward compatibility shims — old names are detected as legacy for cleanup
  • 24 files updated across Go source, tests, docs, and configs

Test plan

  • make build passes
  • 15/15 MCP healthcheck, drift detection, and repair plan tests pass
  • No remaining tw- references in source (only legacy detection code)
  • No remaining taskwing-mcp references in source (only legacy detection code)

Greptile Summary

This PR renames all slash commands from tw-*taskwing:* (Claude Code namespace format) and the MCP server from taskwing-mcptaskwing across 24 files. The renaming intent is sound — taskwing:ask is a cleaner, tool-namespaced UX than tw-ask. Documentation, runtime strings, test fixtures, and mcpcfg/naming.go are all updated correctly. However, internal/bootstrap/initializer.go — the single file responsible for actually writing command files to disk — contains three bugs that would cause silent or hard failures at install time:

  • OpenCode installs are completely broken: createOpenCodeCommands validates command names against ^[a-z0-9]+(-[a-z0-9]+)*$, but now passes cmd.SlashCmd (e.g., "taskwing:ask") which contains a colon. Every command fails validation on the first iteration; no OpenCode commands are ever written.
  • Claude Code command files have colons in their names: Files are written as taskwing/taskwing:ask.md instead of taskwing/ask.md. Colons are illegal in Windows filenames, and Claude Code would resolve this as /taskwing:taskwing:ask (double-namespaced) rather than the intended /taskwing:ask. The comment on line 377 correctly documents the right mapping (taskwing/ask.md → /taskwing:ask) — the implementation just doesn't match it.
  • Legacy tw-*.md cleanup is broken: managedSlashCommandBases() registers "tw-" + cmd.SlashCmd = "tw-taskwing:ask" as the legacy key, but actual legacy files on disk are named using cmd.BaseName (tw-ask.md). Since "tw-ask" is never in the managed set, old files are silently skipped and never pruned.

All three issues stem from the same root cause: using cmd.SlashCmd (the full taskwing:ask token) where cmd.BaseName (just ask) is needed for filesystem operations.

Confidence Score: 1/5

  • Not safe to merge — OpenCode installs will hard-error, Claude Code command files will have wrong names on all platforms and be completely broken on Windows, and legacy tw-* cleanup will silently fail for all upgrading users.
  • The documentation, string constants, hook messages, and mcpcfg naming changes are all correct. But the single most critical file — initializer.go, which actually writes slash command files to disk — has three distinct bugs in the new namespace logic, all caused by using cmd.SlashCmd (containing a colon) instead of cmd.BaseName in filesystem operations. The tests pass because they mirror the same buggy expected-filename logic, so the test suite gives false confidence. Real-world installs on every supported AI tool would be broken or produce incorrect command names.
  • internal/bootstrap/initializer.go requires targeted fixes in expectedSlashCommandFiles, managedSlashCommandBases, CreateSlashCommands (filename construction), and createOpenCodeCommands (validation + filename). The test file internal/bootstrap/mcp_healthcheck_test.go should also be updated once the filename logic is corrected.

Important Files Changed

Filename Overview
internal/bootstrap/initializer.go Core of the refactor — three critical/high bugs: files written with colon-containing names (taskwing:ask.md) breaking Claude Code namespacing and Windows compatibility; OpenCode validation regex rejects cmd.SlashCmd (contains colon), blocking all OpenCode installs; legacy tw-* cleanup logic uses cmd.SlashCmd instead of cmd.BaseName so old files are never removed.
internal/bootstrap/integration_health.go Health evaluation updated to scan taskwing/ namespace subdirectory for command files and detect legacy tw-* flat files; logic is consistent but depends on the correct filenames being written by initializer.go (which has bugs).
internal/bootstrap/mcp_healthcheck_test.go Tests correctly updated to use nsDir (namespace subdirectory) when writing test fixture files, and assertion strings updated to new MCP server name; the tests pass because they mirror the (buggy) expected-filename logic, not because the resulting filenames are correct.
internal/mcpcfg/naming.go Clean inversion of canonical/legacy names: CanonicalServerName changed from "taskwing-mcp" to "taskwing", IsLegacyServerName updated reciprocally; logic is correct and well-structured.
cmd/mcp_server.go MCP server Implementation.Name changed from "taskwing-mcp" to "taskwing" — straightforward, correct rename with no side effects.
cmd/slash_content.go All prompt content string constants updated — comment headers and inline command references changed from tw-* to taskwing:*; purely cosmetic/doc changes, no logic affected.
opencode.json MCP server key renamed correctly; however, the command array still contains a hardcoded absolute path to a developer-specific machine path — pre-existing issue but should be addressed.
cmd/slash.go Usage examples in the command description updated from tw-* to taskwing:* — no logic changes.
cmd/hook.go User-facing hook response messages updated from /tw-next to /taskwing:next — correct rename in all four call sites.
cmd/mcp_detect.go Comment strings updated to match new server name; actual detection logic delegates to mcpcfg.ContainsCanonicalServerName which is correctly updated in naming.go.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[taskwing bootstrap] --> B{AI Tool type?}
    B -->|Claude Code / Gemini TOML| C[CreateSlashCommands]
    B -->|OpenCode| D[createOpenCodeCommands]
    B -->|GitHub Copilot| E[createSingleFileInstructions]

    C --> F[mkdir .claude/commands/taskwing/]
    F --> G["Write taskwing/⚠️taskwing:ask.md\n(BUG: should be ask.md)"]
    G --> H[pruneStaleSlashCommands]
    H --> I["Scan root for tw-* files\n⚠️ BUG: 'tw-ask' not in managedBases\n→ legacy files NOT removed"]
    H --> J["Scan taskwing/ for stale files\n(expects taskwing:ask.md keys)"]

    D --> K["Validate cmd.SlashCmd\nagainst ^[a-z0-9]+(-[a-z0-9]+)*$\n⚠️ BUG: 'taskwing:ask' has colon\n→ validation FAILS, returns error"]

    E --> L[Write single instructions .md file]
    L --> M[Embed MCP config with 'taskwing' server name ✓]

    style G fill:#ff6b6b,color:#fff
    style I fill:#ff6b6b,color:#fff
    style K fill:#ff6b6b,color:#fff
    style M fill:#51cf66,color:#fff
Loading

Comments Outside Diff (12)

  1. internal/bootstrap/initializer.go, line 469-476 (link)

    Colon in filename will fail on macOS (HFS+/APFS)

    After this rename, cmd.BaseName is "taskwing:ask", "taskwing:next", etc. The code constructs fileName = cmd.BaseName + ".md""taskwing:ask.md" and passes it to os.WriteFile. On macOS (HFS+ / APFS), the colon : is a reserved path separator and is not permitted in filenames. The syscall will return EINVAL, silently breaking taskwing bootstrap for every Claude, Cursor, Codex, and Gemini user on macOS.

    For Claude Code's namespaced slash commands (e.g. /taskwing:next), the correct approach is a subdirectory, not a colon in the filename:

    • Create .claude/commands/taskwing/next.md → Claude Code exposes it as /taskwing:next

    The SlashCommand struct already has a separate SlashCmd field ("next", "ask", etc.) that should be used as the filename, while "taskwing" becomes the subdirectory name.

    Note: this same issue affects the Gemini TOML path (cmd.BaseName + ".toml" at the equivalent location).

  2. internal/bootstrap/initializer.go, line 662-666 (link)

    OpenCode bootstrap will always error — all commands fail name validation

    openCodeSkillNameRegex is `^[a-z0-9]+(-[a-z0-9]+)*## Summary

  • Rename all slash commands from tw-* to taskwing:* (e.g., /tw-next/taskwing:next)
  • Rename MCP server from taskwing-mcp to taskwing
  • No backward compatibility shims — old names are detected as legacy for cleanup
  • 24 files updated across Go source, tests, docs, and configs

Test plan

  • make build passes
  • 15/15 MCP healthcheck, drift detection, and repair plan tests pass
  • No remaining tw- references in source (only legacy detection code)
  • No remaining taskwing-mcp references in source (only legacy detection code)

Greptile Summary

This PR renames slash commands from tw-* to taskwing:* and the MCP server from taskwing-mcp to taskwing across 24 files. The intent is sound and most changes are executed cleanly — the MCP server rename, documentation, and string updates are consistent and correct.

However, the slash command rename introduces three critical runtime bugs in internal/bootstrap/initializer.go that will silently fail bootstrap for affected users:

  1. macOS filesystem failure: The code uses cmd.BaseName (now "taskwing:ask", "taskwing:next", etc.) directly as a filename. On macOS (HFS+/APFS), colons are reserved path separators and forbidden in filenames. os.WriteFile will return EINVAL for all Claude, Cursor, Codex, and Gemini users on macOS when running taskwing bootstrap.

  2. OpenCode validation failure: The OpenCode regex `^[a-z0-9]+(-[a-z0-9]+)*## Summary

  • Rename all slash commands from tw-* to taskwing:* (e.g., /tw-next/taskwing:next)
  • Rename MCP server from taskwing-mcp to taskwing
  • No backward compatibility shims — old names are detected as legacy for cleanup
  • 24 files updated across Go source, tests, docs, and configs

Test plan

  • make build passes
  • 15/15 MCP healthcheck, drift detection, and repair plan tests pass
  • No remaining tw- references in source (only legacy detection code)
  • No remaining taskwing-mcp references in source (only legacy detection code)

Greptile Summary

This PR renames all slash commands from tw-*taskwing:* (Claude Code namespace format) and the MCP server from taskwing-mcptaskwing across 24 files. The renaming intent is sound — taskwing:ask is a cleaner, tool-namespaced UX than tw-ask. Documentation, runtime strings, test fixtures, and mcpcfg/naming.go are all updated correctly. However, internal/bootstrap/initializer.go — the single file responsible for actually writing command files to disk — contains three bugs that would cause silent or hard failures at install time:

  • OpenCode installs are completely broken: createOpenCodeCommands validates command names against ^[a-z0-9]+(-[a-z0-9]+)*$, but now passes cmd.SlashCmd (e.g., "taskwing:ask") which contains a colon. Every command fails validation on the first iteration; no OpenCode commands are ever written.
  • Claude Code command files have colons in their names: Files are written as taskwing/taskwing:ask.md instead of taskwing/ask.md. Colons are illegal in Windows filenames, and Claude Code would resolve this as /taskwing:taskwing:ask (double-namespaced) rather than the intended /taskwing:ask. The comment on line 377 correctly documents the right mapping (taskwing/ask.md → /taskwing:ask) — the implementation just doesn't match it.
  • Legacy tw-*.md cleanup is broken: managedSlashCommandBases() registers "tw-" + cmd.SlashCmd = "tw-taskwing:ask" as the legacy key, but actual legacy files on disk are named using cmd.BaseName (tw-ask.md). Since "tw-ask" is never in the managed set, old files are silently skipped and never pruned.

All three issues stem from the same root cause: using cmd.SlashCmd (the full taskwing:ask token) where cmd.BaseName (just ask) is needed for filesystem operations.

Confidence Score: 1/5

  • Not safe to merge — OpenCode installs will hard-error, Claude Code command files will have wrong names on all platforms and be completely broken on Windows, and legacy tw-* cleanup will silently fail for all upgrading users.
  • The documentation, string constants, hook messages, and mcpcfg naming changes are all correct. But the single most critical file — initializer.go, which actually writes slash command files to disk — has three distinct bugs in the new namespace logic, all caused by using cmd.SlashCmd (containing a colon) instead of cmd.BaseName in filesystem operations. The tests pass because they mirror the same buggy expected-filename logic, so the test suite gives false confidence. Real-world installs on every supported AI tool would be broken or produce incorrect command names.
  • internal/bootstrap/initializer.go requires targeted fixes in expectedSlashCommandFiles, managedSlashCommandBases, CreateSlashCommands (filename construction), and createOpenCodeCommands (validation + filename). The test file internal/bootstrap/mcp_healthcheck_test.go should also be updated once the filename logic is corrected.

Important Files Changed

Filename Overview
internal/bootstrap/initializer.go Core of the refactor — three critical/high bugs: files written with colon-containing names (taskwing:ask.md) breaking Claude Code namespacing and Windows compatibility; OpenCode validation regex rejects cmd.SlashCmd (contains colon), blocking all OpenCode installs; legacy tw-* cleanup logic uses cmd.SlashCmd instead of cmd.BaseName so old files are never removed.
internal/bootstrap/integration_health.go Health evaluation updated to scan taskwing/ namespace subdirectory for command files and detect legacy tw-* flat files; logic is consistent but depends on the correct filenames being written by initializer.go (which has bugs).
internal/bootstrap/mcp_healthcheck_test.go Tests correctly updated to use nsDir (namespace subdirectory) when writing test fixture files, and assertion strings updated to new MCP server name; the tests pass because they mirror the (buggy) expected-filename logic, not because the resulting filenames are correct.
internal/mcpcfg/naming.go Clean inversion of canonical/legacy names: CanonicalServerName changed from "taskwing-mcp" to "taskwing", IsLegacyServerName updated reciprocally; logic is correct and well-structured.
cmd/mcp_server.go MCP server Implementation.Name changed from "taskwing-mcp" to "taskwing" — straightforward, correct rename with no side effects.
cmd/slash_content.go All prompt content string constants updated — comment headers and inline command references changed from tw-* to taskwing:*; purely cosmetic/doc changes, no logic affected.
opencode.json MCP server key renamed correctly; however, the command array still contains a hardcoded absolute path to a developer-specific machine path — pre-existing issue but should be addressed.
cmd/slash.go Usage examples in the command description updated from tw-* to taskwing:* — no logic changes.
cmd/hook.go User-facing hook response messages updated from /tw-next to /taskwing:next — correct rename in all four call sites.
cmd/mcp_detect.go Comment strings updated to match new server name; actual detection logic delegates to mcpcfg.ContainsCanonicalServerName which is correctly updated in naming.go.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[taskwing bootstrap] --> B{AI Tool type?}
    B -->|Claude Code / Gemini TOML| C[CreateSlashCommands]
    B -->|OpenCode| D[createOpenCodeCommands]
    B -->|GitHub Copilot| E[createSingleFileInstructions]

    C --> F[mkdir .claude/commands/taskwing/]
    F --> G["Write taskwing/⚠️taskwing:ask.md\n(BUG: should be ask.md)"]
    G --> H[pruneStaleSlashCommands]
    H --> I["Scan root for tw-* files\n⚠️ BUG: 'tw-ask' not in managedBases\n→ legacy files NOT removed"]
    H --> J["Scan taskwing/ for stale files\n(expects taskwing:ask.md keys)"]

    D --> K["Validate cmd.SlashCmd\nagainst ^[a-z0-9]+(-[a-z0-9]+)*$\n⚠️ BUG: 'taskwing:ask' has colon\n→ validation FAILS, returns error"]

    E --> L[Write single instructions .md file]
    L --> M[Embed MCP config with 'taskwing' server name ✓]

    style G fill:#ff6b6b,color:#fff
    style I fill:#ff6b6b,color:#fff
    style K fill:#ff6b6b,color:#fff
    style M fill:#51cf66,color:#fff
Loading

explicitly rejects colons. All 9 command names fail validation on the first iteration, making taskwing bootstrap --ai opencode completely broken.

  1. Migration cleanup broken: The managedSlashCommandBases() function only recognizes the new "taskwing:*" names. Old tw-* files will never be pruned, leaving orphaned files in users' .claude/commands/ and .cursor/rules/ directories after upgrade.

The MCP server rename in internal/mcpcfg/naming.go, cmd/mcp_server.go, and test fixtures is well-executed. All documentation and in-prompt references are consistently updated.

Confidence Score: 1/5

  • Not safe to merge — three runtime-breaking bugs will silently fail bootstrap for macOS users and all OpenCode users, plus broken migration cleanup.
  • The MCP server rename portion of this PR is clean and correct. However, the slash command rename produces BaseName values containing colons, which are then used directly as raw filenames in CreateSlashCommands and createOpenCodeCommands. On macOS (the primary dev platform given Homebrew in docs and /Users/josephgoksu in opencode.json), colons are forbidden filesystem characters — this is a hard EINVAL failure, not an edge case. For OpenCode, the validation regex explicitly rejects colons, guaranteeing failure on every command. Additionally, the migration cleanup function won't recognize old tw-* files, leaving orphaned files. These are not theoretical issues — they affect the core taskwing bootstrap flow for the majority of users (macOS + OpenCode users).
  • internal/bootstrap/initializer.go requires critical fixes: filename construction must use subdirectories for namespaced commands (Claude/Cursor/Codex/Gemini) and short names (OpenCode). Migration cleanup must recognize both old and new basenames.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[taskwing bootstrap --ai X] --> B{AI type?}
    B -- "claude / cursor / codex" --> C[CreateSlashCommands]
    B -- "opencode" --> D[createOpenCodeCommands]
    B -- "copilot" --> E[createSingleFileInstructions]
    B -- "gemini" --> F[CreateSlashCommands TOML]

    C --> G["fileName = cmd.BaseName + '.md'<br/>e.g. 'taskwing:ask.md'"]
    G --> H{"macOS HFS+/APFS?"}
    H -- "Yes" --> I["❌ os.WriteFile fails<br/>EINVAL: colon in filename"]
    H -- "No Linux" --> J["✅ File created<br/>but wrong path for<br/>Claude Code namespace"]

    D --> K["openCodeSkillNameRegex<br/>^[a-z0-9]+(-[a-z0-9]+)*$<br/>match 'taskwing:ask'?"]
    K -- "NO colon fails regex" --> L["❌ Error returned<br/>on EVERY command<br/>bootstrap always fails"]
    K -- "match" --> M["✅ File created"]

    F --> N["fileName = cmd.BaseName + '.toml'<br/>e.g. 'taskwing:ask.toml'"]
    N --> H

    E --> O["Single file: copilot-instructions.md<br/>cmd.BaseName used only in display text"]
    O --> P["✅ No filesystem colon issue"]

    C --> Q[pruneStaleSlashCommands]
    Q --> R{"base 'tw-ask' in<br/>managedBases?"}
    R -- "NO only 'taskwing:ask' present" --> S["🟡 Old tw-* files<br/>NOT pruned"]
Loading

. Every command in SlashCommands now has cmd.BaseName set to "taskwing:ask", "taskwing:next", etc. The colon character is explicitly rejected by this regex, so the if !openCodeSkillNameRegex.MatchString(cmd.BaseName) check will fail on the very first command and return an error every single time. taskwing bootstrap --ai opencode is now completely broken.

For OpenCode (flat directory, no namespace hierarchy), the correct fix is to use the short SlashCmd field ("ask", "next", etc.) as the filename, with a descriptive prefix if disambiguation is needed:

  1. internal/bootstrap/initializer.go, line 384-390 (link)

    Old tw-* files will not be pruned during migration

    managedSlashCommandBases() now returns a map with keys "taskwing:ask", "taskwing:next", etc. (the new BaseName values). When pruneStaleSlashCommands checks an existing tw-ask.md:

    base := strings.TrimSuffix("tw-ask.md", ".md")  // = "tw-ask"
    if _, known := managedBases[base]; !known {
        continue  // "tw-ask" is NOT in the new managedBases → skipped, not pruned
    }

    Users upgrading from the old naming will have orphaned tw-ask.md, tw-next.md, etc. left in their .claude/commands/ directory indefinitely, because the old names are no longer recognized as "managed by us." To handle the migration, managedSlashCommandBases() should include both the old and new base names:

  2. internal/bootstrap/initializer.go, line 277-284 (link)

    Misleading comment on SlashCommandNames()

    The updated comment says "without /taskwing: prefix", but the function iterates over cmd.SlashCmd (values like "ask", "next", "done"), which carry no prefix at all — neither the old /tw- form nor the new /taskwing: form. The comment should be updated to accurately describe what is returned:

  3. internal/bootstrap/initializer.go, line 713-714 (link)

    OpenCode command install broken — colon in cmd.SlashCmd fails regex

    cmd.SlashCmd is now "taskwing:ask", "taskwing:next", etc. — all containing a colon (:). The OpenCode validation regex `^[a-z0-9]+(-[a-z0-9]+)*## Summary

  • Rename all slash commands from tw-* to taskwing:* (e.g., /tw-next/taskwing:next)
  • Rename MCP server from taskwing-mcp to taskwing
  • No backward compatibility shims — old names are detected as legacy for cleanup
  • 24 files updated across Go source, tests, docs, and configs

Test plan

  • make build passes
  • 15/15 MCP healthcheck, drift detection, and repair plan tests pass
  • No remaining tw- references in source (only legacy detection code)
  • No remaining taskwing-mcp references in source (only legacy detection code)

Greptile Summary

This PR renames all slash commands from tw-*taskwing:* (Claude Code namespace format) and the MCP server from taskwing-mcptaskwing across 24 files. The renaming intent is sound — taskwing:ask is a cleaner, tool-namespaced UX than tw-ask. Documentation, runtime strings, test fixtures, and mcpcfg/naming.go are all updated correctly. However, internal/bootstrap/initializer.go — the single file responsible for actually writing command files to disk — contains three bugs that would cause silent or hard failures at install time:

  • OpenCode installs are completely broken: createOpenCodeCommands validates command names against ^[a-z0-9]+(-[a-z0-9]+)*$, but now passes cmd.SlashCmd (e.g., "taskwing:ask") which contains a colon. Every command fails validation on the first iteration; no OpenCode commands are ever written.
  • Claude Code command files have colons in their names: Files are written as taskwing/taskwing:ask.md instead of taskwing/ask.md. Colons are illegal in Windows filenames, and Claude Code would resolve this as /taskwing:taskwing:ask (double-namespaced) rather than the intended /taskwing:ask. The comment on line 377 correctly documents the right mapping (taskwing/ask.md → /taskwing:ask) — the implementation just doesn't match it.
  • Legacy tw-*.md cleanup is broken: managedSlashCommandBases() registers "tw-" + cmd.SlashCmd = "tw-taskwing:ask" as the legacy key, but actual legacy files on disk are named using cmd.BaseName (tw-ask.md). Since "tw-ask" is never in the managed set, old files are silently skipped and never pruned.

All three issues stem from the same root cause: using cmd.SlashCmd (the full taskwing:ask token) where cmd.BaseName (just ask) is needed for filesystem operations.

Confidence Score: 1/5

  • Not safe to merge — OpenCode installs will hard-error, Claude Code command files will have wrong names on all platforms and be completely broken on Windows, and legacy tw-* cleanup will silently fail for all upgrading users.
  • The documentation, string constants, hook messages, and mcpcfg naming changes are all correct. But the single most critical file — initializer.go, which actually writes slash command files to disk — has three distinct bugs in the new namespace logic, all caused by using cmd.SlashCmd (containing a colon) instead of cmd.BaseName in filesystem operations. The tests pass because they mirror the same buggy expected-filename logic, so the test suite gives false confidence. Real-world installs on every supported AI tool would be broken or produce incorrect command names.
  • internal/bootstrap/initializer.go requires targeted fixes in expectedSlashCommandFiles, managedSlashCommandBases, CreateSlashCommands (filename construction), and createOpenCodeCommands (validation + filename). The test file internal/bootstrap/mcp_healthcheck_test.go should also be updated once the filename logic is corrected.

Important Files Changed

Filename Overview
internal/bootstrap/initializer.go Core of the refactor — three critical/high bugs: files written with colon-containing names (taskwing:ask.md) breaking Claude Code namespacing and Windows compatibility; OpenCode validation regex rejects cmd.SlashCmd (contains colon), blocking all OpenCode installs; legacy tw-* cleanup logic uses cmd.SlashCmd instead of cmd.BaseName so old files are never removed.
internal/bootstrap/integration_health.go Health evaluation updated to scan taskwing/ namespace subdirectory for command files and detect legacy tw-* flat files; logic is consistent but depends on the correct filenames being written by initializer.go (which has bugs).
internal/bootstrap/mcp_healthcheck_test.go Tests correctly updated to use nsDir (namespace subdirectory) when writing test fixture files, and assertion strings updated to new MCP server name; the tests pass because they mirror the (buggy) expected-filename logic, not because the resulting filenames are correct.
internal/mcpcfg/naming.go Clean inversion of canonical/legacy names: CanonicalServerName changed from "taskwing-mcp" to "taskwing", IsLegacyServerName updated reciprocally; logic is correct and well-structured.
cmd/mcp_server.go MCP server Implementation.Name changed from "taskwing-mcp" to "taskwing" — straightforward, correct rename with no side effects.
cmd/slash_content.go All prompt content string constants updated — comment headers and inline command references changed from tw-* to taskwing:*; purely cosmetic/doc changes, no logic affected.
opencode.json MCP server key renamed correctly; however, the command array still contains a hardcoded absolute path to a developer-specific machine path — pre-existing issue but should be addressed.
cmd/slash.go Usage examples in the command description updated from tw-* to taskwing:* — no logic changes.
cmd/hook.go User-facing hook response messages updated from /tw-next to /taskwing:next — correct rename in all four call sites.
cmd/mcp_detect.go Comment strings updated to match new server name; actual detection logic delegates to mcpcfg.ContainsCanonicalServerName which is correctly updated in naming.go.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[taskwing bootstrap] --> B{AI Tool type?}
    B -->|Claude Code / Gemini TOML| C[CreateSlashCommands]
    B -->|OpenCode| D[createOpenCodeCommands]
    B -->|GitHub Copilot| E[createSingleFileInstructions]

    C --> F[mkdir .claude/commands/taskwing/]
    F --> G["Write taskwing/⚠️taskwing:ask.md\n(BUG: should be ask.md)"]
    G --> H[pruneStaleSlashCommands]
    H --> I["Scan root for tw-* files\n⚠️ BUG: 'tw-ask' not in managedBases\n→ legacy files NOT removed"]
    H --> J["Scan taskwing/ for stale files\n(expects taskwing:ask.md keys)"]

    D --> K["Validate cmd.SlashCmd\nagainst ^[a-z0-9]+(-[a-z0-9]+)*$\n⚠️ BUG: 'taskwing:ask' has colon\n→ validation FAILS, returns error"]

    E --> L[Write single instructions .md file]
    L --> M[Embed MCP config with 'taskwing' server name ✓]

    style G fill:#ff6b6b,color:#fff
    style I fill:#ff6b6b,color:#fff
    style K fill:#ff6b6b,color:#fff
    style M fill:#51cf66,color:#fff
Loading

does not allow colons, so this check will return an error for every command on the very first iteration, making OpenCode command installation completely non-functional after this PR.

The old code passed cmd.BaseName (e.g., "ask"), which matched the regex. OpenCode uses flat filenames without namespacing, so cmd.BaseName is still the right field here.

The same fix applies to the filePath construction two lines below (line 727) and the verbose print (line 733) — all three should reference cmd.BaseName, not cmd.SlashCmd.

  1. internal/bootstrap/initializer.go, line 516-529 (link)

    Colon in generated filenames breaks Claude Code namespacing

    cmd.SlashCmd is "taskwing:ask" (etc.), so fileName becomes "taskwing:ask.md" / "taskwing:ask.toml". This produces files at .claude/commands/taskwing/taskwing:ask.md.

    Two concrete problems:

    1. Wrong Claude Code command name — Claude Code resolves a file at commands/<namespace>/<file> as /<namespace>:<file-stem>. So taskwing/taskwing:ask.md would produce /taskwing:taskwing:ask (double-namespaced), not /taskwing:ask.
    2. Invalid on Windows — colons are reserved characters in Windows filenames. Any user or CI agent running on Windows would get a write error.

    The comment on line 377 itself documents the correct mapping: ".claude/commands/taskwing/ask.md → /taskwing:ask". The filename inside nsDir should therefore be cmd.BaseName, not cmd.SlashCmd.

    expectedSlashCommandFiles on line 384 also needs the same fix (expected[cmd.BaseName+ext]) so the health-check stays consistent with what is actually written to disk.

  2. internal/bootstrap/initializer.go, line 389-397 (link)

    Legacy tw-*.md cleanup silently skipped — old files will never be removed

    managedSlashCommandBases() now populates the legacy entry as "tw-" + cmd.SlashCmd = "tw-taskwing:ask". But files written by the previous version of TaskWing used cmd.BaseName as the stem, producing tw-ask.md, tw-next.md, etc.

    When pruneStaleSlashCommands scans the commands root and calculates base = "tw-ask", it checks managedBases["tw-ask"] — which is absent (the map only contains "tw-taskwing:ask"). The guard at line 418 fires, and the file is skipped, never cleaned up. Existing users upgrading from the old tw-* commands will silently retain all stale files.

  3. internal/bootstrap/initializer.go, line 277-283 (link)

    Stale SlashCommandNames doc comment — returns full names, not short names

    The comment says the function returns "short names (e.g., 'ask', 'next', 'done')", but since line 281 now reads names = append(names, cmd.SlashCmd), it actually returns fully-qualified names like "taskwing:ask", "taskwing:next", etc.

  4. opencode.json, line 1-10 (link)

    Developer-only absolute path committed to repo

    The command array contains a hardcoded absolute path pointing to a specific developer's machine:

    /Users/josephgoksu/Development/products/taskWing-cli/bin/taskwing
    

    Every contributor cloning this repo will have a broken local opencode.json config. This file should either not be committed (add to .gitignore) or use the installed binary name "taskwing" directly — matching the README's recommended config:

    "command": ["taskwing", "mcp"]

    This was a pre-existing issue, but it is surfaced here again because the key was changed in this PR.

Fix All in Claude Code

Last reviewed commit: c4da094

…r to taskwing

Standardize naming convention across the entire codebase:
- Slash commands: /tw-ask → /taskwing:ask, /tw-next → /taskwing:next, etc.
- MCP server name: taskwing-mcp → taskwing
- No backward compatibility shims — old names detected as legacy for cleanup
Fix three critical runtime bugs identified by Greptile review:

1. macOS filesystem failure: colons in filenames (taskwing:ask.md) are
   invalid on HFS+/APFS. Now uses subdirectory approach:
   .claude/commands/taskwing/ask.md → /taskwing:ask

2. OpenCode validation failure: regex rejects colons. Now uses SlashCmd
   field (ask, next, etc.) instead of BaseName for OpenCode filenames.

3. Migration cleanup: managedSlashCommandBases() now includes legacy
   tw-* names so old files are properly pruned during upgrade.

Also fixes misleading comment on SlashCommandNames().
@josephgoksu
Copy link
Owner Author

@greptile

Replace absolute dev binary path with portable "taskwing" command name
so the config works on any machine.
@josephgoksu josephgoksu merged commit 6e04dec into main Mar 9, 2026
@josephgoksu josephgoksu deleted the refactor/rename-slash-commands-taskwing-colon branch March 9, 2026 00:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant