-
Notifications
You must be signed in to change notification settings - Fork 1
Add kernel claude command group for Claude extension support
#59
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: main
Are you sure you want to change the base?
Conversation
Implement a complete workflow for using the Claude for Chrome extension in Kernel browsers: Commands: - kernel claude extract: Extract extension + auth from local Chrome - kernel claude launch: Create browser with Claude pre-loaded - kernel claude load: Load extension into existing browser - kernel claude status: Check extension/auth status - kernel claude send: Send single message (scriptable) - kernel claude chat: Interactive TUI chat session Features: - Cross-platform Chrome path detection (macOS, Linux, Windows) - Bundle format with extension and auth storage - Embedded Playwright scripts for browser automation - Scriptable send command with stdin/file/JSON support - Interactive chat with /help, /status, /clear commands
Add retry loop to poll GET /browsers/:id after creation to handle eventual consistency before attempting to load the extension.
The LevelDB files inside the auth storage directory need to be owned by the kernel user, not just the directory itself. Use process exec with chown -R to fix the LOCK file access denied errors.
- Add pinExtension() to update Chrome's Preferences file with the extension ID in pinned_extensions array - Restart Chromium via supervisorctl to pick up the new preference - Use Spawn (fire and forget) since supervisorctl restart takes time
Chrome overwrites the Preferences file on exit, so we need to: 1. Stop Chromium via supervisorctl stop 2. Update the Preferences file with pinned_extensions 3. Start Chromium via supervisorctl start This ensures Chrome reads our updated Preferences on startup.
The Claude extension opens claude.ai by default, which shows a login prompt. After loading the extension and restarting Chrome, navigate all tabs to chrome://newtab for a cleaner initial state.
The Claude extension opens a second tab to claude.ai. Close all but the first tab before navigating to chrome://newtab.
The SDK's Playwright.Execute has built-in retry, so we can fire and forget the supervisorctl start command instead of waiting for it.
| pterm.Info.Println(" 2. The Claude for Chrome extension is installed") | ||
| pterm.Info.Println(" 3. You're using the correct Chrome profile (use --list-profiles to see available profiles)") | ||
| return nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extract command returns success on extension not found
When GetChromeExtensionPath fails (Chrome or extension not installed), the function prints error messages via pterm.Error but then returns nil instead of the error. This causes the command to exit with status code 0 (success), which breaks scripting and automation workflows that check exit codes. Other error handling in the same function correctly uses return fmt.Errorf(...). This should return the error or a wrapped version of it.
| return err | ||
| } | ||
| continue | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Symlink target not validated during zip extraction
The unzip function validates destPath against zip-slip attacks (line 195-196), but when extracting symlinks, the linkTarget read from the zip file is not validated. A malicious bundle could contain a symlink like extension/config -> /etc/passwd that passes the destination path check but points outside the extraction directory. When files are later read through this symlink, sensitive files could be accessed or overwritten.
| pterm.Info.Printf("Navigating to: %s\n", startURL) | ||
| _, err := client.Browsers.Playwright.Execute(ctx, browser.SessionID, kernel.BrowserPlaywrightExecuteParams{ | ||
| Code: fmt.Sprintf(`await page.goto('%s');`, startURL), | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL not escaped in JavaScript code execution
The startURL is directly interpolated into JavaScript code using string formatting without proper escaping. If a URL contains single quotes or is crafted maliciously (e.g., http://x'); malicious_code(); //), it can break out of the string literal and execute arbitrary JavaScript in the Playwright context. The code uses fmt.Sprintf with '%s' but doesn't escape the URL first using something like jsonMarshalString which is available and used elsewhere in this codebase.
The Playwright execution API expects inline code, not CommonJS modules. Remove the async function wrapper and module.exports, making the scripts execute directly in the Playwright context.
- Use div.claude-response for Claude's response messages - Use [contenteditable].ProseMirror for the chat input - These match the actual DOM structure of the Claude extension
Slash commands in Claude require an extra Enter press to confirm. Detect if message starts with '/' and press Enter a second time.
Instead of navigating to the sidepanel URL (which opens it as a broken full tab), click on the pinned extension icon at coordinates (1775, 55) to open the proper side panel. - Add OpenSidePanel() function that uses Computer.ClickMouse API - Add ExtensionIconX/Y constants for the click coordinates - Update send, status, and chat commands to call OpenSidePanel first - Update Playwright scripts to wait for the side panel to appear instead of trying to navigate to it
| return client.Browsers.Computer.ClickMouse(ctx, browserID, kernel.BrowserComputerClickMouseParams{ | ||
| X: ExtensionIconX, | ||
| Y: ExtensionIconY, | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded click coordinates fail for non-1920x1080 viewports
OpenSidePanel uses hardcoded coordinates (ExtensionIconX = 1775, ExtensionIconY = 55) that are explicitly documented as being for 1920x1080 resolution. When users launch a browser with a different viewport via the --viewport flag (e.g., 1280x720), the extension icon will be at a different X position. The click will miss the icon entirely (or click outside the visible area), causing send, chat, and status commands to fail to open the side panel.
Additional Locations (1)
Check if a page with sidepanel.html exists before clicking. This prevents accidentally clicking the extensions button when the side panel is already visible.
Claude for Chrome has its own slash commands (like /hn-summary). Only handle /quit, /exit, /clear locally; pass everything else to Claude.
Summary
Adds a new
kernel claudecommand group that provides a complete workflow for using the Claude for Chrome extension in Kernel browsers:Usage
Step 1: Extract the extension from your local Chrome (run on your Mac/Linux machine with Chrome)
Step 2: Launch a Kernel browser with Claude pre-loaded
Step 3: Interact with Claude
Loading into existing browser
Implementation Details
browsers.LoadExtensions,browsers.Fs,browsers.Process,browsers.Playwrightsend_message.js,check_status.js,stream_chat.js)chrome://newtabTest plan
kernel claude extractworks on macOS/Linux with Chrome installedkernel claude launchcreates browser with extension loaded and pinnedkernel claude loadloads extension into existing browserkernel claude statusreports extension statekernel claude sendsends messages and receives responseskernel claude chatprovides interactive TUINote
Adds a focused CLI workflow to run the Claude for Chrome extension inside Kernel browsers.
kernel claudecommand group:extract,launch,load,status,send,chatbrowsers.LoadExtensions,browsers.Fs,browsers.Process,browsers.Playwright) to upload/pin the extension, open the side panel, and automate chatinternal/claude:bundle.go(zip bundle create/extract),paths.go(Chrome/extension paths, profile discovery),loader.go(load/pin, auth storage upload), constants, and embedded scripts (scripts/send_message.js,scripts/check_status.js,scripts/stream_chat.js)cmd/root.goand documents usage inREADME.mdWritten by Cursor Bugbot for commit ef81888. This will update automatically on new commits. Configure here.