Skip to content

feat(vscode): integrate world browser automation - #12754

Open
IamCoder18 wants to merge 3 commits into
Kilo-Org:mainfrom
IamCoder18:feat/world-vscode
Open

feat(vscode): integrate world browser automation#12754
IamCoder18 wants to merge 3 commits into
Kilo-Org:mainfrom
IamCoder18:feat/world-vscode

Conversation

@IamCoder18

@IamCoder18 IamCoder18 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Context

The native World tool should be available consistently in VS Code without the extension maintaining a separate Playwright MCP process. This PR replaces that older integration with the CLI-owned runtime from the preceding PRs, adds settings for the native browser, and renders World screenshots directly in chat.

Part of #12751.

Depends on #12753 and #12752. Until those PRs merge, review the focused VS Code-layer diff; GitHub will then reduce this PR’s Files changed tab to this layer automatically.

Implementation

I, a human, have manually reviewed every change in this PR.

Remove the extension-managed Playwright MCP service and its VS Code settings. The Browser settings page now writes directly to Kilo configuration, where World is enabled by default, runs headless by default, and can optionally use an installed Chrome with Chromium fallback. The experimental settings page exposes the same enable/disable flag, and all affected copy is translated across the 20 supported locales.

Package the World daemon beside every extension CLI binary and include it in local binary freshness checks, resource copying, and source watching. Chat registers a focused World renderer that shows action metadata and inline screenshot attachments with full-size preview support.

Update the changeset introduced in PR 2 to include the VS Code extension and describe the complete user-facing workflow.

Screenshots / Video

Headless

world_vscode_windows_headless.mp4

Headed

world_vscode_windows_headed.mp4

How to Test

Manual/local verification

  • Ran extension typecheck, lint, compile, unused-export checks, and the Kilo marker guard successfully.
  • Ran the 35 companion-resource tests successfully, including daemon manifest copying, missing-daemon rejection, and Windows path handling.
  • Ran the full unit suite: 3,662 tests passed; one unrelated Agent Manager test fails reproducibly on this checkout because Git reports a freshly cloned branch as local-tracking instead of remote.

Reviewer test steps

  1. From packages/opencode, run bun run script/build.ts --single --skip-install.
  2. From packages/kilo-vscode, run bun run extension --no-build, or use the normal extension development launch with the built CLI.
  3. Open Settings → Browser and confirm World is enabled and headless by default.
  4. Toggle headless mode and system Chrome, then confirm the corresponding Kilo configuration updates.
  5. Ask Kilo to navigate to a local web app and interact with it using World.
  6. Confirm each visual action shows an inline screenshot in chat and clicking it opens the full-size preview.
  7. Disable World and confirm browser capabilities disappear from the agent.

Checklist

  • Issue linked above, or exception explained
  • Tests/verification described
  • Screenshots/video included for visual changes, or marked N/A
  • Changeset considered for user-facing changes
  • I personally reviewed the diff and can explain the changes, including any AI-assisted work.

Get in Touch

Discord: @IamCoder18

Comment thread packages/kilo-vscode/webview-ui/src/components/chat/WorldToolRenderer.tsx Outdated
Comment thread packages/kilo-vscode/webview-ui/src/components/chat/WorldToolRenderer.tsx Outdated
Comment thread packages/kilo-vscode/webview-ui/src/i18n/en.ts
Comment thread packages/kilo-vscode/script/build.ts
Comment thread packages/kilo-vscode/src/services/cli-backend/cli-resources.ts
Comment thread packages/kilo-world/src/daemon/dispatch.ts Outdated
Comment thread packages/kilo-world/src/core/browser/runner.ts Outdated
Comment thread packages/kilo-world/src/commands/browser/drag.ts Outdated
Comment thread packages/kilo-world/src/daemon/server.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Incremental review of 04622f47 -> 9f6b42d8: pure rebase — both commits have identical trees (e22bf885af14), so the increment introduces no content changes. No new findings; the review state from the previous summary is unchanged.

Files Reviewed (0 files in the incremental diff)

The incremental range contains no file changes. Findings from earlier reviews remain on the PR as existing inline comments.

Previous Review Summaries (10 snapshots, latest commit 04622f4)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 04622f4)

Status: No Issues Found | Recommendation: Merge

Incremental review of 405bbeb5 -> 04622f47: pure rebase — both commits have identical trees (e22bf885af14), so the increment introduces no content changes. No new findings; the review state from the previous summary is unchanged.

Files Reviewed (0 files in the incremental diff)

The incremental range contains no file changes. Findings from earlier reviews remain on the PR as existing inline comments.

Previous review (commit 405bbeb)

Status: No Issues Found | Recommendation: Merge

Incremental review of 43471b59 -> 405bbeb5: pure rebase — both commits have identical trees (e22bf885af14), so the increment introduces no content changes. No new findings; the review state from the previous summary is unchanged.

Files Reviewed (0 files in the incremental diff)

The incremental range contains no file changes. Findings from earlier reviews remain on the PR as existing inline comments.

Previous review (commit 43471b5)

Status: No Issues Found | Recommendation: Merge

Incremental review of fe1e3bc8 -> 43471b59: pure rebase — both commits have identical trees, so the increment introduces no content changes. No new findings; the review state from the previous summary is unchanged.

Files Reviewed (0 files in the incremental diff)

The incremental range contains no file changes. Findings from earlier reviews remain on the PR as existing inline comments.

Previous review (commit fe1e3bc)

Status: No Issues Found | Recommendation: Merge

Incremental review of 696c31c3 -> fe1e3bc8. The PR was rebased onto current main (6ec20f2, a docs-sync fix); the author-owned increment is confined to the daemon build lock/fingerprint path (3 files, ~70 lines). Both findings from the previous review are resolved:

  • build-daemon.tsalive() now treats a lock older than LOCK_TIMEOUT_MS as dead before consulting the pid, so a stale lock whose pid was recycled by an unrelated process is reclaimed after one timeout window instead of failing every build for as long as that process lives. Using the full 90s ceiling rather than the old 5s "recent" window keeps the busy-holder false-steal risk low.
  • build.ts — the fingerprint now hashes only the playwright spec, the resolved playwright/playwright-core lock entries, and playwright-scoped patches instead of the entire bun.lock. The 4-space package-entry lookup was verified against the real lockfile, and the new test in build.test.ts locks in the narrower invalidation behavior.
Files Reviewed (3 files in the incremental diff)
  • packages/kilo-world/script/build-daemon.ts - 0 issues (previous WARNING resolved)
  • packages/kilo-world/src/daemon/build.ts - 0 issues (previous SUGGESTION resolved)
  • packages/kilo-world/test/build.test.ts - 0 issues

The .github/docs-sync/* changes in the 696c31c3..fe1e3bc8 range come from the rebase onto main and are not part of this PR. Findings from earlier reviews on files outside this increment are not repeated here; their existing inline comments remain on the PR.

Previous review (commit 696c31c)

Status: 2 Issues Found | Recommendation: Address before merge

Incremental review of 3e5a991e -> 696c31c3. The PR was rebased onto current main; the author-owned increment is confined to the daemon build/lock/lifecycle path (4 files, ~170 lines). All five previous findings are resolved: responsive() retries the ping before tearing down a stalled daemon, alive() no longer requires a fresh heartbeat, terminate() can now attribute and stop inherited daemons via process start time, the playwright catalog lookup is fail-closed against bun.lock, and close covers spawn failures. The increment introduces the two findings below.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-world/script/build-daemon.ts 86 a stale lock whose pid was recycled by an unrelated process now blocks every build until the 90s timeout and then fails, for as long as that process lives

SUGGESTION

File Line Issue
packages/kilo-world/src/daemon/build.ts 61 hashing all of bun.lock invalidates the daemon build on any monorepo dependency change, not just playwright resolution changes
Files Reviewed (4 files in the incremental diff)
  • packages/kilo-world/script/build-daemon.ts - 1 issue
  • packages/kilo-world/src/daemon/build.ts - 1 issue
  • packages/kilo-world/src/daemon/client.ts - 0 issues
  • packages/kilo-world/test/build.test.ts - 0 issues

The remaining files in the 3e5a991e..696c31c3 range are main-branch changes pulled in by the rebase (chart/send_file tools, agent-manager, speech-to-text, i18n) and are not part of this PR. Findings from earlier reviews on files outside this increment are not repeated here; their existing inline comments remain on the PR.

Fix these issues in Kilo Cloud

Previous review (commit 3e5a991)

Status: 5 Issues Found | Recommendation: Address before merge

Incremental review of 71692a35 -> 3e5a991e. The increment touches only the daemon build/lock/lifecycle path (4 files, ~104 lines) and resolves three previously reported findings: the STAMP/manifest rename order, the hardcoded manifest filename, and the 2s build-failure cooldown (now 30s). The new lock heartbeat and terminate() escalation introduce the findings below.

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-world/src/daemon/client.ts 517 one missed 500ms __ping__ now escalates straight to terminate() in both apply() and ensureRunning(), so a transient stall kills a correctly configured daemon and discards the browser context it exists to preserve
packages/kilo-world/script/build-daemon.ts 87 alive() now requires a heartbeat within 5s in addition to a live pid, so a holder whose event loop is busy loses its lock; the stealing process's clean() then deletes the in-flight staging dir
packages/kilo-world/src/daemon/client.ts 559 terminate() only escalates for daemons spawned by the current process, so a daemon inherited from an earlier CLI/extension process that is alive but not answering HTTP still has no recovery path — ensureRunning() and apply() just throw until the idle timeout expires

SUGGESTION

File Line Issue
packages/kilo-world/src/daemon/build.ts 52 the catalog lookup fails open to the literal "catalog:" string, and the playwright signal is now the declared spec rather than the installed package, so a reinstall or patch no longer invalidates dist/
packages/kilo-world/src/daemon/client.ts 231 exit is not emitted when the spawn itself fails, so a failed launch leaves the ChildProcess in children for the process lifetime; close covers both cases
Files Reviewed (4 files in the incremental diff)
  • packages/kilo-world/src/daemon/client.ts - 3 issues
  • packages/kilo-world/script/build-daemon.ts - 1 issue
  • packages/kilo-world/src/daemon/build.ts - 1 issue
  • packages/kilo-world/script/daemon.ts - 0 issues

Findings from earlier reviews on files outside this incremental diff are not repeated here; their existing inline comments remain on the PR.

Fix these issues in Kilo Cloud

Previous review (commit 71692a3)

Status: 6 Issues Found | Recommendation: Address before merge

Incremental review of 016e7bae -> 71692a35. The branch was rebased from 0aabd47b onto c5544090; the PR's own patch is byte-identical to the previously reviewed one, so no new code was introduced. No new inline comments were posted. The findings below were re-verified against current HEAD.

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 3
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-world/script/build-daemon.ts 39 STAMP is still renamed before the manifest, so a build interrupted between the two renames leaves a fresh stamp beside a stale manifest that fresh() accepts forever, and manifest-driven copyWorldDaemon then ships the wrong chunk set
packages/kilo-world/src/daemon/client.ts 506 apply() has no recovery path for a daemon that is alive but not answering HTTP: it throws on every later call while DaemonServer.start refuses as long as the pid lives
packages/kilo-vscode/script/build.ts 87 the extension ships the daemon and its assets but no Chromium, while packages/opencode/src/kilocode/tool/registry.ts:239 still advertises the tool on experimental.world_browser !== false with no browser-availability gate, so a user with no Chrome-family browser and no local Playwright Chromium gets a launch failure instead of a hidden tool

SUGGESTION

File Line Issue
packages/kilo-world/src/daemon/build.ts 23 require.resolve("playwright/package.json") is unguarded and runs before any fallback, so an unresolvable Playwright breaks the world tool even when dist/world-daemon.cjs is present and fresh
packages/kilo-world/src/daemon/client.ts 49 the manifest filename is hardcoded ("world-daemon.assets.json") instead of shared with WorldDaemon.manifest; drift silently costs a full build spawn per call
packages/kilo-world/src/daemon/client.ts 50 the 2s BUILD_FAILURE_COOLDOWN_MS lets a permanent build failure re-run the full bundle + smoke on nearly every world call
Files Reviewed (0 files in the incremental diff)

The incremental range contains only the rebase onto new main (.changeset/fair-subagents-route.md, JetBrains changelog/version, subagent routing config and test). None of those files are authored by this PR, so they were excluded from review scope.

Fix these issues in Kilo Cloud

Previous review (commit 016e7ba)

Status: 6 Issues Found | Recommendation: Address before merge

Incremental review of dd774df -> 016e7bae. The only change is packages/kilo-world/test/daemon.test.ts, which now creates the nested node_modules directory before mkdtempSync. No new issues in this increment; the findings below were re-verified against current HEAD.

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 3
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-world/script/build-daemon.ts 40 STAMP is still renamed before the manifest, so a build interrupted between the two renames leaves a fresh stamp beside a stale manifest that fresh() accepts forever, and manifest-driven copyWorldDaemon then ships the wrong chunk set
packages/kilo-world/src/daemon/client.ts 513 apply() has no recovery path for a daemon that is alive but not answering HTTP: it throws on every later call while DaemonServer.start refuses as long as the pid lives
packages/kilo-vscode/script/build.ts 87 the extension ships the daemon and its assets but no Chromium, while packages/opencode/src/kilocode/tool/registry.ts:239 still advertises the tool on experimental.world_browser !== false with no browser-availability gate, so a user with no Chrome-family browser and no local Playwright Chromium gets a launch failure instead of a hidden tool

SUGGESTION

File Line Issue
packages/kilo-world/src/daemon/build.ts 23 require.resolve("playwright/package.json") is unguarded and runs before any fallback, so an unresolvable Playwright breaks the world tool even when dist/world-daemon.cjs is present and fresh
packages/kilo-world/src/daemon/client.ts 49 the manifest filename is hardcoded ("world-daemon.assets.json") instead of shared with WorldDaemon.manifest; drift silently costs a full build spawn per call
packages/kilo-world/src/daemon/client.ts 50 the 2s BUILD_FAILURE_COOLDOWN_MS lets a permanent build failure re-run the full bundle + smoke on nearly every world call
Verified fixed in this increment
  • test/daemon.test.ts now calls mkdirSync(dir, { recursive: true }) before mkdtempSync, so the runner-under-Node test no longer throws ENOENT on hoisted install layouts with no nested node_modules.
Files Reviewed (1 file in the incremental diff)
  • packages/kilo-world/test/daemon.test.ts - no new issues

Fix these issues in Kilo Cloud

Previous review (commit dd774df)

Status: 7 Issues Found | Recommendation: Address before merge

Incremental review of 11c11af -> dd774df (6 files, all in packages/kilo-world/ plus .gitignore). This increment makes the build fingerprint async and Playwright-aware, moves the freshness gate behind the build lock, adds a client-side fresh() fast path plus a 2s failure cooldown, detaches the build child so the whole process group can be killed on timeout, bounds the smoke daemon with --idle=15000 + KILO_WORLD_PARENT_PID, and removes the kill escalation from apply(). 6 new findings; 1 earlier finding is still open.

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 4
New in this increment (6 issues)

WARNING

File Line Issue
packages/kilo-world/script/build-daemon.ts 40 the manifest is renamed after STAMP, so a build interrupted between the two renames leaves a fresh stamp beside a stale manifest that fresh() accepts forever, and manifest-driven copyWorldDaemon then ships the wrong chunk set
packages/kilo-world/src/daemon/client.ts 513 dropping the escalation leaves no recovery path for a daemon that is alive but not answering HTTP: apply() throws on every later call and DaemonServer.start refuses while the pid lives

SUGGESTION

File Line Issue
packages/kilo-world/src/daemon/build.ts 23 require.resolve("playwright/package.json") is unguarded and runs before any fallback, so an unresolvable Playwright breaks the world tool even when dist/world-daemon.cjs is present and fresh
packages/kilo-world/src/daemon/client.ts 49 the manifest filename is hardcoded instead of shared with WorldDaemon.manifest; drift silently costs a full build spawn per call
packages/kilo-world/src/daemon/client.ts 50 a 2s cooldown lets a permanent build failure re-run the full bundle + smoke (up to 150s) on nearly every world call
packages/kilo-world/test/daemon.test.ts 183 mkdtempSync into packages/kilo-world/node_modules throws ENOENT on hoisted install layouts where no nested node_modules exists
Still open from earlier reviews (1 issue)

WARNING

File Line Issue
packages/kilo-vscode/script/build.ts 87 re-verified at HEAD: the extension ships the daemon and its assets but no Chromium, while kilocode/tool/registry.ts:239 still advertises the tool on experimental.world_browser !== false with no browser-availability gate, so a user with no Chrome-family browser and no local Playwright Chromium gets a launch failure instead of a hidden tool
Verified fixed since the last review

Re-checked against current HEAD; these earlier findings no longer reproduce:

  • The entry file now lands in dist/ before STAMP, so an interrupted build no longer leaves a fresh stamp beside a stale world-daemon.cjs (the residual ordering issue is the manifest, filed above).
  • A cached build failure is no longer permanent for the process lifetime — failed is cleared after BUILD_FAILURE_COOLDOWN_MS.
  • apply() no longer signals a pid read from a reboot-surviving handshake file (the escalation was removed entirely; see the new finding on the resulting dead end).
  • The lock's pid parse now rejects 0 and non-integers via Number.isSafeInteger(pid) && pid > 0, so an empty lock file falls through to the mtime heuristic instead of handing 0 to process.kill.
  • The fingerprint now hashes the resolved playwright/package.json, so a Playwright bump invalidates the prebuilt daemon.
  • entry() short-circuits on fresh() before spawning bun, so an up-to-date checkout no longer pays a build subprocess per daemon start (the tree hash itself is still per-call, now async).
Checked, not flagged
  • clean() only removes .world-daemon-* directories under the package root and runs while the build lock is held, so it cannot delete a concurrent builder's stage in the normal case; the matching .gitignore entry covers the relocated stage dirs.
  • fresh() rejects manifests containing path separators (basename(item) === item), which keeps the existence check and the later rename loop confined to dist/.
  • detached: process.platform !== "win32" is what makes kill(child)'s process.kill(-pid) viable, so a build timeout now also reaps the smoke daemon; on Windows the fallback child.kill() is unchanged.
  • Smoke tests are now bounded twice over (--idle=15000 plus the KILO_WORLD_PARENT_PID watcher in server.ts:485), so a killed build no longer leaves a never-timing-out daemon behind.
  • BUILD_TIMEOUT_MS = LOCK_TIMEOUT_MS + 60_000 keeps the client's kill deadline above the child's own lock-wait deadline, so lock contention surfaces as the child's clearer error.
  • The runner-under-Node test now cleans up the spawned child in a finally and throws instead of asserting on a possibly-undefined bundle output.
Files Reviewed (6 files in the incremental diff)
  • packages/kilo-world/script/build-daemon.ts - 1 issue
  • packages/kilo-world/src/daemon/client.ts - 3 issues
  • packages/kilo-world/src/daemon/build.ts - 1 issue
  • packages/kilo-world/test/daemon.test.ts - 1 issue
  • packages/kilo-world/script/daemon.ts - no new issues
  • .gitignore - no new issues

Fix these issues in Kilo Cloud

Previous review (commit 11c11af)

Status: 7 Issues Found | Recommendation: Address before merge

Incremental review of ef63c9c -> 11c11af (8 files, all in packages/kilo-world/). This increment turns the lazy daemon build into a content-addressed, lock-protected, freshness-stamped build (src/daemon/build.ts + rewritten script/build-daemon.ts), captures build output instead of inheriting stdio, caches build failures, makes the launch-config restart in apply() escalate to SIGTERM/SIGKILL against a bounded DaemonServer.shutdownTimeoutMs, stops throwing on malformed KILO_WORLD_ARGS, and restores the runner guarantees that were dropped with browser.test.ts via a Node-executed test/runner-node.ts. 6 new findings; 1 earlier finding is still open.

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 3
New in this increment (6 issues)

WARNING

File Line Issue
packages/kilo-world/script/build-daemon.ts 28 STAMP is renamed into dist/ before world-daemon.cjs, so a build interrupted between the two renames leaves a fresh stamp beside a stale entry and current() reports up to date forever
packages/kilo-world/src/daemon/client.ts 48 failed is keyed by the source fingerprint and only cleared by a successful build, so a lock-wait timeout / missing node / ENOSPC poisons the world tool until the CLI server restarts
packages/kilo-world/src/daemon/client.ts 509 the new kill escalation signals a pid read from a reboot-surviving handshake file; after pid recycling this can SIGTERM/SIGKILL an unrelated process

SUGGESTION

File Line Issue
packages/kilo-world/script/build-daemon.ts 61 Number("") is 0, so an empty lock file passes Number.isFinite, makes the mtime fallback unreachable, and hands 0 to process.kill (own process group)
packages/kilo-world/src/daemon/build.ts 10 the fingerprint hashes package.json but not the resolved playwright version (catalog:), so a Playwright bump leaves the prebuilt daemon looking current
packages/kilo-world/src/daemon/client.ts 47 in a source checkout every daemon start does a synchronous whole-src hash on the event loop plus a bun subprocess that recomputes it, even when nothing changed
Still open from earlier reviews (1 issue)

WARNING

File Line Issue
packages/kilo-vscode/script/build.ts 87 re-verified at HEAD: copyWorldDaemon ships the daemon but no Chromium, and kilocode/tool/registry.ts:239 still advertises the tool on experimental.world_browser !== false with no browser-availability gate, so a VS Code user with no Chrome-family browser and no local Playwright Chromium gets a launch failure instead of a hidden tool
Verified fixed since the last review

Re-checked against current HEAD; these earlier findings no longer reproduce and their inline threads can be resolved:

  • config.ts no longer calls JSON.parse unguarded — parse() returns [] for malformed KILO_WORLD_ARGS, so defaultConfig() is no longer a throwing function on the palette / world-call path.
  • client.ts build() no longer uses stdio: "inherit"; output is piped, capped at 16 KB, and surfaced in the failure message, with a build timeout and abort-signal support.
  • apply() no longer relies on a fixed 5s wait shorter than the daemon's own shutdown budget: it waits DaemonServer.shutdownTimeoutMs (2s server close + 5s browser close + 1s), then escalates

[Snapshot truncated.]

Additional previous summary content was truncated to keep this comment within platform limits.


Reviewed by kimi-k3 · Input: 58.2K · Output: 3.3K · Cached: 210.1K

Review guidance: REVIEW.md from base branch main

Comment thread packages/kilo-vscode/src/services/cli-backend/server-manager.ts Outdated
Comment thread packages/opencode/src/kilocode/tool/world.ts Outdated
Comment thread packages/opencode/src/kilocode/tool/world-config.ts
Comment thread packages/kilo-world/src/daemon/server.ts Outdated
Comment thread packages/kilo-world/package.json
Comment thread packages/opencode/src/kilocode/tool/world.ts Outdated
Comment thread packages/opencode/src/kilocode/tool/world.ts Outdated
Comment thread packages/kilo-world/src/commands/browser/cookies.ts Outdated
Comment thread packages/kilo-world/src/core/browser/runner.ts Outdated
Comment thread package.json
Comment thread packages/kilo-world/package.json Outdated
Comment thread packages/kilo-world/src/core/browser/runner.ts Outdated
Comment thread packages/opencode/src/kilocode/plugins/world-palette.tsx
Comment thread packages/opencode/src/kilocode/plugins/world-palette.tsx Outdated
Comment thread packages/kilo-world/test/browser.test.ts Outdated
Comment thread packages/opencode/src/kilocode/tool/world.ts
Comment thread packages/opencode/src/kilocode/tool/registry.ts Outdated
Comment thread packages/kilo-world/src/daemon/protocol.ts Outdated
Comment thread packages/opencode/src/kilocode/plugins/world-palette.tsx Outdated
Comment thread packages/kilo-world/src/daemon/client.ts Outdated
Comment thread packages/kilo-world/src/config.ts Outdated
Comment thread packages/kilo-world/src/daemon/client.ts Outdated
Comment thread packages/kilo-world/test/daemon.test.ts
Comment thread packages/kilo-world/script/build-daemon.ts Outdated
Comment thread packages/kilo-world/script/build-daemon.ts Outdated
Comment thread packages/kilo-world/src/daemon/build.ts Outdated
Comment thread packages/kilo-world/src/daemon/client.ts Outdated
Comment thread packages/kilo-world/src/daemon/client.ts Outdated
Comment thread packages/kilo-world/src/daemon/client.ts Outdated
Comment thread packages/kilo-world/script/build-daemon.ts Outdated
Comment thread packages/kilo-world/src/daemon/client.ts
Comment thread packages/kilo-world/src/daemon/build.ts Outdated
Comment thread packages/kilo-world/src/daemon/client.ts Outdated
Comment thread packages/kilo-world/src/daemon/client.ts
Comment thread packages/kilo-world/test/daemon.test.ts Outdated
@IamCoder18
IamCoder18 force-pushed the feat/world-vscode branch 3 times, most recently from 71692a3 to 3e5a991 Compare August 3, 2026 04:30
Comment thread packages/kilo-world/src/daemon/client.ts Outdated
Comment thread packages/kilo-world/script/build-daemon.ts Outdated
Comment thread packages/kilo-world/src/daemon/build.ts Outdated
Comment thread packages/kilo-world/src/daemon/client.ts Outdated
@marius-kilocode

Copy link
Copy Markdown
Collaborator

@IamCoder18 how would this differ from a model using playwright? Why should we do this internally, instead of letting the user configure this themselfs? I see the benefit of integrating an inline browser into agent manager sidebar and as separate tab, but this might be out of scope.

@marius-kilocode

Copy link
Copy Markdown
Collaborator

It looks like a big effort from your side so I don't want to simply dismiss it, on the other hand this will add quite some complexity we will need to maintain.

@IamCoder18

IamCoder18 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

@marius-kilocode Thank you for taking time to look into this!

@IamCoder18 how would this differ from a model using playwright? Why should we do this internally, instead of letting the user configure this themselfs? I see the benefit of integrating an inline browser into agent manager sidebar and as separate tab, but this might be out of scope.

This offers a few advantages over Playwright:

  • Perhaps the biggest advantage is convenience. Kilo supporting Browser Use out of the box, enabled by default with the same permissions that other tools offer, would greatly improve model outputs (see benchmarks below) for all users, even inexperienced users who don't even know what MCP is.
  • From my testing (see benchmark below), World is both faster and cheaper than Playwright! Half the cost than Playwright in half the time for similar or better results in some cases.
  • It is useful for models as it allows them to script multiple commands in a single tool call lowering agent turns and cost required to perform Browser Use tasks.
  • Playwright is only available on VS Code, not on CLI (my most used surface) and JetBrains.
  • Improves transparency. Every time a model call the World tool, the user is shown a screenshot of in VS Code. This allows users to audit actions of agents even weeks after the session. Because of this transparency, World can be enabled by default, increasing reliability of UI generations. The inspiration was Codex, which always takes screenshots of it's work and improves based on it.
  • Customizability in the context of permissions (which I can make more granular if you want), and consistency across surfaces (CLI, VS Code, and later JetBrains).
  • Extensibility, allowing me to add Computer Use (that was actually my original objective, but I wanted a solid foundation first), add would bring the same convenience, transparency, and customizability to Computer Use.
  • Prevents MCP creep by giving a single tool, not 52. The entire tool's description is comparable to task, and isn't even the largest tool description, yet models still have 90% of the same functionaly (only major exception is video recordings, which I'm also working on)

It looks like a big effort from your side so I don't want to simply dismiss it, on the other hand this will add quite some complexity we will need to maintain.

I make World it's own package to minimize upstream merge conflicts. Additionally, I have tested thoroughly on Ubuntu 26.04 (CLI) and Windows 11 (CLI and VS Code).

I admit it would require maintenance, and I won't always be able to always help out (especially with school starting in September).

If you disagree with World for the project's long-term vision, I'd be fine with adding Playwright support to the CLI.


Doing some benchmarking, it is using World proactively without explicit instructions to do so, and is using it to improve the quality of the output:

image image image

I'll share more results when I'm done.


More results!

Transparency first: the code I used to benchmark is available at https://gist.github.com/IamCoder18/ad7c646cd43326325bd0316b3e052954.
It allows me to run bun bench.ts --name foo --tool all --prompt "..." and compare the three options. --tool supports playwright, plain, and world, and support multiple --tools (like --tool plain --tool world), as well as --tool all.

Prompt: Create a dashboard with lots of charts and graphs populated with sample data. Add a button on the page that toggles all the graphs into a 3D space where the user can rotate the view with the mouse, zoom in/out with the scroll wheel, and pan/move around the scene with click-and-drag. Constraint: do not use any chart/graph library — write the visualization code yourself (e.g. SVG, Canvas, or raw DOM). You may use a 3D library such as three.js to render the 3D view.

Results

image

No Playwright, No World (MiniMax M3, $0.0368, ~3m13s)

image image

With Playwright (MiniMax M3, $0.0357 (<- highest cost out of the runs), ~4m12s)

image image

Note: Some 3D controls were inverted, rotating caused text selection on cards, and there were a few visibility and contrast issues.

With World (MiniMax M3, $0.0305, ~3m36s)

image image image

Notes: Cards always face the camera is a great touch.

Winner: World

Prompt: Turn llama.cpp into a fully interactive 3D world. It should explain how data passes and how the 'magic' of llama.cpp works. Have both interactive walkthroughs as well as explore at your own pace options. The repo containing llama cpp source code is stored at /tmp/llamacpp for reference.

Results

image

No Playwright, No World (MiniMax M3, $0.0245, 2m32s)

image

With Playwright (MiniMax M3, $0.0669, 3m11s)

image image

With World (MiniMax M3, $0.0331, 2m16s) (half the cost of Playwright, fastest run)

image image

Winner: World

Though this run was close, World wins because it has better visuals to show data flow (an explicit part of the prompt) and has nicer 3D control.


Results

Both Playwright and World drastically improve agent performance, however, World improves the quality of agents' work faster and cheaper than Playwright. Through earlier (undocumented) testing, World has a larger improvement on free models than smarter models, and is a valuable asset to users running free models for webdev.

Comment thread packages/kilo-world/script/build-daemon.ts
Comment thread packages/kilo-world/src/daemon/build.ts Outdated
@IamCoder18
IamCoder18 force-pushed the feat/world-vscode branch 3 times, most recently from 43471b5 to 405bbeb Compare August 3, 2026 22:55
@IamCoder18

Copy link
Copy Markdown
Contributor Author

Tests failing are unrelated.

@IamCoder18

Copy link
Copy Markdown
Contributor Author

Re-ran tests and the pass now!

@marius-kilocode

Copy link
Copy Markdown
Collaborator

Do you have a link to the project?

@IamCoder18

Copy link
Copy Markdown
Contributor Author

Do you have a link to the project?

World is implemented in #12752 (new @kilocode/world package), and added to the CLI in #12753. This PR adds it to VS Code.

If you meant a link to the benchmark results, they're hosted on https://bench.aaravlabs.com/.

Hope that helps.

@marius-kilocode

Copy link
Copy Markdown
Collaborator

@IamCoder18 wait so this is custom code and no library?

@IamCoder18

IamCoder18 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

@IamCoder18 wait so this is custom code and no library?

Yes, that is correct. It uses Playwright heavily under the hood, but World is a custom wrapper over it.

@IamCoder18

IamCoder18 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

To clarify: the heavy lifting (browser lifecycle, DOM interactions, page navigation, screenshots) is powered by standard Playwright.

What is "custom" in @kilocode/world is the thin IPC/daemon bridge that lets the Kilo CLI and VS Code extension invoke Playwright commands consistently across surfaces without running a separate MCP server process.

Additionally, it handles persisting browser sessions for each sessions and ensure other sessions cannot access other browser sessions, enhancing security.

@IamCoder18

Copy link
Copy Markdown
Contributor Author

This allows me to add the entirely custom Computer Use in the same World surface, making it highly extensible.

@marius-kilocode

marius-kilocode commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

It's impressive work from you, but the problem with this is that this increases the maintenance risk since it hasn't been scaled to many users and the amount of edge cases is high. Can we go for the CLI playwrite route instead for now? We would much more rather adopt tools that are already tested in production for such complicated cases.

@IamCoder18

IamCoder18 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

It's impressive work from you, but the problem with this is that this increases the maintenance risk since it hasn't been scaled to many users and the amount of edge cases is high. Can we go for the CLI playwrite route instead for now? We would much more rather adopt tools that are already tested in production for such complicated cases.

@marius-kilocode I understand.

However, as the benchmarks show, an agent running World is both faster and cheaper than Playwright, and delivers the same or better levels of intelligence.

Therefore, Would it be possible to add World as an opt-in experimental feature? When users attempt to enable it, I can add a dialog that explains that it may have edge cases and might be unstable.

  • If something breaks and it is unmaintainable, it can easily be removed and Playwright would still work.

This solution would have the best of both worlds (pun intended), with 99% of sessions using stable, battletested Playwright, and the 1% who prefer World get access to it.

Another benefit is keeping the door open for Computer Use.

If you agree, I can make the changes across PRs.

@IamCoder18

Copy link
Copy Markdown
Contributor Author

Comment to prevent this PR from automatically closing due to 30 days of inactivity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants