Skip to content

fix(opencode): register /impeccable slash command via commands/ bridge - #483

Open
4nibhal wants to merge 17 commits into
pbakaus:mainfrom
4nibhal:opencode/slash-command-bridge
Open

fix(opencode): register /impeccable slash command via commands/ bridge#483
4nibhal wants to merge 17 commits into
pbakaus:mainfrom
4nibhal:opencode/slash-command-bridge

Conversation

@4nibhal

@4nibhal 4nibhal commented Aug 2, 2026

Copy link
Copy Markdown

Before opening

This repo is issue-first for outside contributions. If you are not pbakaus or abdulwahabone, please link the issue where a maintainer approved or requested this PR. Unsolicited PRs may be closed without review.

Summary

npx impeccable install --providers=opencode installs the skill but never registers a slash command: OpenCode (1.18.10) silently ignores the Claude-style SKILL.md frontmatter extensions (user-invocable, argument-hint, etc.) and only surfaces .opencode/commands/*.md in the TUI slash menu. The README, the site, and the skill's own Setup section all promise /impeccable init, so OpenCode users hit a silent dead end (repro in #474).

This PR makes the install emit a parallel commands/ artifact for OpenCode:

  • Transformer (scripts/lib/transformers/factory.js): emits dist/opencode/.opencode/commands/impeccable.md — a strict-schema bridge command (agent: build, subtask: true) that loads the skill via the skill tool, runs the mandatory context.mjs setup, and routes $ARGUMENTS to sub-commands. The body discovers <skill-base-dir> from the skill tool response, so project, global, and custom OPENCODE_CONFIG_DIR installs all work (respects [Bug] Global OpenCode install uses the wrong directory #406).
  • CLI (cli/bin/commands/skills.mjs): new copyProviderCommands step installs commands/ into .opencode/ for project and global scopes, mirroring Install global OpenCode skills into the config dir OpenCode reads #417's symlink / realpath / dotfiles migration guards.
  • Pin (skill/scripts/pin.mjs): impeccable pin <cmd> now writes .opencode/commands/impeccable-<cmd>.md for OpenCode instead of a skill-only shortcut.
  • Docs (docs/HARNESSES.md): corrects the OpenCode frontmatter row (OpenCode only honours the Agent Skills spec subset) and adds the commands substitution row.
  • Test registry (scripts/test-suites.mjs): registers the two new test files in the core suite.

Forward-compatible with a future OpenCode skill→command auto-bridge (anomalyco/opencode#35341, anomalyco/opencode#34410): explicit commands outrank the bridge, and nothing here depends on the bridge staying absent.

Closes #474

Type of change

  • New command
  • New / updated skill reference
  • New anti-pattern guidance
  • Bug fix
  • Documentation update
  • Build system / tooling
  • Other:

Checklist

  • Source files updated in source/
  • bun run build ran successfully
  • bun test passes
  • Tested with at least one provider (Cursor / Claude Code / Gemini CLI / Codex / Copilot / Grok Build / Kiro / OpenCode / Qoder / Mistral Vibe)
  • README / DEVELOP.md updated if needed
  • I reviewed the full diff myself before requesting human review
  • I disclosed any AI assistance in this PR and related commits/comments, or no AI assistance was used

Validation

  • bun run build ✓ — 16 providers assembled, prose/version validators green.
  • bun run test ✓ — 415 pass (bun) + 326 pass (node --test), 0 fail, 8 skip (pre-existing).
  • Smoke (fresh git init + install --providers=opencode --scope=project): .opencode/commands/impeccable.md created with correct frontmatter; skill tree intact.
  • Live TUI smoke on OpenCode 1.18.10: /impeccable appears in slash autocomplete; --command impeccable runs end-to-end.

Generated provider output

Intentionally omitted. bun run build was used for validation only; tracked root harness folders and plugin/ are untouched per the source-first policy — .github/workflows/sync-generated-output.yml regenerates them post-merge.

AI assistance disclosure

Drafted and implemented with AI assistance (OpenCode + MiniMax M3), reviewed by me before opening. All commits carry an AI-Assisted trailer.


Note

Medium Risk
Changes install/update/link file layout and freshness checks across scopes, but scope is limited to OpenCode command artifacts with migration guards and broad test coverage.

Overview
OpenCode ignores Claude-style SKILL.md frontmatter for slash menus, so installs could ship the skill without a usable /impeccable entry (#474). This PR adds an OpenCode commands/ bridge end-to-end.

The build now emits .opencode/commands/impeccable.md (OpenCode-only frontmatter: description, agent: build, subtask: true) that delegates via the skill tool and $ARGUMENTS. syncRootCommands mirrors those files into tracked harness folders on release sync so GitHub/submodule installs get the bridge too.

The CLI gains copyProviderCommands, wired into install, update, and link, with the same global config dir precedence and legacy ~/.opencode/commands cleanup as skills (#417). isUpToDate treats missing or drifted bundle command files as stale so reinstall/update backfills the bridge without falsely reporting “up to date.”

pin.mjs writes impeccable-<cmd>.md command shortcuts for OpenCode (project and user scope) instead of useless .opencode/skills/<cmd> pins. docs/HARNESSES.md documents OpenCode’s real frontmatter and command substitution.

Reviewed by Cursor Bugbot for commit 85f307d. Bugbot is set up for automated code reviews on this repo. Configure here.

4nibhal and others added 5 commits August 2, 2026 15:50
…ills

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
… guards

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
…rtcut

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
…titution row

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
@4nibhal
4nibhal requested a review from pbakaus as a code owner August 2, 2026 14:06
Comment thread cli/bin/commands/skills.mjs
@greptile-apps

greptile-apps Bot commented Aug 2, 2026

Copy link
Copy Markdown

Greptile Summary

This change adds OpenCode command bridges across generation, installation, synchronization, and pinning. A real mixed-provider installation was exercised with Claude already present and OpenCode explicitly selected: the CLI reported success and installed the OpenCode skill, but did not create .opencode/commands/impeccable.md, leaving /impeccable unavailable.

Confidence Score: 4/5

Not safe to merge until mixed OpenCode installs also copy the command bridge.

The reproduced installation path reports a successful OpenCode installation even though it omits the command file required for /impeccable.

Files Needing Attention: cli/bin/commands/skills.mjs

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex produced a proof for a posted P1 finding and linked it to the corresponding review comment for details.
  • T-Rex produced a second proof for another posted P1 finding.
  • T-Rex performed a general-contract-validation proving the exact executable fixture and the before/after log states, showing the CLI ran successfully and the OpenCode skill was installed while the bridge was omitted.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (2)

  1. cli/bin/commands/skills.mjs, line 1978-1986 (link)

    P1 Mixed install omits command bridge

    When an explicit install selects OpenCode alongside a provider that is already installed, this fresh-target branch copies the OpenCode skill and agents but never calls copyProviderCommands. The CLI therefore reports success while .opencode/commands/impeccable.md remains absent, leaving /impeccable unavailable. Copy command artifacts for missingSelectedTargets in this branch, as the normal installation and update paths do.

    Context Used: AGENTS.md (source)

    Artifacts

    Exact isolated CLI reproduction source

    • This executable creates a temporary mixed-provider fixture and invokes the real CLI, proving the exact scenario is exercised.

    Before capture for mixed OpenCode installation

    • This captured setup run shows Claude already installed, OpenCode skill and command absent, and the source bundle command present—the required mixed starting condition.

    After capture showing omitted OpenCode command bridge

    • This captured CLI run exits successfully and installs the OpenCode skill while leaving the supplied command bridge absent, confirming the bug.

    View artifacts

    T-Rex Ran code and verified through T-Rex

    Fix in Codex Fix in Claude Code

  2. General comment

    P1 Mixed explicit install omits the OpenCode command bridge for fresh providers

    • Bug
      • At cli/bin/commands/skills.mjs:1978-1986, an explicit mixed request (claude,opencode) after Claude is already installed enters the existing-install branch. The reproduced execution installed .opencode/skills/impeccable/SKILL.md, while .opencode/commands/impeccable.md remained absent even though the local bundle supplied it.
    • Cause
      • The fresh-provider block calls copyProviderSkills and copyProviderAgents, but unlike the copied-provider update block at line 1972 and the normal fresh-install flow, it never calls copyProviderCommands(bundleDir, installRoot, missingSelectedTargets, { scope }).
    • Fix
      • After copyProviderSkills succeeds in the missingSelectedTargets block, call copyProviderCommands(bundleDir, installRoot, missingSelectedTargets, { scope }) before reporting completion.

    T-Rex Ran code and verified through T-Rex

Fix All in Codex Fix All in Claude Code

Reviews (11): Last reviewed commit: "Harden the pinned OpenCode command body ..." | Re-trigger Greptile

Comment thread docs/HARNESSES.md Outdated
4nibhal added 2 commits August 2, 2026 17:12
…rent installs

isUpToDate now treats bundle-shipped command artifacts (e.g.
.opencode/commands/impeccable.md) as part of freshness, and the reinstall
refresh path copies provider commands alongside skills and agents. Existing
OpenCode installs (pbakaus#474) get /impeccable restored by a plain reinstall or
update instead of staying bridge-less until --force. Pinned and user commands
never affect freshness and are never touched.

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
The table already documented .opencode/commands/ without @file; keep the
single complete row (with @file, per opencode.ai/docs/commands).

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
Comment thread cli/bin/commands/skills.mjs
impeccable link only symlinked skills, and linked providers are deliberately
excluded from install/update refreshes (overwriting a symlink would destroy
the link), so linked OpenCode installs had no path to /impeccable at all.
link now copies the command bridge from the source bundle alongside the
skill symlinks; it no-ops when the checkout has no built commands. Also adds
user-scope coverage for the commands-aware freshness check
(OPENCODE_CONFIG_DIR resolution).

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
@github-actions github-actions Bot added the needs maintainer review Ready for a maintainer to review or decide label Aug 2, 2026
Comment thread cli/bin/commands/skills.mjs
Comment thread scripts/lib/transformers/factory.js Outdated
Comment thread skill/scripts/pin.mjs
Scope-less runs (skills check, or update from the home dir) match global
OpenCode skills via HOME_SKILLS_DIR_OVERRIDES, but the commands-aware
freshness check resolved the bridge via providerCommandsDir, which without an
explicit scope always points at <root>/.opencode/commands. Global installs
were perpetually stale: check falsely reported updates and update refreshed
every run. The commands dir is a sibling of the matched skills dir in every
layout copyProviderCommands writes, so derive it from localSkillsDir. The
regression test runs through the CLI subprocess because Bun caches
os.homedir() and cannot observe a runtime HOME override.

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
Comment thread scripts/lib/transformers/factory.js
Comment thread scripts/lib/root-commands-sync.mjs
Comment thread scripts/test-suites.mjs
syncRootOutputs mirrored skills, agents, and hooks but not commands/, so
the post-merge release sync would never commit
.opencode/commands/impeccable.md and direct GitHub / npx-skills / submodule
installs would keep shipping OpenCode without the slash command bridge.
syncRootCommands mirrors generated command files per entry, preserving
repo-local and pinned commands at the destination. Verified end to end:
bun run build:release logs the sync and lands the bridge at the repo root
(generated churn intentionally reverted per the source-first policy).

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
@4nibhal
4nibhal force-pushed the opencode/slash-command-bridge branch from 733cb4f to 78edf1e Compare August 2, 2026 16:47
Comment thread skill/scripts/pin.mjs
@4nibhal

4nibhal commented Aug 2, 2026

Copy link
Copy Markdown
Author

@greptile-apps Both findings reproduce only against the OpenCode 1.3.10 runtime in the T-Rex sandbox, which predates OpenCode's skills and custom-commands support entirely. The captured run is self-defeating evidence: the server returned no installed skill from /skill either, so that runtime cannot discover any skill — impeccable or otherwise — and init/review are just the built-in commands.

Verified against the current OpenCode release (1.18.10, opencode --version):

  • opencode debug skill lists impeccable after npx impeccable install --providers=opencode.
  • /impeccable appears in the TUI slash autocomplete and opencode run --command impeccable executes end to end.
  • pin audit writes .opencode/commands/impeccable-audit.md, discovered from the same .opencode/commands/ dir (per https://opencode.ai/docs/commands/).

The emitted frontmatter (description, agent, subtask) matches the strict command schema at opencode/packages/core/src/v1/config/command.ts:5-13, and docs/HARNESSES.md already documents the 1.18.10 frontmatter behavior explicitly. A CLI-side warning when the detected OpenCode version is below the supported floor is a reasonable follow-up, but out of scope for this PR.


Drafted with AI assistance (OpenCode + MiniMax M3), reviewed by me.

Comment thread skill/scripts/pin.mjs Outdated
pin/unpin only recognised project-local OpenCode installs, so a global
install (OPENCODE_CONFIG_DIR / XDG / ~/.config/opencode, the pbakaus#406 layout)
made pin exit 0 with 'No harness directories' and no pinned command. The
OpenCode branch now resolves both scopes — project commands dir and user
config commands dir, deduped — with the same marker guards, and the
no-harness early return only fires when neither scope has an install. The
user-scope precedence helper mirrors the CLI's opencodeGlobalConfigDir;
duplicated because pin.mjs ships inside the installed skill. Tests sanitize
OPENCODE_CONFIG_DIR/XDG_CONFIG_HOME so runs never touch the developer's
real global config.

AI-Assisted: OpenCode + MiniMax M3, reviewed by 4nibhal
@pbakaus

pbakaus commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Would be great if you could resolve conflicts. Also, I'm a bit unsure about this one...feels like a workaround with a lot of code to maintain specifically for a temporary issue with OpenCode. Have you validated that the command can reference and load other files in the skill folder etc?

4nibhal added 2 commits August 4, 2026 16:33
Resolve the single conflict in scripts/test-suites.mjs by keeping
main's suite structure (plugin-e2e in DEFAULT_SUITES, plus the
validate-plugin-manifest and release test entries) and re-adding
this branch's three bridge tests to the bun runner list.

Drafted with AI assistance (OpenCode + k3-256k); reviewed and approved by the human author.
- factory.js: the bridge body no longer re-implements the skill Setup
  flow; it delegates to OpenCode's skill tool in one line, and the
  '(slash command bridge)' suffix is gone from the description the TUI
  menu displays
- skills.mjs: drop the identity PROVIDER_CONFIG_DIRS table; the
  fallback already computed the same result for every provider
- tests: pin the exact delegating body and a quoting-agnostic
  description assertion

Drafted with AI assistance (OpenCode + k3-256k); reviewed and approved by the human author.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 26ae983. Configure here.

Comment thread skill/scripts/pin.mjs Outdated
@4nibhal

4nibhal commented Aug 4, 2026

Copy link
Copy Markdown
Author

Thanks for the review — fair point that the first version read like a workaround. I dug into what OpenCode actually does today (verified against a local OpenCode 1.18.10 install, not assumed) and reworked the PR around it. Facts first, then the changes in impeccable.

What OpenCode already does (verified)

  • OpenCode does register skill-sourced commands server-side and they do execute: GET /command returns impeccable with source: "skill", and opencode run --command impeccable runs with no bridge file present.
  • OpenCode's TUI submit handler resolves typed commands against the full unfiltered list (packages/tui/src/component/prompt/index.tsx:1071-1072 in the OpenCode repo), so typing /impeccable by hand works today.
  • What does not happen: OpenCode's TUI autocomplete menu skips skill-sourced commands (packages/tui/src/component/prompt/autocomplete.tsx:451). That's a deliberate, non-configurable design decision in OpenCode — per @rekram1-node (OpenCode collaborator) in anomalyco/opencode#25439 (comment): "it's intentional you can't /".
  • The gap is tracked in the OpenCode repo: anomalyco/opencode#34410 (@ and / skill invocation in the TUI prompt) and anomalyco/opencode#35341 (auto-register / from skills), plus open OpenCode PRs #29217 ($skill inline, idle since May) and #35522. Nothing landed, no stated timeline.
  • When a command file exists, OpenCode cleanly shadows the skill-sourced entry with it (one registration, source: "command"). No duplication or conflict.

So on OpenCode today: /impeccable works if you already know it exists — but it's invisible in the / menu, which is how users discover commands. That's the dead end reported in impeccable#474.

Why impeccable ships a command file (and why this body)

One detail from the same OpenCode thread is worth noting: rekram1-node also said "it's BAD that skill invocations reuse command logic and dont invoke the skill tool — we need to update that." The revised bridge in this PR does exactly what OpenCode's collaborator described — the entire body is one line:

Call skill({ name: "impeccable" }) and follow its Setup and Commands sections to handle $ARGUMENTS.

The file earns its place in impeccable's OpenCode install for three reasons, and only the first is contingent on OpenCode's current design:

  1. Menu discoverability — the OpenCode gap above. This part becomes redundant the day OpenCode surfaces skill commands in its autocomplete menu.
  2. Execution policyagent: build + subtask: true, pinned by impeccable as the skill author. OpenCode's native execution uses whatever primary agent is selected, with no way for a skill to pin this.
  3. Reliable base-dir resolution — routing through OpenCode's skill tool returns the skill's absolute base directory, so impeccable's Setup flow finds its scripts/ and reference/ folders regardless of install scope (the same class of issue as impeccable#406). OpenCode's native execution dumps the raw SKILL.md as the prompt template and leaves the agent to guess paths.

What changed in this revision of the PR

  • Bridge body: 12 lines → 1 line (scripts/lib/transformers/factory.js). It no longer re-implements impeccable's Setup flow — that was the workaround smell. SKILL.md stays the single source of truth.
  • Description cleaned up — OpenCode's TUI menu displays this text, so the "(slash command bridge)" suffix is gone.
  • Removed an identity lookup table in cli/bin/commands/skills.mjs (16 entries each mapping a provider to itself; the fallback already computed the same result).
  • scripts/test-suites.mjs conflict resolved as a union of both lists.
  • The emitter comment in factory.js states plainly why the file exists and which part is contingent on OpenCode's design, so future maintainers of impeccable know exactly what can be deleted if OpenCode's behavior changes.

Deliberately kept: the user-scope install migration, freshness check, and reinstall/update backfill in impeccable's CLI — those manage the installed artifact's lifecycle and earn their keep independently of OpenCode's menu gap.

Validation: bun run build clean, full bun run test green, plus live checks against a real OpenCode 1.18.10 — schema-valid command registration, clean shadowing, and opencode run --command impeccable execution all confirmed locally.

Drafted with AI assistance (OpenCode + k3-256k); reviewed and approved by the human author.

Comment thread skill/scripts/pin.mjs Outdated
4nibhal added 2 commits August 4, 2026 16:53
findOpencodeCommandsDirs() only enumerated a commands dir while the
matching skills/impeccable dir existed, so unpin after uninstalling the
skill left the marker-bearing impeccable-<cmd>.md behind and wrongly
reported that no pinned shortcut was found. unpin now enumerates both
scopes with forCleanup: removal stays safe because
removePinnedOpencodeCommand is marker-guarded, and pin keeps the
skill-presence gate so pins are never written where the skill is not
installed. Adds regression tests for project-scope and user-scope
removal plus the non-pinned-command guard.

Flagged by greptile-apps[bot] on pbakaus#483.

Drafted with AI assistance (OpenCode + k3-256k); reviewed and approved by the human author.
The pinned OpenCode command body resolved reference/<cmd>.md without a
base-dir prefix, leaving the lookup ambiguous for agents that do not
infer it from the skill tool response. The path now matches the
explicit <skill-base-dir> form already used for context.mjs.

Flagged by cursor[bot] on pbakaus#483.

Drafted with AI assistance (OpenCode + k3-256k); reviewed and approved by the human author.
Comment thread skill/scripts/pin.mjs Outdated
@github-actions github-actions Bot added blocked: review threads Unresolved review feedback or requested changes remain waiting on contributor Waiting for the PR author to respond or make changes needs maintainer review Ready for a maintainer to review or decide ready to merge Passing, resolved, and ready for a maintainer merge decision blocked: merge conflicts PR cannot merge until conflicts are resolved and removed needs maintainer review Ready for a maintainer to review or decide blocked: review threads Unresolved review feedback or requested changes remain waiting on contributor Waiting for the PR author to respond or make changes ready to merge Passing, resolved, and ready for a maintainer merge decision labels Aug 4, 2026
pbakaus and others added 2 commits August 9, 2026 17:17
The pinned command wrote <skill-base-dir> without ever defining it, so a
weaker agent could take the placeholder literally (the concern behind the
earlier review finding). The body now states that the placeholder is the
base directory the skill tool reports and must be substituted with the
real absolute path. Also corrects the comment above
generatePinnedOpencodeCommand, which claimed the body routes through the
parent /impeccable bridge when it actually loads the skill and the
sub-command reference directly, and swaps an em dash in the fallback
description string for house-style punctuation, since that string is
written into user-facing command files.

AI-assisted (Claude Code).

Co-Authored-By: Claude <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Aug 10, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Start a greploop in Codex and it will work through the open comments and keep going until this PR reviews clean.

@pbakaus

pbakaus commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Thanks for the thorough rework here. The one-line bridge that delegates to the skill via OpenCode's skill tool is exactly the right shape, and your OpenCode citations checked out against their docs: .opencode/commands/*.md with description, agent, and subtask is the documented, first-class way to get a slash command, so this no longer reads as a workaround.

To save you a round trip, we pushed two commits to your branch. The first resolves the merge conflict with main (just the import lines in tests/skills-cli.test.js, taken as the union of both sides). The second is a small hardening of the pinned OpenCode command in pin.mjs: the body now spells out that <skill-base-dir> means the base directory the skill tool reports and must be substituted with the real path, the comment that claimed the pin routes through the parent bridge now matches what the code does, and an em dash in the fallback description was swapped for house punctuation. Build, the full test suite, and the remote CLI E2E suite are all green on the result.

One open question before merge: with subtask: true, can you confirm that the Setup interview's questions still reach the user in the OpenCode TUI? Your smoke test showed the command runs end to end, but Setup is interactive, and we want to be sure a subagent invocation does not swallow the questions.

(Posted with AI assistance via Claude Code.)

@pbakaus pbakaus removed the blocked: merge conflicts PR cannot merge until conflicts are resolved label Aug 10, 2026
@github-actions github-actions Bot added the blocked: ci Latest commit has failing required checks label Aug 10, 2026
@4nibhal

4nibhal commented Aug 10, 2026

Copy link
Copy Markdown
Author

Confirmed on OpenCode 1.18.11: the Setup interview does reach the user with subtask: true.

In a real TUI session of /impeccable init through the bridge, the build subagent opened the question modal over the main view with the full init flow — product purpose, platform & stack, constraints & assets, and the final confirm round — and blocked until answered. (Verified manually in the TUI; headless opencode run never renders the question modal.)

Why it works: the TUI surfaces question requests from child sessions on the parent view (session/index.tsx). Same mechanism as OpenCode's built-in /review.

AI-assisted (OpenCode + deepseek-v4-flash).

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

Labels

blocked: ci Latest commit has failing required checks needs maintainer review Ready for a maintainer to review or decide policy: approved

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] README and site promise /impeccable for OpenCode, but install never registers a slash command in the TUI

2 participants