feat(chat): suggest matching slash commands from natural language#1803
feat(chat): suggest matching slash commands from natural language#1803sukria-koan0 wants to merge 8 commits into
Conversation
PR Review — feat(chat): suggest matching slash commands from natural languageClean feature design, but the prompt template has two issues that should be fixed before merge.
🟡 Important1. Phantom command in prompt example (`koan/system-prompts/chat.md`, L21-26)
Use a real, simple command from the catalog — e.g. 2. Instruction block leaks when catalog is empty (`koan/system-prompts/chat.md`, L21-26)When suggestions are disabled or in lite mode, Fix: move the entire block (header + catalog + instructions) into 3. Weak assertion — always passes via template text (`koan/tests/test_awake.py`, L3603-3607)
Assert on the actual injected content instead: assert "/status" in prompt, "Catalog content should appear in prompt"🟢 Suggestions1. Alphabetical sort != "top" commands (`koan/app/awake.py`, L207-210)The docstring says "selects the top ~20 by group" but Consider explicit priority ordering or at least sort by group relevance. Alternatively, add a Checklist
To rebase specific severity levels, mention me: Silent Failure Analysis🟡 **MEDIUM** — catch-all masks registry bugs (`koan/app/awake.py:213-216`)Risk: The broad Fix: Narrow the catch to expected failures (e.g. Automated review by Kōan (Claude · model claude-opus-4-6) |
Koan-Bot
left a comment
There was a problem hiding this comment.
Blocking issues found — see the review comment above.
|
Review comments addressed:
All 8 catalog/chat tests pass. |
|
@sukria-koan0 review |
|
|
|
To fix :
@sukria-koan0 rebase |
Replace the intent-routing/confirmation machinery from PR #1799 with a simpler, zero-cost approach: enrich the chat prompt with a compact catalog of available slash commands and an instruction to suggest the matching command when a user's conversational message maps to one of them. Changes: - Add _build_command_catalog() helper in awake.py to generate human-triggerable commands from the skill registry, filtered by audience and grouped by help group - Update _build_chat_prompt() to inject {SKILLS_CATALOG} placeholder (empty in lite mode to save tokens) - Enhance koan/system-prompts/chat.md with command-suggestion section and instruction: suggest at most one command when the mapping is clear - Add get_chat_suggest_commands_enabled() config getter with default=true - Add chat.suggest_commands opt-in flag to instance.example/config.yaml - Add comprehensive tests for catalog builder, config getter, and prompt injection Benefits over intent-routing: - Zero extra Claude calls (no 5-10s latency, no round-trip) - No confirmation state machine or guard-bypass surface - Natural discovery inside the existing single-call chat path - Human always in control (suggestions only, no auto-execution) - Config opt-in for operators who prefer it disabled Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Update CLAUDE.md awake.py description to mention optional command suggestions - Add new 'Chat Command Suggestions' subsection in user-manual.md explaining the feature: advisory suggestions with copy-pasteable commands, opt-in via config - Clarify that suggestions are always user-controlled, not auto-executed Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…command
- _build_command_catalog() now returns the full section (header +
body + suggestion instruction) so chat.md has a single {SKILLS_CATALOG}
placeholder — when catalog is disabled/empty the surrounding text no
longer leaks into the prompt
- Replace hallucinated /resume_recurring example with /status (a real command)
- Tighten test assertion: assert "/status" in prompt instead of the vacuous
`or "Available slash commands"` branch that always passed via template text
Rebase with requested adjustmentsBranch Changes applied
StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
c8ec4ee to
2a2647a
Compare
|
By reading the diff, I see that we lost the "queuing" mechanic here, koan will just spot the matching command and say "want me to queue it" whereas it will not. This is misleading. Queuing the command was a nice idea, but led to security concerns. Advise on the best solution here: KISS would argue to just rephrase the comment : "Seems you want to run ." and stop here (enhanced, dynamic documentation, in a way, which is good). Or, really queue the command, ask for confirmation, and if user confirms, trigger the command → I would really like koan to be able to do that, but that must go through the natural workflow/gates/security of existing code paths. |
# Conflicts: # koan/app/config.py
Chat can now offer to run an eligible slash command and execute it on a one-word "yes" — including subcommands/args derived from the conversation (e.g. /recurring then /recurring run 3). Security: no new trigger path. A confirmed "yes" replays the *exact* literal command shown, through the existing handle_message -> handle_command pipeline, so every existing gate (channel filter, permission checks, pause/passive state) still applies. No LLM at confirmation time. - Per-skill opt-in via `chat_confirmable: true` in SKILL.md (mechanism, not a hardcoded list). Destructive commands are never eligible. - Tight affirmatives only; channel-bound, single-use, 5-min-TTL pending slot; injection-char rejection; rejected/garbage markers stripped before display. - Kill switch: chat.confirm_commands: false (prose suggestions stay on). - Opt-in set: 23 read-only/reversible core skills. Also fixes a pre-existing PERF401 lint error in recurring.py. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hard anti-fabrication guardrail
The model never emitted the SUGGEST_COMMAND marker and instead fabricated
actions ("je lance la mission… elle entre en Pending") because:
1. The catalog showed only each skill's FIRST command, so the force-run form
(/recurring run <n>) was invisible — the model saw only /daily. Rebuild the
catalog with a dedicated "Commands you can OFFER TO RUN" section listing each
confirmable skill's representative command WITH its real usage string, so the
model can construct the exact subcommand the human asked for.
2. The selection surfaced junk/dangerous non-⚡ commands and dropped key ones
(/status wasn't even listed). Split into a runnable ⚡ section and a prose-only
section.
3. The directive was weak ("you MAY offer") and buried mid-prompt. Add a hard,
last-word guardrail in chat.md: the chat cannot run/queue/launch anything and
must NEVER claim it did — only the marker + the human's "yes" runs anything.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… in validator Silences the spurious "[config] unrecognized key 'chat'" startup warning. The keys were already read correctly; this just teaches the validator their schema. Also includes the refined chat.md anti-fabrication guardrail wording. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@sukria-koan0 review |
Now implemented as confirm-to-run, not queue. Chat offers via |
PR Review — feat(chat): suggest matching slash commands from natural languageSolid confirm-to-run design; addresses prior feedback and the queuing concern. Merge-ready.
Checklist
Silent Failure Analysis🟡 **MEDIUM** — fallback value re-leaks marker on error (`koan/app/awake.py:478-481`)Risk: On any failure during suggestion processing the raw, unstripped reply is returned, so a stray Fix: On exception, fall back to a marker-stripped reply (e.g. 🟡 **MEDIUM** — fallback value hides empty-strip result (`koan/app/awake.py:465-467`)Risk: When the stripped reply is empty/whitespace, the Fix: Drop the Automated review by Kōan (Claude · model opus) |
|
Note: Would be nice to also support telegram group for such interactions and be able to reply |

Replace intent-routing/confirmation with simpler zero-cost approach.
Closes #1799
Quality Report
Changes: 24 files changed, 1504 insertions(+), 2011 deletions(-)
Code scan: clean
Tests: passed (403
tests)
Branch hygiene: clean
Generated by Kōan