Repository navigation
feat(mod): run a built-in slash command the user asks the session for - #60
Merged
Merged
Conversation
Told to run /compact, the model answered that it could not: the Skill tool refuses a built-in. hooks/self-command.js takes that refusal and queues the command with $.command.run from a timer, so it runs on the session itself once the asking turn ends; the Skill tool's description says so. /model and /effort are refused, since run this way they become every session's default. A tool of the mod's own is not possible: $.tool.register refuses mcp__lich__* in a session whose MCP config has lich's server.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lets a Claude Code session inside lich run one of its own built-in slash commands when the user asks for it ("run /compact"). This is plugin-only. Nothing goes through lich, whose
controlrefuses a session acting on itself on purpose (lichdocs/ceilings.md, "A session cannot control itself").Design
hooks/self-command.js(registered byhooks/lich.js) works through the Skill tool, the tool the model already reaches for:tool.describeonSkillappends one paragraph saying a built-in slash command can be named there when the user asks, and that it runs once the turn ends.tool.callonSkillruns the native tool first, so skills and the built-ins it serves as prompts (/init,/review) stay its own. The mod steps in only when that call errored and$.command.list()names the command asbuiltin. It then answers in the Skill tool'sinlineshape ({ success, commandName }), with a context note saying the command is queued and the turn should end. It calls$.command.runfrom$.clock.after(0), because$.command.runrejects inside a hook the turn is waiting on. The command runs once the session is idle, after the turn that asked for it./modeland/effortget adenythat points at lich's per-session override, and never run. Through a mod, Claude Code saves them as the default for every new session.LICH_SESSION_IDset in an interactive session.Measured (Claude Code 2.1.295)
mcp__lich__<name>, and$.tool.registerrefuses withthe session already has an MCP server named "lich" in its MCP config; registering would replace it. That covers every lich session.Skill(compact)returnsisErrorwithcompact is a built-in CLI command, not a skill….--plugin-dir, lich's MCP server in the config, the same prompt): the model calledSkill(compact)and said it would run once the turn ended. The turn ended, and/compactthen ran and compacted the conversation. Claude Code accepted theinlineresult./model,/effortand/costwere not run live.Known ceilings (in
docs/self-command.md)/cost) holds the command queue until Esc is pressed.$.command.list()cannot tell such commands apart, so none is refused.Changes
hooks/self-command.js, registered inhooks/lich.js.docs/self-command.md, plusCLAUDE.md,README.md,docs/providers.md, and CHANGELOG under[Unreleased]› Added.tests/self-command.test.mjs(9) andtests/self-command.engine.test.ts(2). The kit has nocommand.list, so a test hook stands in for the session's list.No version bumped.
Tests
node --test tests/*.test.mjs: 372 pass, 0 fail.claude plugin test .: 31 pass, 0 fail.claude plugin validate .claude-plugin/plugin.json: passes. The only warnings are ones that already existed, plus a "gating hook without .catch" warning on the newtool.callhook, the same one every other mod already gets.