-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Feat: custom commands #1304
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Feat: custom commands #1304
Conversation
This PR is huge, I've been adding support for references for agents. Does your change follow nested links? |
Also have been wondering if agents could be used as custom commands; lots of features have overlap. |
- Remove allowed-tools from CommandMetadataSchema - Delete unused parser.ts file - Remove ParsedToolRestriction type - Simplify implementation for this iteration
- Add app context to CommandResolver constructor - Implement getBaseDirectory() to determine correct base path based on scope - User commands now resolve files relative to global config directory - Project commands resolve files relative to project root - Fallback resolution: first try relative to command file, then base directory - Addresses reviewer concern about path resolution for different scopes
…commands - Update unprefixedMap to only store project commands over user commands - Reorder getCommand lookup to check project: prefix before user: prefix - Ensures project-specific commands override global user commands with same name
- Create self-contained test that doesn't depend on imports - Mock file system operations to test command loading logic - Test all three key scenarios: basic loading, namespacing, and priority - Ensures tests can run anywhere without dependency issues
- Remove original loader.test.ts that had import issues - Rename loader-standalone.test.ts to loader.test.ts - Keep the self-contained test that works in CI environments
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. |
Not sure what you mean by nested links. I did update the path resolution though. |
@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 #1317 These changes are non-trivial, though. I would wait for @thdxr's opinion regarding implementation. |
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. |
@thdxr any plans on adding commands any time soon? |
would be a massive fan of this feature |
TBH without this feature, I won't migrate from Claude Code. Custom commands are deeply integrated into my workflow now. |
for me too this is a must have feature |
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 |
@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 #707 (comment) 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 |
This feature is essential to my workflow. I am eagerly awaiting it. |
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. |
I think proposed arguments definition is not really "user friendly":
Is there a reason to pass a string in place of a yaml array? arguments:
name: string
params: array
return-type: string So Idk how all is already implemented. This is a just a suggestion on the fly 😄 |
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
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:
orproject:
) to prevent conflicts• Project commands take priority over user commands with the same name
• Hot-reloads commands when files change
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
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
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 integrationTUI-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:
Command with arguments:
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.