What your AI coding agent trusts on your Mac: 8 things to check
Claude Code, Cursor, Copilot, Codex and Gemini CLI now run git, npm and shell commands for you, often in repos you cloned an hour ago. What those commands actually do is decided by a handful of config files: some in your home folder, some shipped inside the repo. Every item below has a published attack or advisory behind it.
For each one: what to look for, how to check by hand, and the source. At the end there is a free, open-source scanner that checks all of them at once.
1. Agent auto-approve settings
With auto-approve on, a prompt injection in a README or an issue becomes a command that runs without asking. A Copilot flaw (CVE-2025-53773) worked by switching chat.tools.autoApprove on.
Look for: chat.tools.autoApprove in VS Code or Cursor settings, Codex approval_policy = "never" or sandbox_mode = "danger-full-access", Gemini CLI folder trust turned off, Aider yes-always: true.
grep -n "autoApprove" ~/Library/Application\ Support/{Code,Cursor}/User/settings.json
grep -nE "approval_policy|sandbox_mode" ~/.codex/config.toml
2. Claude Code hooks and project settings
Hooks run shell commands on events like starting a session. A .claude/settings.json committed to a repo can add hooks, auto-enable the repo's MCP servers, or point API traffic elsewhere with ANTHROPIC_BASE_URL. Check Point showed this leading to code execution and API token theft (CVE-2025-59536).
Look for: hooks that download and run code (curl … | sh), hooks that run a script from the repo, Bash(*) permission rules, and repo settings with ANTHROPIC_BASE_URL, apiKeyHelper or enableAllProjectMcpServers.
grep -nE "curl|wget|Bash\(\*\)" ~/.claude/settings.json
find ~/code ~/projects -maxdepth 4 -path '*/.claude/settings.json' \
-exec grep -lE "ANTHROPIC_BASE_URL|apiKeyHelper|enableAllProjectMcpServers|hooks" {} +
3. MCP servers on unpinned packages
An MCP server started with npx -y some-package and no version can pick up a new release of that package without you noticing. If the package or its maintainer account is compromised, that release runs with your user's access. SafeDep found a malicious MCP package on npm that installed a macOS infostealer (SafeDep).
Look for: npx -y without an @version, and API keys written straight into a server's env, args or URL.
grep -n '"-y"' ~/.claude.json ~/.cursor/mcp.json 2>/dev/null
4. Git config that runs commands
A repo's own .git/config can name programs git runs on everyday commands: core.fsmonitor on every git status, core.pager on git log, filters on checkout. When an agent runs git status in a repo you just cloned, that program runs too (VulnCheck advisory; a nested bare repo variant in Copilot CLI GHSA-9ccr-r5hg-74gf).
# inside a repo
git config --show-origin --get-regexp '^(core\.(fsmonitor|pager|editor|sshcommand)|filter\..*|alias\..*)'
# every repo under ~/code
find ~/code -maxdepth 4 -path '*/.git/config' -exec grep -lE 'fsmonitor|sshCommand|\[filter' {} +
5. Hidden text in agent rules files
AGENTS.md, CLAUDE.md, .cursorrules and Copilot instructions are read by the agent as instructions. Invisible Unicode (zero-width characters, bidirectional controls, tag characters) can carry instructions the agent follows but a reviewer never sees (Pillar Security, "Rules File Backdoor").
perl -CSD -ne 'print "$ARGV:$.\n" if /[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2066}-\x{2069}\x{E0000}-\x{E007F}]/; close ARGV if eof' \
AGENTS.md CLAUDE.md .cursorrules 2>/dev/null
6. Tokens in plain-text dotfiles
npm worms go straight for these files. Shai-Hulud 2.0 collected tokens from developer machines, including Google Cloud's application_default_credentials.json (Datadog); the malicious Nx releases did the same (Nx postmortem).
Look for: ~/.npmrc with _authToken=, ~/.git-credentials, ~/.pypirc, ~/.cargo/credentials.toml, ~/.netrc, AWS AKIA… keys in ~/.aws/credentials, and AI keys in project .env files. These commands count matches; they don't print the values.
grep -c "_authToken=" ~/.npmrc
ls ~/.git-credentials ~/.pypirc ~/.netrc ~/.config/gcloud/application_default_credentials.json 2>/dev/null
grep -c "AKIA" ~/.aws/credentials
7. Shell startup files and history
macOS stealers such as AMOS persist through shell startup files like .zshrc, which run every time a terminal opens (Hackread), and they search shell history for keys you once pasted on the command line (Wiz on the LiteLLM compromise).
grep -nE 'curl[^|]*\|[[:space:]]*(ba|z)?sh|base64 (-d|--decode)' ~/.zshrc ~/.zprofile ~/.zshenv ~/.bashrc 2>/dev/null
grep -cE "(sk-|ghp_|AKIA|xox[bp]-)" ~/.zsh_history
8. Editor extensions and login items
Compromised extension releases have reached both marketplaces: Nx Console 18.95.0 shipped a credential stealer in May 2026 (StepSecurity) and the GlassWorm campaign on OpenVSX (Socket). Extensions installed from a local .vsix file skip marketplace checks entirely. Malware that gets in often stays through a LaunchAgent.
code --list-extensions --show-versions # compare against published reports
grep -o '"source":"vsix"' ~/.vscode/extensions/extensions.json | wc -l
ls -lt ~/Library/LaunchAgents # anything you don't recognise?
Or check all of it in one command
Running those by hand across every editor and repo gets old. macflow-check is a free, MIT-licensed scanner that does it for you:
brew install mazharul/tap/macflow-check
macflow-check
!macflow-check output: 7 to fix now, 2 worth fixing, each with a fix and a file location
It lists what to fix first, numbered, each with the fix and the file and line. Findings of the same kind collapse into one line; macflow-check --show 3 lists every finding in group 3, and --json gives machine-readable output. It also checks for known vulnerable or malicious packages in package-lock.json, Pipfile.lock and composer.lock via OSV, SSH config, outdated PHP, and reclaimable cache space.
What it doesn't do: it is read-only. It never changes a file, never runs a program it finds, and never prints a secret: findings name the file, line and kind of value only. The one network call sends lockfile package names, versions and ecosystems to OSV; --offline skips it. There is no telemetry.
Limitations: macOS only. It reads config files, not running processes or network traffic. Every check is a pattern for a known risky setting, so a config written to avoid those patterns will get past it. "No known match" means none of the checks matched, not that nothing is wrong.
The code, every rule and its source are on GitHub. Issues and PRs for new checks are welcome.
---
macflow-check is made by MacFlow, a Mac app that snapshots your dev setup and shows what changed. Continuous watching for these checks is planned.
How I built Browy, an AI agent that lives in your browser
---
title: "How I built Browy, an AI agent that lives in your browser"
published: true
description: "Browy is an open-source AI agent that works inside the browser you're already signed into. Here's how the pieces fit together, and what broke along the way."
tags: ai, webdev, opensource, architecture
canonical_url: browyhq.github.io
cover_image: browyhq.github.io
---
When you send Browy its first message, Chrome puts up a bar saying that Browy
started debugging this browser. No extension can hide it, Browy included. It
appears because Browy drives your tabs through chrome.debugger, which lets
an extension speak the Chrome DevTools Protocol, the same protocol your own
DevTools use.
I've grown to like that bar, because it describes Browy better than I usually
manage to. Browy is an AI agent that lives in your browser, and I mean that
literally. It works in the Chrome, Edge or Brave window you already have open,
signed in to everything you're signed in to.
You chat with it in the side panel, or type at it in a DevTools panel, and it
reads pages, clicks, types, fills forms and runs JavaScript in your tabs while
you watch. The models come through your own GitHub Copilot subscription. It's
open source under Apache-2.0, and I've
been building it on my own since April. This is the long version of how it
works, with the bugs left in.
What happens when you hit send
Three programs on your computer take part, and they talk over pipes.
The first is your browser, running Browy's extension: a side panel for
chatting, a DevTools panel for people who'd rather type commands, and a
settings page. None of them talk to the model. They talk to the extension's
service worker, which keeps one connection open to the second program. The
frontend architecture page walks through the extension file
by file.
That connection is Chrome's native messaging. Browy's installer registers a
manifest under the name com.browy.host, and when the service worker calls
chrome.runtime.connectNative('com.browy.host'), Chrome starts the host and
wires the extension to its stdin and stdout. Each message is a four-byte
length followed by JSON. The open port also keeps the service worker alive,
which Manifest V3 would otherwise put to sleep.
The host is a Node program, and it's where the agent lives. It wraps GitHub's
Copilot SDK, which starts the third
program, the Copilot CLI, in headless
mode and talks JSON-RPC to it over another pair of pipes. The CLI makes the
model calls on your Copilot subscription and stores each chat. Browy's code
covers the browser half: the tools, and the picture of the page the model gets
on every turn. The backend architecture page has the
details.
That picture is rebuilt each time you send a message. The host appends a
<browser_context> block to your text, with the active tab's title and URL,
the viewport, the scroll position and any text you've selected, followed by a
snapshot of the page and the agent's last few tool calls. Your words go first,
so the chat's summary in the history list shows what you asked.
When the model calls a tool, the SDK runs a handler in the host. If the tool
needs the page, the host sends a cdp.send message back up the native port,
naming a DevTools Protocol method and its parameters. The service worker picks
the tab, attaches chrome.debugger if it isn't attached yet, runs the command
and sends the result back down. Network and console events travel the same
route. The host coordinates, and every action happens in your browser.
The DevTools panel is the same agent with a terminal in front: slash commands,
a model picker, and a /js mode that runs each line in the inspected page
without calling the model. Each panel works on the tab it inspects. The
DevTools CLI page covers how the REPL is built.
The page as a numbered list
Ask a model to click something by CSS selector and it will happily invent one.
Even a correct selector only says where an element sat at one moment, and a
re-render can move it.
So Browy hands the model a numbered list. One Runtime.evaluate call walks
the page, shadow roots and same-origin iframes included, and keeps each
element that's interactive, visible and within 2,000 pixels of the viewport.
It sorts them in reading order, drops any that sit almost entirely inside
another, stops at 150 and stamps each one with a data-browy-id attribute.
The model sees something like this:
[1]<a href=/expenses>My expenses</a>
[4]<input type=text name=title placeholder="e.g. Client dinner" aria-name=Title />
[5]<input type=number name=amount aria-name="Amount (SGD)" />
[6]<input type=checkbox name=billable unchecked aria-name="Billable to client" />
[*7]<button>Attach receipt</button>
[~12]<button type=submit>Submit for approval</button>
A ~ marks an element that's off screen, which the click tools scroll into
view first. A * marks one that wasn't in the previous snapshot, which is how
the model notices that a dialog opened or a new part of the form appeared. The
aria-name is what a screen reader would announce, usually the label you'd
read yourself.
For click_index(12), the host finds the stamped element and sends real mouse
events to its center with Input.dispatchMouseEvent. Before and after, it
records the URL, the title, a hash of the visible text, the number of open
dialogs and the element's ARIA state. Half a second after the click it
compares them and reports what changed, with flags like urlChanged,
domChanged, modalAppeared and elementStateChanged. If nothing changed,
the reply says so and suggests what might be in the way, such as an overlay or
a page that's still rendering.
I didn't invent this. The indexed snapshot is modeled on
browser-use's DOM service and
serializer, down to the rule for dropping nested elements, and I'm grateful to
that team for working it out in the open.
Turning tools off
Browy has 54 browser tools, from click_index and fill_form to
get_network_requests and replay_request. Most have a switch in Browy's
settings. Turning one off removes it from two places, the tool definitions
sent to the model and the SDK's availableTools allowlist, so the model never
learns it exists.
Two of them run code the model writes. evaluate_js runs JavaScript in
the page, for the jobs the indexed tools can't express, and it's on.
run_script runs Node.js on your computer, so it's off until you switch it
on. It was on by default until version 0.1.10, which was the wrong default
for a tool that reaches your machine.
The Copilot CLI also brings tools of its own, like bash and web_fetch,
which act on your computer instead of the tab. Browy keeps those out of the
allowlist until you switch them on, one at a time, the same as run_script.
This matters because Browy reads pages written by strangers while it's signed
in as you. Any page can carry text aimed at the model, and Browy's security
model assumes some pages will. The switches decide what a page like that could
talk the agent into.
Why your own browser
Plenty of agents start a fresh browser, often on a server, with an empty
profile that isn't signed in to anything. For public pages at scale, that's
the right design. Most of my repetitive work happens on pages that only exist
because I'm signed in, though: the pull request I'm reviewing, my Gmail
filters, an expense claim, a journal's submission portal. A fresh browser sent
to any of them lands on a login screen. I wrote about the form-filling side of
this in an earlier post.
Browy sidesteps that by staying in your browser. Ask about the pull request in
front of you, and it reads the pull request in front of you, in the tab where
you're already signed in. Your logins stay where you made them, in your
browser profile, next to your cookies and your password manager. When a page
wants a password or a 2FA code, the agent is meant to call await_user, which
pauses and hands the job to you. That tool's own description tells the model
to use it instead of typing into password fields.
Your chat history is stored on your machine too, under ~/.copilot/. What
leaves it is what the model needs to see: your messages and the page content
the agent reads, sent through your Copilot subscription under GitHub's terms,
the same way the Copilot CLI sends them from a terminal.
The trade is scale. Browy works in one browser on one machine, and only when
you ask. It won't run a hundred jobs overnight, and I'm fine with that.
The second install, and other costs
Browy needs two programs that live outside the browser, Node for the agent and
the Copilot CLI for the model. An extension can't install those, and native
messaging only reaches a program that's already registered on the machine. So
Browy installs in two steps: the extension from the Chrome Web Store, then a
one-line command in PowerShell or a terminal. The side panel shows the command
for your system, with a copy button, and picks up the host by itself once it's
registered. In my testing that took 3.6 seconds. The
install guide has both commands.
Having two halves also means two update schedules: the Web Store updates the
extension, and you update the host, which the side panel prompts you to do
when it falls behind.
Then there's size. The Windows download is about 140 MB, most of it the
Copilot CLI. In August I cut a 106 MB native binary out of every download,
because the SDK ran the CLI as a Node script and nothing ever executed the
binary. In October the CLI itself moved into that same package as a native
executable. Switching to it cut the CLI's startup on Windows from 5.8 seconds
to 0.6, and pushed the Windows download from about 80 MB back up to about 140.
You download Browy once and wait for it to start far more often, so I'll take
that trade.
Browy is also Chromium only: Chrome, Edge and Brave. All of the above depends
on chrome.debugger, and Firefox and Safari don't give extensions an
equivalent.
And there's the debugging bar from the top of this post. It stays up while
Browy holds a tab, and clicking Cancel on it detaches the agent.
The system prompt that never arrived
In October I noticed that Browy still bundled version 1.0.36 of the Copilot
CLI, while the current release was 1.0.95, the native binary from the last
section. Updating meant checking each SDK call Browy makes against the new
CLI, and that turned up a bigger problem.
The SDK builds its session.create request from named fields, and the system
prompt goes in one called systemMessage. Browy had been passing its prompt
as systemPrompt since the first commit. Nothing complained. JavaScript
doesn't mind an extra key on an options object, and the SDK never looked for
that one. For five and a half months, every Browy chat ran on the Copilot
CLI's default instructions plus Browy's tool list. The instructions that tell
the model it's Browy, how to use the indexed tools and when to hand a sign-in
back to you never reached it.
The SDK's TypeScript types would have caught it, since SessionConfig has a
systemMessage field and no systemPrompt. But Browy loads the SDK with
require() and holds the client as any, so the compiler never compared the
two.
The part that stings is a comment about thirty lines higher in the same
function, shipped in the very first release. It notes that an earlier
includeDefaultTools: false flag had never been a real SDK option either. I
had caught this exact kind of bug once and written it down, and the second one
sat thirty lines below my note.
I suspect Browy mostly behaved anyway because the tool descriptions did reach
the model, and a lot of the guidance lives there.
The fix was one line, systemMessage: { content: SYSTEM_PROMPT }, with a
catch. The prompt I'd written in April told the model to fill a form and then
submit it, and once the prompt started arriving, that rule would have taken
effect for the first time. So the same release rewrote it. Browy now submits
only when you ask it to submit, send, post or buy, and otherwise stops and
tells you the form is ready to check. Asked its name, it finally says "I'm
Browy."
The chats that were on disk all along
In May I removed my development copy of the extension to test a clean
install, the way a new user would get it. When I opened the new copy, my older chats were
missing from the history list. Uninstalling an extension wipes its storage, so
I assumed they were gone.
They weren't. The Copilot SDK had written every turn of every chat to its
session store under ~/.copilot/, on my own disk, and the host already knew
how to list and read those sessions. It just didn't recognize the old ones as
Browy's. It looked for session ids starting with sp- (side panel) or dt-
(DevTools), and my older chats predated that scheme.
Version 0.1.4 recognizes a Browy session by any of three marks: the id prefix,
the working directory every Browy session is created with, or the
<browser_context> block Browy adds to messages. I widened the rule for
listing chats but left the narrow one in charge of automatic cleanup, so
nothing of uncertain origin could be deleted by accident.
Chats looked lost once more in August, when "No past chats yet" turned out to
be a four-second timeout on a host that needed between 7.7 and 40 seconds to
answer. Both times, the chats were fine. That's an upside of a local agent I
hadn't planned for: when the interface said my chats were gone, I could open
the folder and check.
The form it said it had filled
On every turn, Browy shows the model its own last five tool calls in a
<recent_actions> block, with each tool's arguments, whether it worked, how
long it took and the start of its result. That's how the model checks whether
its last click did anything. The same idea shows up in browser-use and in
research agents like ReAct and SeeAct.
The list lived on the host's agent object, and one agent serves every chat. So
a new chat's first message arrived carrying the previous chat's last five
calls.
I found out on October 13, while filming the demo video that's now on Browy's
homepage. In a brand-new chat, I asked Browy to fill the same form it had just
filled in another chat. It replied that the form was filled. It hadn't called
a single tool.
The model wasn't making things up, exactly. It was reading. Its context showed
fill_form coming back ok moments earlier, in what it had every reason to
think was its own chat, and it believed the record.
The fix keys the list by chat, in
a small module of its own,
and a new test fails if a fresh chat ever starts with another chat's tool
calls again. Version 0.1.9 shipped the same day.
The demo video came out of that same filming session. It runs 65 seconds in
real time: one sentence typed into the side panel, a paper open in one tab,
and a 26-field paper submission form in the other. By the end every field is
filled, and the submit button is still waiting for me.
---
- All posts Index of every post on the Browy blog.
- Architecture: native host How the host wraps the Copilot SDK and routes tool calls back to the extension.
1 reaction · 1 comment
Mentions
GitHub Copilot App のサンドボックスで .NET アプリを開発するための設定を試してみた GitHub Copilot App のローカルサンドボックスが GA したらしいので、.NET の開発で使えそうかどうか見てみようと思います。 今回は Windows 環境で、コンソールアプリの作成・実行と NuGet パッケージの追加を試し、その後に Minimal API も動かしてみました。 コンソールアプリは動かせましたが、ファイルのアクセス許可を調整したり、NuGet のエラーを調べたりする必要がありました。Minimal API は起動したものの、エンドポイントへのアクセスがタイムアウトし、今回はそこで断念しました。 ワークツリーの保存先を変更している場合の注意 GitHub Copilot App のワークツリーの保存先を D ドライブなどに変更している場合は、デフォルトの C ドライブ配下の場所に戻す必要があります。 現在、Windows のサンドボックスでは、システムドライブ以外にあるフォルダーを作業場所にすると、シェルでフォルダーの一覧取得などができない問題が報告されているためです。以下の Issue でも、D ドライブなどではアクセス拒否になり、システムドライブの C ドライブでは動くことが確認されています。 copilot-cli#5207 コンソールアプリを作成して実行するための設定 GitHub Copilot App にコンソールアプリの作成と実行を依頼したところ、dotnet new console の実行時にアクセス拒否のエラーが出ました。.NET SDK やテンプレートが使うフォルダーへの読み書きを許可する必要がありました。 使ったのは .NET 10 で、global.json で SDK を 10.0.403 に指定しています。 アクセスを拒否されたのは次のパスです。 %USERPROFILE%.dotnet\10.0.403.toolpath.sentinel %USERPROFILE%.templateengine\dotnetcli\10.0.403 %USERPROFILE%.templateengine\packages.json そこで、GitHub Copilot App のサイドバーから Settings を開き、Repositories で対象のリポジトリを選びます。Sandbox にある Additional read/write の Add folder から、次のフォルダーを追加しました。 C:\Users<ユーザー名>.dotnet C:\Users<ユーザー名>.templateengine <ユーザー名> は自分の環境に合わせて置き換えてください。 設定を変更しただけでは実行中のセッションに反映されないので、/restart-session でセッションを再起動する必要があります。 docs.github.com 上記のフォルダーへのアクセスを許可してセッションを再起動した後、Copilot に再実行を依頼すると、dotnet new console でのアプリ作成と、dotnet run での Hello, World! の表示に成功しました。 NuGet パッケージの追加を試してみる コンソールアプリの作成と実行ができたので、続いて Copilot に ReactiveProperty の追加を依頼しました。Copilot が実行したのは次のコマンドです。 dotnet add .\HelloWorld\HelloWorld.csproj package ReactiveProperty ところが、パッケージの追加もアクセス拒否で失敗しました。エラーメッセージには、拒否されたパスが出ていません。 error: Access to the path is denied. NuGet のパッケージ保存先やキャッシュのフォルダーが怪しいと思い、Additional read/write に次の4つを追加しました。 C:\Users<ユーザー名>.nuget C:\Users<ユーザー名>\AppData\Local\Temp\NuGetScratch C:\Users<ユーザー名>\AppData\Roaming\NuGet C:\Users<ユーザー名>\AppData\Local\NuGet 設定を反映して Copilot に再実行を依頼しましたが、それでも Access to the path is denied. が解消しませんでした。 ログを確認すると、次の URL からパッケージの登録情報を取得する GET リクエストには 200 OK が返っていました。少なくとも、この通信には成功しています。 api.nuget.org そこで、Copilot に NUGET_SHOW_STACK を有効にして再実行してもらいました。スタックトレースでは、NuGet.Protocol.HttpCacheUtility.CreateCacheFileAsync から呼ばれた System.IO.FileSystem.MoveFile で失敗していました。登録情報の取得ではなく、キャッシュファイルの移動で止まっていることが分かりました。 フォルダーの許可を追加しても解決せず、ログからもアクセスを拒否されたパスが分からなかったので、Process Monitor で実際のアクセス先を調べることにしました。 Process Monitor で失敗した操作を見る エラーメッセージだけでは先に進めなかったので、Microsoft の Process Monitor(Procmon)を使って、もう一度パッケージ追加を実行したときのファイル操作を確認しました。 learn.microsoft.com そこで見つかったのは、次の場所にあるファイルのリネームの失敗でした。ユーザー名やサンドボックスごとに変わる部分は置き換えています。 %LOCALAPPDATA%\Packages\sandbox.{GUID}\AC\NuGet\v3-cache<source-cache-dir>\list_reactiveproperty_index.dat-new list_reactiveproperty_index.dat-new の名前を、同じディレクトリ内で list_reactiveproperty_index.dat に変えようとしたところ、アクセスを拒否されていました。Procmon では、このリネーム操作(SetRenameInformationFile)の結果が ACCESS DENIED と記録されていました。 実際のアクセス先が AppData\Local\Packages 配下だったので、Additional read/write に次のパスを追加しました。 C:\Users<ユーザー名>\AppData\Local\Packages セッションを再起動して Copilot にパッケージ追加を再実行してもらうと、ReactiveProperty 9.10.0 と依存パッケージの導入に成功しました。値の変更を Subscribe で受け取り、コンソールに出力する処理も動きました。 これで動くようになりました。ただ、ここまでにいくつかのフォルダーを許可しているので、全部必要だったかは確認していません。AppData\Local\Packages を丸ごと許可するのは範囲が広いので、もう少し絞れないかは気になるところです。 私の環境でコンソールアプリを実行できた設定例 試した結果、ユーザー設定の Additional read/write(Folders the sandbox may read and modify)に残っていた .NET 用のパスは次の 7 件です。 C:\Users<ユーザー名>.dotnet C:\Users<ユーザー名>.templateengine C:\Users<ユーザー名>.nuget C:\Users<ユーザー名>\AppData\Local\Temp\NuGetScratch C:\Users<ユーザー名>\AppData\Roaming\NuGet C:\Users<ユーザー名>\AppData\Local\NuGet C:\Users<ユーザー名>\AppData\Local\Packages 設定する場合は、C:\Users<ユーザー名> の部分を自分の環境の絶対パスに置き換えてください。ここでは設定画面で環境変数が展開されるかどうかは確認していないので、絶対パスで記載しています。 これとは別に、添付画像へアクセスするために追加したパスもありました。 C:\Users<ユーザー名>.copilot\workspaces こちらは .NET の実行用ではなく、添付画像へのアクセス用です。 私の環境では、この設定でコンソールアプリの作成・パッケージ追加・実行までできました。もう少し許可するフォルダーを減らせるかもしれませんが、そこまでは試していません。 特に AppData\Local\Packages は、広い範囲の読み書きを許可することになります。今回の実験で使った設定であって、全員にそのまま追加することを勧めるものではありません。どこまで権限を絞っても動くかは未確認です。 Minimal API も試してみる コンソールアプリが動いたので、次は Copilot に Minimal API の作成と実行を依頼しました。アプリは起動しましたが、エンドポイントにアクセスするとタイムアウトしてしまいました。 サンドボックス設定の Outbound internet と Local network は、セッション開始時からどちらも ON にしていました。それでも接続できなかったので、ネットワーク周りの制約を調べてみました。 調べていると、Microsoft の MXC の公開資料で、似た症状の既知の制約を見つけました。Windows の特定の構成では、ホストからサンドボックス内で起動したサーバーへの接続がタイムアウトするというものです。 github.com/microsoft/mxc/blob/main/docs/backends/… リンク先では、Windows build 26691.1002 で、サンドボックスから外への通信をプロキシー経由に限定して試していました。ホストとのループバック通信を許可しても、ホストからサンドボックス内のサーバーへの接続はタイムアウトしたそうです。一方、プロキシーを使わない別の構成では接続できたとのことでした。 今回もこの制約に当たったのかは分かりません。ただ、起動した API に接続できない状態では開発を進められないので、今回はここまでにしました。 まとめ 今回は、サンドボックスのアクセス許可を追加することで、コンソールアプリの作成から NuGet パッケージの追加、実行までできました。ただ、途中で Procmon を使ってアクセス先を調べる必要があり、Minimal API も接続できないところで止まってしまいました。 今回試した Windows のローカル環境では、現時点で自分の実開発に使うにはまだ厳しいと感じました。サンドボックス自体は重要だと思っているので、今後の改善も追っていきたいです。
なるほど、GitHub Copilot Appのサンドボックスとの戦に負け続けているのは、このIssueのせいか!!! システムドライブじゃないとダメだったなんて…。早く非システムドライブでもOKにならないかなぁ。 今は時間切れだけど、後でシステムドライブでの作業を試してみよう copilot-cli#5207
@kkamegawa @yuma_prog 多分、これのせいでした。Dドライブ使ってます…。 copilot-cli#5207
What your AI coding agent trusts on your Mac: 8 things to check Claude Code, Cursor, Copilot, Codex and Gemini CLI now run git, npm and shell commands for you, often in repos you cloned an hour ago. What those commands actually do is decided by a handful of config files: some in your home folder, some shipped inside the repo. Every item below has a published attack or advisory behind it. For each one: what to look for, how to check by hand, and the source. At the end there is a free, open-source scanner that checks all of them at once. 1. Agent auto-approve settings With auto-approve on, a prompt injection in a README or an issue becomes a command that runs without asking. A Copilot flaw (CVE-2025-53773) worked by switching chat.tools.autoApprove on. Look for: chat.tools.autoApprove in VS Code or Cursor settings, Codex approval_policy = "never" or sandbox_mode = "danger-full-access", Gemini CLI folder trust turned off, Aider yes-always: true. grep -n "autoApprove" ~/Library/Application\ Support/{Code,Cursor}/User/settings.json grep -nE "approval_policy|sandbox_mode" ~/.codex/config.toml 2. Claude Code hooks and project settings Hooks run shell commands on events like starting a session. A .claude/settings.json committed to a repo can add hooks, auto-enable the repo's MCP servers, or point API traffic elsewhere with ANTHROPIC_BASE_URL. Check Point showed this leading to code execution and API token theft (CVE-2025-59536). Look for: hooks that download and run code (curl … | sh), hooks that run a script from the repo, Bash(*) permission rules, and repo settings with ANTHROPIC_BASE_URL, apiKeyHelper or enableAllProjectMcpServers. grep -nE "curl|wget|Bash\(\*\)" ~/.claude/settings.json find ~/code ~/projects -maxdepth 4 -path '*/.claude/settings.json' \ -exec grep -lE "ANTHROPIC_BASE_URL|apiKeyHelper|enableAllProjectMcpServers|hooks" {} + 3. MCP servers on unpinned packages An MCP server started with npx -y some-package and no version can pick up a new release of that package without you noticing. If the package or its maintainer account is compromised, that release runs with your user's access. SafeDep found a malicious MCP package on npm that installed a macOS infostealer (SafeDep). Look for: npx -y without an @version, and API keys written straight into a server's env, args or URL. grep -n '"-y"' ~/.claude.json ~/.cursor/mcp.json 2>/dev/null 4. Git config that runs commands A repo's own .git/config can name programs git runs on everyday commands: core.fsmonitor on every git status, core.pager on git log, filters on checkout. When an agent runs git status in a repo you just cloned, that program runs too (VulnCheck advisory; a nested bare repo variant in Copilot CLI GHSA-9ccr-r5hg-74gf). # inside a repo git config --show-origin --get-regexp '^(core\.(fsmonitor|pager|editor|sshcommand)|filter\..*|alias\..*)' # every repo under ~/code find ~/code -maxdepth 4 -path '*/.git/config' -exec grep -lE 'fsmonitor|sshCommand|\[filter' {} + 5. Hidden text in agent rules files AGENTS.md, CLAUDE.md, .cursorrules and Copilot instructions are read by the agent as instructions. Invisible Unicode (zero-width characters, bidirectional controls, tag characters) can carry instructions the agent follows but a reviewer never sees (Pillar Security, "Rules File Backdoor"). perl -CSD -ne 'print "$ARGV:$.\n" if /[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2066}-\x{2069}\x{E0000}-\x{E007F}]/; close ARGV if eof' \ AGENTS.md CLAUDE.md .cursorrules 2>/dev/null 6. Tokens in plain-text dotfiles npm worms go straight for these files. Shai-Hulud 2.0 collected tokens from developer machines, including Google Cloud's application_default_credentials.json (Datadog); the malicious Nx releases did the same (Nx postmortem). Look for: ~/.npmrc with _authToken=, ~/.git-credentials, ~/.pypirc, ~/.cargo/credentials.toml, ~/.netrc, AWS AKIA… keys in ~/.aws/credentials, and AI keys in project .env files. These commands count matches; they don't print the values. grep -c "_authToken=" ~/.npmrc ls ~/.git-credentials ~/.pypirc ~/.netrc ~/.config/gcloud/application_default_credentials.json 2>/dev/null grep -c "AKIA" ~/.aws/credentials 7. Shell startup files and history macOS stealers such as AMOS persist through shell startup files like .zshrc, which run every time a terminal opens (Hackread), and they search shell history for keys you once pasted on the command line (Wiz on the LiteLLM compromise). grep -nE 'curl[^|]*\|[[:space:]]*(ba|z)?sh|base64 (-d|--decode)' ~/.zshrc ~/.zprofile ~/.zshenv ~/.bashrc 2>/dev/null grep -cE "(sk-|ghp_|AKIA|xox[bp]-)" ~/.zsh_history 8. Editor extensions and login items Compromised extension releases have reached both marketplaces: Nx Console 18.95.0 shipped a credential stealer in May 2026 (StepSecurity) and the GlassWorm campaign on OpenVSX (Socket). Extensions installed from a local .vsix file skip marketplace checks entirely. Malware that gets in often stays through a LaunchAgent. code --list-extensions --show-versions # compare against published reports grep -o '"source":"vsix"' ~/.vscode/extensions/extensions.json | wc -l ls -lt ~/Library/LaunchAgents # anything you don't recognise? Or check all of it in one command Running those by hand across every editor and repo gets old. macflow-check is a free, MIT-licensed scanner that does it for you: brew install mazharul/tap/macflow-check macflow-check !macflow-check output: 7 to fix now, 2 worth fixing, each with a fix and a file location It lists what to fix first, numbered, each with the fix and the file and line. Findings of the same kind collapse into one line; macflow-check --show 3 lists every finding in group 3, and --json gives machine-readable output. It also checks for known vulnerable or malicious packages in package-lock.json, Pipfile.lock and composer.lock via OSV, SSH config, outdated PHP, and reclaimable cache space. What it doesn't do: it is read-only. It never changes a file, never runs a program it finds, and never prints a secret: findings name the file, line and kind of value only. The one network call sends lockfile package names, versions and ecosystems to OSV; --offline skips it. There is no telemetry. Limitations: macOS only. It reads config files, not running processes or network traffic. Every check is a pattern for a known risky setting, so a config written to avoid those patterns will get past it. "No known match" means none of the checks matched, not that nothing is wrong. The code, every rule and its source are on GitHub. Issues and PRs for new checks are welcome. --- macflow-check is made by MacFlow, a Mac app that snapshots your dev setup and shows what changed. Continuous watching for these checks is planned.
GitHub’s multi-model Copilot harness comes to Microsoft Foundry for building custom AI agents Microsoft has introduced the GitHub-built Copilot harness in Foundry Agent Service in public preview. Developers can supply their own instructions, skills and tools while Foundry manages the agent loop and execution environment. The open-source connection is the Copilot SDK, which is available under the MIT license. It lets developers integrate Copilot’s agent capabilities into their own applications, with SDKs for Python, TypeScript, Go, .NET, Java and Rust. There is a licensing distinction: the SDK communicates with Copilot CLI, which has a separate license restricting modification of the CLI itself. The SDK’s MIT license does not make the entire agent runtime open source. The Foundry preview also supports Model Context Protocol (MCP) tools, reusable skills and agent definitions maintained alongside application code. These provide ways to customize and connect agents while the execution infrastructure remains managed by Foundry. sources - Foundry public preview announcement - Copilot SDK documentation and architecture - Copilot SDK MIT license - Copilot CLI license
Managed Model "fusion"ってなんだー。HydraFusionのこと?autoでも選ばれるらしい。 github.com/github/copilot-cli/releases/tag/v1.0.1…
Gleiches Modell und völlig unbrauchbar?! Hier geht's zu WECHSELPILOT: wechselpilot.short.gy [Werbung] Mit dem Code MORPHEUS bekommt ihr zusätzlich 20 € Cashback auf den ersten Wechsel. Teil 2 vom CLI-Benchmark: GitHub Copilot CLI, OpenCode und Kilo Code bekommen dasselbe Modell wie die Tools aus Teil 1, Gemini 3.7 Flash, und dieselbe Aufgabe: MorphCook mit genau einem Prompt bauen. Ich schaue mir an, was jeder Harness daraus macht, wer mitten in der Arbeit stehen bleibt und was das am Ende kostet. Quellen zum Video: TheMorpheus407/morphcook github/copilot-cli anomalyco/opencode Kilo-Org/kilocode MorphReader im PlayStore: play.google.com MorphReader im App Store: apps.apple.com Newsletter und RSS-Feeds: patreon.com Kostenlos Informatik lernen mit der Bootstrap Academy: bootstrap.academy github.com/Bootstrap-Academy Instagram: instagram.com Meine anderen Kanäle und Projekte: the-morpheus.de Discord: the-morpheus.de Unterstützt mich – danke! patreon.com paypal.me Kapitel: 0:00 Intro 1:22 Werbung: WECHSELPILOT 2:56 Grundlagen: Testaufbau, Modell, Sandbox, Kosten 8:48 GitHub Copilot CLI: Intro 11:11 GitHub Copilot CLI: Auswertung 21:21 OpenCode: Intro 22:57 OpenCode: Auswertung des Neulaufs 35:40 Kilo Code: Intro 37:51 Kilo Code: Auswertung 46:26 Fazit & Ausblick auf Teil 3 [en-US] Same model and completely unusable?! Here's the link to WECHSELPILOT: wechselpilot.short.gy [Advertisement] Use the code MORPHEUS to get an additional €20 cashback on your first switch. Part 2 of the CLI benchmark: GitHub Copilot CLI, OpenCode, and Kilo Code are given the same model as the tools from Part 1, Gemini 3.7 Flash, and the same task: to build MorphCook with just one prompt. I'll see what each harness can do, which one gets stuck mid-project, and what the final cost is. Part 2 of the CLI benchmark: GitHub Copilot CLI, OpenCode, and Kilo Code are given the same model as the tools from Part 1, Gemini 3.7 Flash, and the same task: to build MorphCook with exactly one prompt. Sources for the video: TheMorpheus407/morphcook github/copilot-cli anomalyco/opencode Kilo-Org/kilocode MorphReader on the Play Store: play.google.com MorphReader on the App Store: apps.apple.com Newsletter and RSS feeds: patreon.com Learn computer science for free with Bootstrap Academy: bootstrap.academy github.com/Bootstrap-Academy Instagram: instagram.com My other channels and projects: the-morpheus.de Discord: the-morpheus.de Support me – thank you! patreon.com paypal.me Chapters: 0:00 Intro 1:22 Advertisement: WECHSELPILOT 2:56 Basics: Test setup, model, sandbox, costs 8:48 GitHub Copilot CLI: Intro 11:11 GitHub Copilot CLI: Evaluation 21:21 OpenCode: Intro 22:57 OpenCode: Evaluation of the rerun 35:40 Kilo Code: Intro 37:51 Kilo Code: Evaluation 46:26 Conclusion & Outlook on Part 3
copilot cli 1.0.101. in a long session, just changing reasoning effort forced a compaction. turn effort up for the hard bit, lose the context you needed it for github.com/github/copilot-cli/releases/tag/v1.0.1…
Copilot CLI 1.0.100 (Oct 19): its sandbox now lets commands reach localhost and private-network services by default. That's where local MCP servers, dev databases and admin panels live. If you enabled the sandbox to contain the agent, re-check its reach. github.com/github/copilot-cli/releases/tag/v1.0.1…
How I built Browy, an AI agent that lives in your browser --- title: "How I built Browy, an AI agent that lives in your browser" published: true description: "Browy is an open-source AI agent that works inside the browser you're already signed into. Here's how the pieces fit together, and what broke along the way." tags: ai, webdev, opensource, architecture canonical_url: browyhq.github.io cover_image: browyhq.github.io --- When you send Browy its first message, Chrome puts up a bar saying that Browy started debugging this browser. No extension can hide it, Browy included. It appears because Browy drives your tabs through chrome.debugger, which lets an extension speak the Chrome DevTools Protocol, the same protocol your own DevTools use. I've grown to like that bar, because it describes Browy better than I usually manage to. Browy is an AI agent that lives in your browser, and I mean that literally. It works in the Chrome, Edge or Brave window you already have open, signed in to everything you're signed in to. You chat with it in the side panel, or type at it in a DevTools panel, and it reads pages, clicks, types, fills forms and runs JavaScript in your tabs while you watch. The models come through your own GitHub Copilot subscription. It's open source under Apache-2.0, and I've been building it on my own since April. This is the long version of how it works, with the bugs left in. What happens when you hit send Three programs on your computer take part, and they talk over pipes. The first is your browser, running Browy's extension: a side panel for chatting, a DevTools panel for people who'd rather type commands, and a settings page. None of them talk to the model. They talk to the extension's service worker, which keeps one connection open to the second program. The frontend architecture page walks through the extension file by file. That connection is Chrome's native messaging. Browy's installer registers a manifest under the name com.browy.host, and when the service worker calls chrome.runtime.connectNative('com.browy.host'), Chrome starts the host and wires the extension to its stdin and stdout. Each message is a four-byte length followed by JSON. The open port also keeps the service worker alive, which Manifest V3 would otherwise put to sleep. The host is a Node program, and it's where the agent lives. It wraps GitHub's Copilot SDK, which starts the third program, the Copilot CLI, in headless mode and talks JSON-RPC to it over another pair of pipes. The CLI makes the model calls on your Copilot subscription and stores each chat. Browy's code covers the browser half: the tools, and the picture of the page the model gets on every turn. The backend architecture page has the details. That picture is rebuilt each time you send a message. The host appends a <browser_context> block to your text, with the active tab's title and URL, the viewport, the scroll position and any text you've selected, followed by a snapshot of the page and the agent's last few tool calls. Your words go first, so the chat's summary in the history list shows what you asked. When the model calls a tool, the SDK runs a handler in the host. If the tool needs the page, the host sends a cdp.send message back up the native port, naming a DevTools Protocol method and its parameters. The service worker picks the tab, attaches chrome.debugger if it isn't attached yet, runs the command and sends the result back down. Network and console events travel the same route. The host coordinates, and every action happens in your browser. The DevTools panel is the same agent with a terminal in front: slash commands, a model picker, and a /js mode that runs each line in the inspected page without calling the model. Each panel works on the tab it inspects. The DevTools CLI page covers how the REPL is built. The page as a numbered list Ask a model to click something by CSS selector and it will happily invent one. Even a correct selector only says where an element sat at one moment, and a re-render can move it. So Browy hands the model a numbered list. One Runtime.evaluate call walks the page, shadow roots and same-origin iframes included, and keeps each element that's interactive, visible and within 2,000 pixels of the viewport. It sorts them in reading order, drops any that sit almost entirely inside another, stops at 150 and stamps each one with a data-browy-id attribute. The model sees something like this: [1]<a href=/expenses>My expenses</a> [4]<input type=text name=title placeholder="e.g. Client dinner" aria-name=Title /> [5]<input type=number name=amount aria-name="Amount (SGD)" /> [6]<input type=checkbox name=billable unchecked aria-name="Billable to client" /> [*7]<button>Attach receipt</button> [~12]<button type=submit>Submit for approval</button> A ~ marks an element that's off screen, which the click tools scroll into view first. A * marks one that wasn't in the previous snapshot, which is how the model notices that a dialog opened or a new part of the form appeared. The aria-name is what a screen reader would announce, usually the label you'd read yourself. For click_index(12), the host finds the stamped element and sends real mouse events to its center with Input.dispatchMouseEvent. Before and after, it records the URL, the title, a hash of the visible text, the number of open dialogs and the element's ARIA state. Half a second after the click it compares them and reports what changed, with flags like urlChanged, domChanged, modalAppeared and elementStateChanged. If nothing changed, the reply says so and suggests what might be in the way, such as an overlay or a page that's still rendering. I didn't invent this. The indexed snapshot is modeled on browser-use's DOM service and serializer, down to the rule for dropping nested elements, and I'm grateful to that team for working it out in the open. Turning tools off Browy has 54 browser tools, from click_index and fill_form to get_network_requests and replay_request. Most have a switch in Browy's settings. Turning one off removes it from two places, the tool definitions sent to the model and the SDK's availableTools allowlist, so the model never learns it exists. Two of them run code the model writes. evaluate_js runs JavaScript in the page, for the jobs the indexed tools can't express, and it's on. run_script runs Node.js on your computer, so it's off until you switch it on. It was on by default until version 0.1.10, which was the wrong default for a tool that reaches your machine. The Copilot CLI also brings tools of its own, like bash and web_fetch, which act on your computer instead of the tab. Browy keeps those out of the allowlist until you switch them on, one at a time, the same as run_script. This matters because Browy reads pages written by strangers while it's signed in as you. Any page can carry text aimed at the model, and Browy's security model assumes some pages will. The switches decide what a page like that could talk the agent into. Why your own browser Plenty of agents start a fresh browser, often on a server, with an empty profile that isn't signed in to anything. For public pages at scale, that's the right design. Most of my repetitive work happens on pages that only exist because I'm signed in, though: the pull request I'm reviewing, my Gmail filters, an expense claim, a journal's submission portal. A fresh browser sent to any of them lands on a login screen. I wrote about the form-filling side of this in an earlier post. Browy sidesteps that by staying in your browser. Ask about the pull request in front of you, and it reads the pull request in front of you, in the tab where you're already signed in. Your logins stay where you made them, in your browser profile, next to your cookies and your password manager. When a page wants a password or a 2FA code, the agent is meant to call await_user, which pauses and hands the job to you. That tool's own description tells the model to use it instead of typing into password fields. Your chat history is stored on your machine too, under ~/.copilot/. What leaves it is what the model needs to see: your messages and the page content the agent reads, sent through your Copilot subscription under GitHub's terms, the same way the Copilot CLI sends them from a terminal. The trade is scale. Browy works in one browser on one machine, and only when you ask. It won't run a hundred jobs overnight, and I'm fine with that. The second install, and other costs Browy needs two programs that live outside the browser, Node for the agent and the Copilot CLI for the model. An extension can't install those, and native messaging only reaches a program that's already registered on the machine. So Browy installs in two steps: the extension from the Chrome Web Store, then a one-line command in PowerShell or a terminal. The side panel shows the command for your system, with a copy button, and picks up the host by itself once it's registered. In my testing that took 3.6 seconds. The install guide has both commands. Having two halves also means two update schedules: the Web Store updates the extension, and you update the host, which the side panel prompts you to do when it falls behind. Then there's size. The Windows download is about 140 MB, most of it the Copilot CLI. In August I cut a 106 MB native binary out of every download, because the SDK ran the CLI as a Node script and nothing ever executed the binary. In October the CLI itself moved into that same package as a native executable. Switching to it cut the CLI's startup on Windows from 5.8 seconds to 0.6, and pushed the Windows download from about 80 MB back up to about 140. You download Browy once and wait for it to start far more often, so I'll take that trade. Browy is also Chromium only: Chrome, Edge and Brave. All of the above depends on chrome.debugger, and Firefox and Safari don't give extensions an equivalent. And there's the debugging bar from the top of this post. It stays up while Browy holds a tab, and clicking Cancel on it detaches the agent. The system prompt that never arrived In October I noticed that Browy still bundled version 1.0.36 of the Copilot CLI, while the current release was 1.0.95, the native binary from the last section. Updating meant checking each SDK call Browy makes against the new CLI, and that turned up a bigger problem. The SDK builds its session.create request from named fields, and the system prompt goes in one called systemMessage. Browy had been passing its prompt as systemPrompt since the first commit. Nothing complained. JavaScript doesn't mind an extra key on an options object, and the SDK never looked for that one. For five and a half months, every Browy chat ran on the Copilot CLI's default instructions plus Browy's tool list. The instructions that tell the model it's Browy, how to use the indexed tools and when to hand a sign-in back to you never reached it. The SDK's TypeScript types would have caught it, since SessionConfig has a systemMessage field and no systemPrompt. But Browy loads the SDK with require() and holds the client as any, so the compiler never compared the two. The part that stings is a comment about thirty lines higher in the same function, shipped in the very first release. It notes that an earlier includeDefaultTools: false flag had never been a real SDK option either. I had caught this exact kind of bug once and written it down, and the second one sat thirty lines below my note. I suspect Browy mostly behaved anyway because the tool descriptions did reach the model, and a lot of the guidance lives there. The fix was one line, systemMessage: { content: SYSTEM_PROMPT }, with a catch. The prompt I'd written in April told the model to fill a form and then submit it, and once the prompt started arriving, that rule would have taken effect for the first time. So the same release rewrote it. Browy now submits only when you ask it to submit, send, post or buy, and otherwise stops and tells you the form is ready to check. Asked its name, it finally says "I'm Browy." The chats that were on disk all along In May I removed my development copy of the extension to test a clean install, the way a new user would get it. When I opened the new copy, my older chats were missing from the history list. Uninstalling an extension wipes its storage, so I assumed they were gone. They weren't. The Copilot SDK had written every turn of every chat to its session store under ~/.copilot/, on my own disk, and the host already knew how to list and read those sessions. It just didn't recognize the old ones as Browy's. It looked for session ids starting with sp- (side panel) or dt- (DevTools), and my older chats predated that scheme. Version 0.1.4 recognizes a Browy session by any of three marks: the id prefix, the working directory every Browy session is created with, or the <browser_context> block Browy adds to messages. I widened the rule for listing chats but left the narrow one in charge of automatic cleanup, so nothing of uncertain origin could be deleted by accident. Chats looked lost once more in August, when "No past chats yet" turned out to be a four-second timeout on a host that needed between 7.7 and 40 seconds to answer. Both times, the chats were fine. That's an upside of a local agent I hadn't planned for: when the interface said my chats were gone, I could open the folder and check. The form it said it had filled On every turn, Browy shows the model its own last five tool calls in a <recent_actions> block, with each tool's arguments, whether it worked, how long it took and the start of its result. That's how the model checks whether its last click did anything. The same idea shows up in browser-use and in research agents like ReAct and SeeAct. The list lived on the host's agent object, and one agent serves every chat. So a new chat's first message arrived carrying the previous chat's last five calls. I found out on October 13, while filming the demo video that's now on Browy's homepage. In a brand-new chat, I asked Browy to fill the same form it had just filled in another chat. It replied that the form was filled. It hadn't called a single tool. The model wasn't making things up, exactly. It was reading. Its context showed fill_form coming back ok moments earlier, in what it had every reason to think was its own chat, and it believed the record. The fix keys the list by chat, in a small module of its own, and a new test fails if a fresh chat ever starts with another chat's tool calls again. Version 0.1.9 shipped the same day. The demo video came out of that same filming session. It runs 65 seconds in real time: one sentence typed into the side panel, a paper open in one tab, and a 26-field paper submission form in the other. By the end every field is filled, and the submit button is still waiting for me. --- - All posts Index of every post on the Browy blog. - Architecture: native host How the host wraps the Copilot SDK and routes tool calls back to the extension.