Skip to content

feat: migrate Claude Code to Theia native slash commands and modes#16541

Merged
planger merged 2 commits intomasterfrom
planger/add-claude-code-modes
Nov 26, 2025
Merged

feat: migrate Claude Code to Theia native slash commands and modes#16541
planger merged 2 commits intomasterfrom
planger/add-claude-code-modes

Conversation

@planger
Copy link
Contributor

@planger planger commented Nov 5, 2025

What it does

This PR migrates Claude Code to use Theia's native slash command and mode infrastructure, replacing custom Monaco-based completion providers with platform-standard implementations.

  1. Native Slash Command Support: Migrates from a custom Monaco completion provider to Theia's PromptService for registering slash commands

    • Static commands (clear, compact, config, init, memory, review, resume) are registered at startup
    • Dynamic commands are loaded from .claude/commands/*.md files with live file watching
  2. Dynamic Command Management: Implements file system watching for .claude/commands/ directory

    • Automatically registers new commands when .md files are added
    • Updates commands when files are modified
    • Removes commands when files are deleted
    • Handles workspace changes by clearing and re-registering commands
  3. Mode Support: Adds three operational modes to the Claude Code chat agent

    • "Ask before edit" (default): Requests permission for file modifications
    • "Edit automatically": Automatically applies suggested changes
    • "Plan mode": Plans changes without executing them
    • Integrates with Theia's native ChatAgent.modes interface

How to test

Testing Slash Commands:

  1. Open the chat view

  2. Type @ClaudeCode / and verify all static commands appear (clear, compact, config, init, memory, review, resume)

  3. Create a .claude/commands/ directory in your workspace

  4. Add a markdown file (e.g., test.md) with command description

  5. Verify the command appears in the slash command list without restarting

  6. Modify the file name and verify the command updates

  7. Delete the file and verify the command is removed

  8. Switch to a different workspace and verify commands update accordingly

  9. Type @ClaudeCode / and verify all static commands work (clear, compact, config, init, resume, ...)

  10. Try if custom commands work

Testing Modes:

  1. Open the chat view and type @ClaudeCode
  2. Locate the mode selector (should show three modes)
  3. Test "Ask before edit" mode: Send a request that would modify files and verify permission prompts appear
  4. Test "Edit automatically" mode: Send a request and verify changes are applied without prompting
  5. Test "Plan mode" mode: Send a request and verify it plans without executing

Follow-ups

Breaking changes

  • This PR introduces breaking changes and requires careful review. If yes, the breaking changes section in the changelog has been updated.

Attribution

Review checklist

Reminder for reviewers

Copy link
Member

@sdirix sdirix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change works for me. Great work 👍

I left some comments about the code. All of them are nitpicks and can be ignored, handled later or be applied to this PR.

I performed all suggested tests. Generally speaking they succeeded for me, but there are some rough edges:

Changing modes

The Claude Code modes work, however changing the mode while a request is in process does not work. Even if the request is stopped because Claude Code asks for an approval, the new mode will not be respected by Claude Code until there is an actual new request from the user.

As we start in "Ask before edit" mode, the user will typically encounter an approval message pretty quick. Then they change the mode and click approve, still all further changes need to be manually improved

ExitPlanTool

Claude Code has an ExitPlanTool it tries to use to exit plan mode (after approval from the user). This fails and the user has to change the mode manually afterwards to continue

Image

"Ask before edit" does not populate the change set

The "Ask before edit" asks for edit approval before doing any edits. However the approved edits do not show up in the changeset. Therefore there is no convenient way of directly seeing the edits of what Claude Code did compared to the "Edit automatically" mode

Custom commands request rendering

This "regression" is not caused by this PR. However it seems very weird to me that the Claude Code commands are rendered as #prompt in the request, e.g.

Image

Mode preference?

Personally I don't like that I need to change the mode for Claude Code in every new chat session. There should be some way to avoid this, for example via a preference.


None of these are deal breakers, so we can merge as is. However please capture these remarks as follow ups in case you don't tackle them here.

Comment on lines +397 to +408
const modeId = request.request.modeId ?? 'default';
switch (modeId) {
case 'acceptEdits':
return 'acceptEdits';
case 'plan':
return 'plan';
case 'bypassPermissions':
return 'bypassPermissions';
case 'default':
default:
return 'default';
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a bit clunky... should we instead have an array of allowed modes and check whether the request.modeId is contained in them?

commandAgents: [CLAUDE_CHAT_AGENT_ID]
});
} catch (error) {
console.error(`Failed to register dynamic command ${commandName}:`, error);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mention claude code in this error message so it's easier to understand for readers what is going on. Bonus points for using a named logger instead.


protected getWorkspaceRoot(): URI | undefined {
const roots = this.workspaceService.tryGetRoots();
return roots.length > 0 ? roots[0].resource : undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should create a follow up to properly support multi root workspaces

Comment on lines +403 to +404
case 'bypassPermissions':
return 'bypassPermissions';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bypassPermissions is currently not on any code path, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true

@github-project-automation github-project-automation bot moved this from Waiting on reviewers to Needs merge in PR Backlog Nov 25, 2025
- Replace custom Monaco completion provider with PromptService-based commands
- Add support for dynamic .claude/commands/*.md files with live file watching
- Implement workspace-aware file monitoring
- Add mode support in Claude Code chat agent
@planger planger force-pushed the planger/add-claude-code-modes branch from b554327 to e3496d1 Compare November 26, 2025 20:45
@planger
Copy link
Contributor Author

planger commented Nov 26, 2025

Thanks for the great review @sdirix!

I've addressed your inline comments and rebased and tracked all follow-ups in #16334.

@planger planger merged commit f320692 into master Nov 26, 2025
10 checks passed
@github-project-automation github-project-automation bot moved this from Needs merge to Done in PR Backlog Nov 26, 2025
@planger planger deleted the planger/add-claude-code-modes branch November 26, 2025 21:09
@github-actions github-actions bot added this to the 1.67.0 milestone Nov 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

2 participants