- Replace process.exit(1) with process.exitCode + return in cmdWaitFor
to allow async CDP cleanup in finally blocks
- Fix cmdScroll enabling Runtime instead of Page domain
- Add BROWSEROS_EXTENSION_ID env var override for extension ID
- Align CLAUDE.md dev server command with SKILL.md canonical command
- Add snapshot vs screenshot guidance table — prefer snapshot for
structural checks, screenshot only for visual/layout verification
- Add server log checking instructions ([agent], [server], [build] tags)
- Add JS error checking via eval
- Add API connectivity verification
- Add common issues troubleshooting table
- Update all examples to use snapshot as default verification
Brings inspect-ui.ts to parity with server's MCP input tools:
- press_key: key combos like Enter, Control+A, Meta+Shift+P
(ported from keyboard.ts pressCombo)
- scroll: up/down/left/right with configurable amount
- hover: hover over element by ID for tooltip/hover state testing
- select_option: select dropdown option by value or visible text
(ported from browser.ts selectOption)
- wait_for: poll for text or CSS selector with 10s timeout
Updated skill documentation with new commands and examples.
Adds a Claude Code skill that lets the agent visually test both
surfaces of the BrowserOS extension:
- New tab page (app.html) — left sidebar with Home, Scheduled Tasks,
Settings, Skills, Memory, Soul, Connect Apps
- Right side panel (sidepanel.html) — chat interface
Includes all gotchas discovered through real testing: randomized ports,
fresh profile onboarding redirect, stale element IDs after navigation,
BrowserOS-specific sidePanel APIs, DOM.getDocument requirement.
- Remove Input.enable (domain has no enable method)
- Add DOM.getDocument before DOM operations (required by protocol)
- Use BrowserOS-specific sidePanel.browserosToggle API instead of
standard chrome.sidePanel.open (side panel starts disabled)
- Enable side panel with setOptions before toggling
- Use Delete key (not Backspace) to match server's keyboard.ts clearField
- Add windowId resolution to open-sidepanel (chrome.sidePanel.open requires it)
- Make target matching case-insensitive
- Replace process.exit(1) in eval with thrown error for proper cleanup
- Add comment referencing DEV_PORTS source of truth
The AI SDK can produce assistant messages with empty parts (parts:[]) when
a stream is aborted, and providers reject assistant messages with empty text
content. This adds a validation utility that filters both cases before
sending messages to createAgentUIStreamResponse and when persisting them.
Mintlify deploys docs by cloning the repo but does not run `git lfs
pull`. The `.gitattributes` rule `docs/images/** filter=lfs` caused
all doc images to be stored as ~130-byte LFS pointer files, which
Mintlify served as-is — breaking every image on the site.
Removing the LFS rule and re-adding the files as regular git blobs
fixes all images without changing any paths or MDX files.
Also fixes broken Slack link placeholder in troubleshooting page.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Images in docs/images/ are served as broken 130-byte placeholders by
Mintlify CDN. Co-locating images with the MDX file (matching the
working pattern in features/workflow/ and features/cowork/) bypasses
this issue. Also fixes the Slack link placeholder.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: fallback to default BrowserOS provider when provider is null
When the extension first loads, provider config is loaded async from
storage. If a chat request fires before loading completes (race
condition), provider is null and the server receives provider: undefined,
causing a Zod validation error. This adds a fallback to
createDefaultBrowserOSProvider() in both chat paths (sidepanel and
scheduled tasks) so provider.type is always defined.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: fallback to first provider when default provider ID is stale
When defaultProviderId in storage doesn't match any loaded provider
(e.g. after Kimi/Moonshot rollout), selectedProvider was null causing
provider: undefined in chat requests. Now falls back to providers[0].
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: repair stale defaultProviderId in storage on load
When the stored default provider ID doesn't match any loaded provider,
write back the corrected ID (providers[0].id) to storage so it doesn't
silently persist across sessions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Comment out non-working Canva and Exa integrations from the OAuth MCP
servers list and remove their imports/icon mappings from the UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: replace rate limit CTAs with Kimi/Moonshot partnership links
Comment out old "Learn more" and "take a quick survey" links on the
daily limit error banner. Replace with Kimi API key docs link and
direct Moonshot AI platform link for conversion tracking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove partnership tagline from rate limit banner
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The Docs link in the settings sidebar was using the Info icon (circle
with "i"). Changed it to BookOpen which is the standard icon for
documentation links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Track docs/images/** and docs/videos/** with Git LFS
- Add packages/browseros/build/tools/ to .gitignore
- Remove appimagetool-x86_64.AppImage from version control (downloaded on demand by build script)
* fix: scheduled task agent not using hidden window for new pages
The agent prompt only told the agent to pass windowId with `new_page`
but not `new_hidden_page`, which the agent prefers for background work.
The agent also had no instruction against closing or replacing its
dedicated hidden window, causing pages to scatter across uncontrolled
windows.
Expanded the scheduled task prompt rules to:
- Cover both `new_page` and `new_hidden_page` windowId requirement
- Forbid closing the dedicated hidden window
- Forbid creating new windows
- Added `new_hidden_page` to tool reference for MCP consumers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove duplicate hidden window creation from scheduled task frontend
The server's ChatService already creates a hidden window for scheduled
tasks (chat-service.ts:99-126), but the frontend (scheduledJobRuns.ts)
was also creating a minimized Chrome window that the server immediately
overwrote. This caused two windows to be created per scheduled task run,
with only one being used.
Removed from scheduledJobRuns.ts:
- chrome.windows.create() call
- 1-second race condition delay hack (FIXME)
- chrome.windows.remove() cleanup
- windowId/activeTab params to getChatServerResponse()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* chore: bump server version
* fix: remove dead getCdpToolReference and unused prompt exports
The getCdpToolReference function was always excluded by the AI SDK agent
(tool schemas are injected by the SDK itself) and never used by the MCP
server (which has its own MCP_INSTRUCTIONS). Also removes unused exports
getSystemPrompt and PROMPT_SECTION_KEYS.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* chore: bump server version
* fix: move session dirs to ~/.browseros/sessions and update skill paths
Session directories now live under ~/.browseros/sessions/{conversationId}/
instead of executionDir/sessions/. Adds 30-day cleanup for stale sessions
at server startup. Updates 6 default skills to reference the working
directory instead of hardcoding ~/Downloads/.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: rename sessionExecutionDir to workingDir across server
Consistent naming for the per-conversation working directory:
- ResolvedAgentConfig.sessionExecutionDir → workingDir
- ToolDirectories.executionDir → workingDir
- resolveExecutionPath() → resolveWorkingPath()
- buildBrowserToolSet param: executionDir → workingDir
Server-level executionDir (DB, logs) unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review — restore emoji folder name, refresh session mtime
- Revert "Read Later" back to "📚 Read Later" to avoid creating
duplicate bookmark folders for existing users
- Touch session dir mtime on each message via utimes() so cleanup
correctly reflects last activity, not just directory creation time
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review round 2 — remove dead executionDir, fix emoji
- Remove executionDir from ChatServiceDeps and ChatRouteDeps since
resolveSessionDir now uses getSessionsDir() directly
- Fix missed emoji in notification format template
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
safeSkillDir() used a hardcoded `/` in the startsWith path traversal
check. On Windows, path.resolve() returns backslash paths, so the check
always failed — blocking getSkill, createSkill, updateSkill, deleteSkill.
Replace `${skillsDir}/` with `${skillsDir}${sep}` using path.sep from
node:path, which returns `\` on Windows and `/` on POSIX.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: persist default kimi hub provider to BrowserOS prefs on first load
When VITE_PUBLIC_KIMI_LAUNCH is enabled, loadProviders() returned default
Kimi provider in-memory but never saved it to the BrowserOS pref. The
browser's C++ code reads the pref directly and found it empty, so Kimi
didn't appear in the toolbar until the user manually edited and saved.
Now loadProviders() persists defaults and ensureKimiFirst() additions to
the pref, keeping the browser in sync with what the extension UI shows.
Fixes#428
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use reference equality for ensureKimiFirst change detection
Address PR review: reference check (normalized !== providers) is more
semantically precise than length comparison since ensureKimiFirst returns
the same reference when unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Return a friendly JSON response when users curl GET /mcp instead of
an opaque 503. Narrows the catch-all .all() to .post() since the MCP
Streamable HTTP transport only needs POST for stateless servers.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add missing patches to features.yaml
Add 37 patch files from chromium_patches/ that were not tracked in
features.yaml. Creates 3 new features (cdp-api, vertical-tabs,
crash-reporter) and adds missing files to 3 existing features
(chromium-ui-fixes, side-panel-fixes, first-run).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: split sparkle third-party from mac-sparkle-updater
Move third_party/sparkle/ into its own feature since the Sparkle
framework is downloaded on-the-fly during build, not a permanent
patch in the tree.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: minor
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Skills page navigation is now hidden when the server version is below
0.0.73, matching the gating pattern used for Memory, Soul, and Workflows.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: move skills into main page navigation
Mirror the soul move pattern (166f6e1b) — promote Skills from
settings sidebar to primary navigation at /home/skills. Adds
backward-compat redirect from /settings/skills.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove missing dismiss-popups skill reference
The SKILL.md file doesn't exist on disk, causing a module
resolution error at server startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: bootstrap 12 default agent skills for new users
Seed common browser automation skills (summarize, research, extract data,
fill forms, dismiss popups, screenshots, organize tabs, compare prices,
save page, monitor changes, read later, manage bookmarks) into
~/.browseros/skills/ on first startup when no user skills exist.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: populate skill edit dialog with existing content
The edit dialog form fields were empty because Radix Dialog's
onOpenChange doesn't fire when the open prop changes programmatically.
Replace the handleOpenChange wrapper with a useEffect that syncs form
state whenever editingSkill changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: correct tool names in default skill instructions
- memory_save → memory_write (actual tool name in memory toolset)
- delete_bookmark → remove_bookmark (actual tool name in registry)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: move skill content from TS template literals to separate SKILL.md files
Replace the monolithic defaults.ts (738-line file with escaped template
literals) with individual SKILL.md files per skill. Uses Bun's text
import (`with { type: 'text' }`) to inline content at bundle time.
Adds md.d.ts for TypeScript module resolution.
Much easier to read and edit skill content as plain markdown.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add build:server:test and start:server:test scripts for local binary testing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: refresh agent skills settings UI
* fix: address PR review comments for 0311-skills_ui_refresh
* feat: enhance default skills with file persistence, HTML reports, and add find-alternatives
Rewrite deep-research, extract-data, compare-prices, manage-bookmarks, and
read-later skills to follow a structured phase-based workflow. Key changes:
- All research skills now save data incrementally to disk instead of
accumulating in memory
- Add HTML report generation (light theme) with source links for
deep-research, extract-data, and compare-prices
- Use hidden windows and parallel tabs (max 10) for multi-source extraction
- Simplify read-later to just bookmark + PDF save
- Simplify manage-bookmarks to max 3-5 top-level folders with confirmation
- Add new find-alternatives skill for product alternative research with
1-5 star ranking
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: simplify skills page rendering
* fix: clean-up skill
* fix: address review feedback for PR #478
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>