#21712: feat(config): add custom commands to CommandsSchema
size: M
Cluster:
Config Fixes and Features
## Summary
Adds `commands.custom` to the Zod config schema so the existing custom commands runtime handler (`commands-custom.ts`) can actually be used.
The handler, interpolation logic (`${ARGS}`, `${WORKSPACE}`), and tests all exist already — the only gap was that `CommandsSchema` used `.strict()` and didn't include a `custom` field, so the config was rejected at validation time.
## Changes
- Added `CustomCommandSchema` (description, exec, reply, ownerOnly)
- Added `custom: z.record(z.string(), CustomCommandSchema).optional()` to `CommandsSchema`
## Config Example
```json
{
"commands": {
"custom": {
"dnd": {
"description": "Toggle Do Not Disturb",
"exec": "bash ${WORKSPACE}/skills/dnd/scripts/toggle.sh ${ARGS}",
"reply": true
}
}
}
}
```
## Testing
- All 417 config tests pass
- All 7 commands-custom tests pass
- Type-check clean (`pnpm tsgo`)
Closes #21700
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR closes the gap between the existing custom commands runtime handler and the Zod config schema validation. The handler (`commands-custom.ts`) and its comprehensive test suite already existed, but `CommandsSchema` used `.strict()` without including a `custom` field, causing config validation to reject valid custom command configurations.
The implementation adds:
- `CustomCommandSchema` with fields for `description`, `exec`, `reply`, and `ownerOnly`
- `custom: z.record(z.string(), CustomCommandSchema).optional()` to `CommandsSchema`
- Handler registration in `commands-core.ts` (positioned after plugin commands, before bash)
- Field label in `schema.labels.ts`
- Type definitions in `types.messages.ts`
The handler includes security controls: `ownerOnly` defaults to requiring authorized senders (line 55 in `commands-custom.ts`), args are passed via string interpolation with `${ARGS}` and `${WORKSPACE}` placeholders, and commands timeout after 10 seconds.
<h3>Confidence Score: 3/5</h3>
- This PR is safe to merge with caution - addresses the config validation gap, but has a shell injection vulnerability
- Score reflects that the PR correctly implements the schema plumbing and has comprehensive tests, but the `interpolateExec` function doesn't escape user-provided arguments before shell execution, creating a command injection risk for authorized users. The feature is owner-restricted by default which limits exposure, but the vulnerability should be fixed.
- Pay close attention to `src/auto-reply/reply/commands-custom.ts` - the interpolation logic needs shell escaping
<sub>Last reviewed commit: 94f56d2</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#12499: fix(config): add missing customBindHost to gateway Zod schema
by sfo2001 · 2026-02-09
75.3%
#10943: fix(config): resolve Control UI "Unsupported schema node" for confi...
by kraftbj · 2026-02-07
75.1%
#19059: feat(telegram): add commands.include/exclude for selective menu reg...
by moxunjinmu · 2026-02-17
73.0%
#19429: Fix/custom bind host validation
by frudas24 · 2026-02-17
72.8%
#23534: fix(config): add firecrawl and readability fields to ToolsWebFetchS...
by slayoffer · 2026-02-22
72.0%
#16412: fix(config): align tools.web.fetch schema with firecrawl/readabilit...
by ciberponk · 2026-02-14
71.3%
#20170: fix(irc): add configurable commandPrefix to avoid IRC reserved / pr...
by yxshee · 2026-02-18
71.1%
#8455: feat: add thinking/model config to skills.entries
by tsukhani · 2026-02-04
70.3%
#10807: fix(config): coerce numeric meta.lastTouchedAt to ISO string
by mcaxtr · 2026-02-07
70.2%
#14395: feat: add gateway.nodes.execEvents config to control exec completio...
by dan3093 · 2026-02-12
69.9%