opencode icon indicating copy to clipboard operation
opencode copied to clipboard

Feat: custom commands

Open ezynda3 opened this issue 5 months ago • 17 comments

feat: Add custom slash commands support

Summary

• Adds support for user-defined custom slash commands stored as markdown files • Commands support dynamic argument interpolation with validation • Implements automatic command discovery with scope-based priority

Overview

This PR implements a custom slash commands feature that allows users to define their own commands as markdown files in .opencode/commands/ directories. Commands are treated as prompts that can include argument placeholders which are validated and interpolated before submission.

Key Features

  1. Command Discovery & Loading • Automatically discovers commands from: • Project-specific: <project>/.opencode/commands/ • User-global: ~/.opencode/commands/ • Supports namespaced commands via directory structure (e.g., git/commit.md/git:commit) • Commands are prefixed with scope (user: or project:) to prevent conflicts • Project commands take priority over user commands with the same name • Hot-reloads commands when files change

  2. Argument Handling • Argument placeholders: $ARGUMENTS or {{args}} in command content • Automatic argument count validation based on placeholder occurrences • Commands with placeholders are inserted into input field for user to add arguments • Commands without placeholders are submitted immediately • Clear error messages when wrong number of arguments provided

  3. Content Resolution • File references: @{path/to/file.ts} injects file contents (relative to command file) • Arguments are interpolated individually into their respective placeholders • File content is truncated to 1MB to prevent memory issues

  4. Integration • Server endpoints: /command, /command/:name, /command/resolve • TUI autocomplete support with descriptions and argument hints • Commands appear in slash command menu with proper categorization • Seamless execution as regular prompts to the AI

Implementation Details

Server-side (TypeScript):packages/opencode/src/command/ - Core command module • types.ts - Type definitions and schemas • loader.ts - Command discovery and file watching • resolver.ts - Argument validation and content resolution • index.ts - Public API with App.state integration

TUI-side (Go):internal/components/chat/editor.go - Command selection and submission logic • Added validation to prevent submission with unresolved placeholders • Custom commands populate input field when arguments are needed

Example Commands

Simple command without arguments:

---
description: Explain the current code
---

Please explain what this code does and how it works.

Command with arguments:

---
description: Create a function with specified parameters
argument-hint: "<name> <params> <return-type>"
---

Create a function named $ARGUMENTS that takes parameters $ARGUMENTS and returns $ARGUMENTS.
Include proper error handling and documentation.

Testing

• Unit tests for argument validation and interpolation • Tests for command loading with scope priority • Tests for file reference resolution • All resolver tests passing (8/8)

Breaking Changes

None - this is a new feature that doesn't affect existing functionality.

ezynda3 avatar Jul 25 '25 09:07 ezynda3

This PR is huge, I've been adding support for references for agents.

Does your change follow nested links? Alos how doesn't handle relative paths? I see workingDirectory: this.app.path.cwd, is that enough to work well in both global and local config?

mpazik avatar Jul 25 '25 11:07 mpazik

Also have been wondering if agents could be used as custom commands; lots of features have overlap.

mpazik avatar Jul 25 '25 11:07 mpazik

Also have been wondering if agents could be used as custom commands; lots of features have overlap.

I'd like to think custom commands should be a totally separate thing as they don't spawn a new context like an agent might. Also hoping to be able to incorporate MCP provided prompts as custom commands soon as well.

ezynda3 avatar Jul 25 '25 13:07 ezynda3

This PR is huge, I've been adding support for references for agents.

Does your change follow nested links? Alos how doesn't handle relative paths? I see workingDirectory: this.app.path.cwd, is that enough to work well in both global and local config?

Not sure what you mean by nested links. I did update the path resolution though.

ezynda3 avatar Jul 25 '25 13:07 ezynda3

@ezynda3 yes, mcp provider support is something that I need as well.

I created a PR for prompt reference resolution for agents and modes at https://github.com/sst/opencode/pull/1317 This supports nested file references and is reusable. Please check it out.

These changes are non-trivial, though. I would wait for @thdxr's opinion regarding implementation.

mpazik avatar Jul 25 '25 14:07 mpazik

hey i appreciate how much work you put into this but in the readme we try to make it clear you should chat with us before working on any large feature

this is a good feature and the design of it might even be close to perfect but we need to run stuff like this through our internal process

lot of work put into this but realistically i'll probably do it from scratch so it aligns with other things we're working on

thdxr avatar Jul 25 '25 14:07 thdxr

hey i appreciate how much work you put into this but in the readme we try to make it clear you should chat with us before working on any large feature

this is a good feature and the design of it might even be close to perfect but we need to run stuff like this through our internal process

lot of work put into this but realistically i'll probably do it from scratch so it aligns with other things we're working on

Crap I should have read closer. My bad. No worries. Just had the itch and wanted to get this feature in there as it's been a while since the rewrite.

ezynda3 avatar Jul 25 '25 15:07 ezynda3

@thdxr any plans on adding commands any time soon?

luisrudge avatar Jul 29 '25 17:07 luisrudge

would be a massive fan of this feature

TamirShklaz avatar Jul 30 '25 15:07 TamirShklaz

TBH without this feature, I won't migrate from Claude Code. Custom commands are deeply integrated into my workflow now.

olafgeibig avatar Aug 01 '25 12:08 olafgeibig

for me too this is a must have feature

ivanthe-stack avatar Aug 01 '25 16:08 ivanthe-stack

you can use your claude commands in sst. if you just @./cursor/commands/your-command.md it works. it's just not discoverable with /your-command

luisrudge avatar Aug 01 '25 16:08 luisrudge

@thdxr Hi pro, any plan for this feature?

hujianxin avatar Aug 02 '25 15:08 hujianxin

@thdxr Hi pro, any plan for this feature?

I think they're busy planning and implementing this, here is the comment to the PR I created a few weeks ago https://github.com/sst/opencode/pull/707#issuecomment-3071380154

It's not really a small feature, so it might take them a while to get it ready on top of staying ahead of the new AI tool releases

ll931217 avatar Aug 04 '25 00:08 ll931217

This feature is essential to my workflow. I am eagerly awaiting it.

quantmind-br avatar Aug 09 '25 13:08 quantmind-br

This is also pretty much a deal breaker for me, I've got claude code running with LiteLLM Proxy to Qwen3 Coder via openrouter and would really just like to use opencode. But commands have become core to my workflow, so when ever I try I get annoyed and bounce off back to claude.

martinffx avatar Aug 09 '25 18:08 martinffx

I think proposed arguments definition is not really "user friendly":

argument-hint: " "

Is there a reason to pass a string in place of a yaml array? I think definition like below can increase DX and be more evolutive (like define arguments types):

arguments:
  name: string
  params: array
  return-type: string

So array type can tell opencode to ask arguments one by one for example. And typing avoid possible errors on interpolation.

Idk how all is already implemented. This is a just a suggestion on the fly 😄

fmatsos avatar Aug 15 '25 08:08 fmatsos