Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/mutant-porte.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
k = subprocess.run(['node', proeve], capture_output=True, text=True, timeout=600, env={**os.environ, 'TMPDIR': tmp + '/'})
groen[proeve] = k.returncode == 0
except subprocess.TimeoutExpired:
groen[proeve] = False
groen[proeve] = False; k = None
finally:
shutil.rmtree(tmp, ignore_errors=True)
if not groen[proeve]: print(f"::error::proeven {proeve} er ROED uden mutation - dens mutanter er ikke bevist")
if not groen[proeve]:
print(f"::error::proeven {proeve} er ROED uden mutation - dens mutanter er ikke bevist")
# 30/10 (0.4.1-LISTE #4): uden hvorfor kunne ingen se, at baggrund-mus/stop-alle kun var roede her - vis halen.
ud = ((k.stdout or '') + (k.stderr or '')).splitlines() if k else ['timeout efter 600 s']
print(f"::group::{proeve} umuteret - de sidste linjer"); print('\n'.join(ud[-40:])); print("::endgroup::")
for m in MUTANTER:
if not groen.get(m['proeve']):
fejl.append(f"{m['navn']}: proeven {m['proeve']} er roed uden mutation"); continue
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/fremmed-mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ jobs:
- name: Mange agenter samtidig
id: par
continue-on-error: true
# 1/11 (panel R2-R3): parallelproeven hang til jobfristen (41077418047 forsoeg 1); mutationsbeviset blev sprunget
# over, og slutporten afviste koerslen. Et normalt trin tager ~4 min.
timeout-minutes: 30
run: |
killall Chess Calculator Contacts "System Settings" "Activity Monitor" Notes Safari "Script Editor" 2>/dev/null || true
CMCP_FILM="$RUNNER_TEMP/film" CMCP_PARALLEL_RAPPORT="$RUNNER_TEMP/parallel.json" node test/parallel.mjs
Expand Down
67 changes: 64 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,67 @@
# Changelog

Dates are the day the version was tagged. Everything here was measured before it
was written down; where a claim has a test, the test is named.
Newest first. Where a claim has a test, the test is named; what is not measured
says so.

## 0.4.1 (in progress)

**The consent box no longer says password apps ask while the agent works in the
background.** In the background they are refused outright, but the box said
"Password apps still always ask". It now says "Password apps stay refused while
it works in the background." The text shown in the foreground was already true.
`test/ikon-godkend.mjs` D2 checks the wording, and fails with the old text.

**The MIT license ships with the package.** The npm package did not carry
`LICENSE`; it does now (`npm pack` lists it), and the MCPB bundle copies the same
file list.

**The lockfile was renewed on 1 November.** An `npx` install has no lockfile and
resolves the newest versions in range; on 1 November that was MCP SDK 1.32.2,
with no `npm audit` findings. 0.4.0's lockfile, which the tests and the MCPB
bundle install from, had SDK 1.32.1 and five audit findings (zod, body-parser,
@hono/node-server, fast-uri, qs). It was replaced that day by a fresh
resolution of this version's `package.json`; newer releases in range can
appear after it. The SDK also has to be at least 1.32.1.

**Several agents at once.** In `test/parallel.mjs`, 5, 10 and 15 agents work in
the background while another test types into TextEdit. An agent that opens a
Finder window brings Finder forward for a moment, and the front is handed
straight back - the longest one that was handed back lasted 2.8 seconds. In
eleven completed runs on GitHub's Mac, on macOS 15.7 and 15.8 alike, it happened twice at
32 of 33 levels; the recording on the front page shows the same thing. In one
of 65 such moments the front could not be handed back: Finder stayed in front
for the rest of that round (at least 40 seconds), and the reply said so
(`gave_back: false`). Under load an agent can also stop and wait when it cannot
tell which app the person is in - it then does nothing - and one run hung until
GitHub's time limit; the cause of the hang is not found. None of this is fixed
in this version. Every word the typing test sent into TextEdit was verified by
the helper (4,939 of 4,939 across the eleven runs); whether keys typed by hand
during such a moment land in Finder is not measured. The test used to blame
whichever agent happened to start during the moment - even one that only
reads - and now judges it on GitHub's Mac the way it already did on a person's
own Mac.

**Tests.** `test/stille-vej.mjs` gives `scroll --app` a point, as 0.4.0's helper
requires; on a foreign Mac that check had failed on 0.4.0. The mutation gate now
prints the last lines of a test that fails before anything is mutated.
`scripts/release.sh` looks for the CI run in the last 100 runs, not 20.

**Known limits found while measuring 0.4.1.** The mutation gate on GitHub's Mac
runs `test/baggrund-mus.mjs` after the many-agents test, and there a menu
opened by a click behind is not closed again (`menu_closed: false` in the
reply) - with Finder in front, and in two runs that put Script Editor in front
first, with Script Editor in front - though these menu checks pass in the
suite. The cause is not found. Its 38 mutants are therefore not proven on a
foreign Mac. In `test/sikker-frigivelse.mjs`, the check that the helper process
ends within 500 ms of a stop (F2b) failed in 4 of 13 completed runs by
1 November (517-546 ms), on 0.4.0 and 0.4.1 alike; the mouse button was
released in all of them (F2).

**Corrected.** The 0.2.1 notes below said "Password managers ask every single
time, in every mode." In background mode they are refused, not asked; in the
foreground they ask every time. The 0.4.0 notes say "A click behind never leaves
a menu over your work." In the mutation gate on GitHub's Mac a menu opened by a
click behind was left open, and the reply said so (`menu_closed: false`).

## 0.4.0 (in progress)

Expand Down Expand Up @@ -447,7 +507,8 @@ that it is leaving and the helper finishes the file on its own. A server killed
anything. Needs macOS 15.

**Consent, as it actually works.** `allow` is the default, so an agent can be
left running. Password managers ask every single time, in every mode. Terminals
left running. Password managers ask every single time, in every mode (corrected
in 0.4.1: in background mode they are refused). Terminals
and editors ask once per app per session. Quitting, closing a window, switching
Space and destructive-looking menu items ask every time. Several pages said
otherwise; they now match the code, and a test derives the forbidden phrasings
Expand Down
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ in the hours you are not watching.
- **It does not take over your Mac.** It presses buttons and fills fields in
windows that stay behind the one you are in, and it leaves your pointer where
you put it. When an app pulls itself to the front as it opens, the front is
handed straight back and the reply says so - nothing is left stealing what you
are typing.
handed straight back and the reply says so. In one of 65 measured moments like
it (GitHub's Mac, many agents at once) it could not be, and the reply said that too (`gave_back:
false`): until you click back, what you type goes to that app. It also leaves
the front alone when you clicked, scrolled or pressed a modifier key such as
Shift in the last 1.5 seconds - that is taken to be you.
- **It does not pretend.** When something is refused or fails, it says so and
says why. The most common complaint about agents driving a computer is that
they carry on as if it worked.
Expand Down Expand Up @@ -133,11 +136,11 @@ and that its chain holds.

<!-- log-uddrag:start -->
```jsonl
{"ts":"2026-10-20T18:52:45.701Z","session":"fabb2663","call":"746fffee","tool":"computer_type","tier":"write","args":{"app":{"length":8,"sha256_12":"1b330dc3a979","salted":true},"text":{"length":37,"sha256_12":"51f664abcb74","salted":true}},"target":"com.apple.TextEdit","mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"CMCP_MODE=allow","l":1,"kaede":"e02a3d1b3560ea17"}
{"ts":"2026-10-20T18:52:45.705Z","session":"fabb2663","call":"746fffee","tool":"computer_type","tier":"write","target":"com.apple.TextEdit","phase":"executing","l":1,"kaede":"c1e763106513c3e7"}
{"ts":"2026-10-20T18:52:46.112Z","session":"fabb2663","call":"746fffee","tool":"computer_type","outcome":"ok","effect":"sent","l":1,"kaede":"b053781eb3511c4d"}
{"ts":"2026-10-20T18:52:47.761Z","session":"fabb2663","call":"88f2d9ae","tool":"computer_menu","tier":"write","args":{"app":{"length":6,"sha256_12":"0771e2f86fa0","salted":true},"path":"File > Move to Trash"},"target":"com.apple.finder","mode":"allow","asker":"menubar","presence":{"idle_at_ask":600,"idle_at_end":600,"server":"0.4.0","icon":"0.4.0","box":"on","sessions":1,"surface_derived":"box+menu"},"decision":"denied","asked":true,"reason":"background mode: nobody answered in the menu bar in time","l":1,"kaede":"9b82d6ae5a36942d"}
{"ts":"2026-10-20T18:52:48.229Z","session":"fabb2663","call":"0ba79155","tool":"computer_type","tier":"write","args":{"app":{"length":9,"sha256_12":"84b5a01fae6a","salted":true},"text":{"length":7,"sha256_12":"b56e1d9fbfd2","salted":true}},"target":"com.1password.1password","mode":"allow","asker":"custom","decision":"denied","asked":false,"reason":"background mode: this would need a dialog, and a dialog takes the screen (a password app can never be approved from the menu bar)","l":1,"kaede":"1be981d7eeaf7445"}
{"ts":"2026-10-31T22:35:10.230Z","session":"56f00545","call":"02bc741b","tool":"computer_type","tier":"write","args":{"app":{"length":8,"sha256_12":"78743a52a54c","salted":true},"text":{"length":37,"sha256_12":"cdde26c85cca","salted":true}},"target":"com.apple.TextEdit","mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"CMCP_MODE=allow","l":1,"kaede":"4fb5f61a6e442962"}
{"ts":"2026-10-31T22:35:10.231Z","session":"56f00545","call":"02bc741b","tool":"computer_type","tier":"write","target":"com.apple.TextEdit","phase":"executing","l":1,"kaede":"13cd03c71bfb3b38"}
{"ts":"2026-10-31T22:35:10.321Z","session":"56f00545","call":"02bc741b","tool":"computer_type","outcome":"ok","effect":"sent","l":1,"kaede":"79696176e8603981"}
{"ts":"2026-10-31T22:35:11.481Z","session":"56f00545","call":"ac33c074","tool":"computer_menu","tier":"write","args":{"app":{"length":6,"sha256_12":"2c65732d0d4e","salted":true},"path":"File > Move to Trash"},"target":"com.apple.finder","mode":"allow","asker":"menubar","presence":{"idle_at_ask":600,"idle_at_end":600,"server":"0.4.1","icon":"0.4.1","box":"on","sessions":1,"surface_derived":"box+menu"},"decision":"denied","asked":true,"reason":"background mode: nobody answered in the menu bar in time","l":1,"kaede":"ad20dddb1195fa7a"}
{"ts":"2026-10-31T22:35:11.578Z","session":"56f00545","call":"5b15b900","tool":"computer_type","tier":"write","args":{"app":{"length":9,"sha256_12":"ac0afc1b1e97","salted":true},"text":{"length":7,"sha256_12":"f0b579393774","salted":true}},"target":"com.1password.1password","mode":"allow","asker":"custom","decision":"denied","asked":false,"reason":"background mode: this would need a dialog, and a dialog takes the screen (a password app can never be approved from the menu bar)","l":1,"kaede":"2332aa9606dd896e"}
```
<!-- log-uddrag:end -->

Expand Down Expand Up @@ -237,13 +240,14 @@ the same way - including when the call failed halfway, because a half-done
write that took the screen must not be the one line that stays silent.
`press` and `menu` carry it too: an app can bring itself forward in response
(measured: File > New Finder Window did), and when it does, the answer says so
and the front is handed straight back to the app you were in (`gave_back`).
and the front is handed straight back to the app you were in - `gave_back`
says whether that worked.
`set_value`, `drag`, `paste` and `move` do not carry the field yet.

`computer_launch` joins them with `background: true`: the app starts behind
what you are doing. Many apps bring themselves forward as they start - six of
eight did on a clean Mac - and when one does, the front is handed straight back
and the answer says `took_screen` and `gave_back`. It is a moment, not nothing. Seven are still held back:
and the answer says `took_screen`, and in `gave_back` whether that worked. It is a moment, not nothing. Seven are still held back:
`move`, `activate`, `quit`, `space`, `window`, `drag` and `paste` - until you lend
the screen: `computer_request_screen` asks you in the box in the corner of your
screen (and in the menu bar), one agent at a time, approved with Touch ID, for at
Expand Down
2 changes: 1 addition & 1 deletion bundle/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": "0.3",
"name": "computer-mcp",
"display_name": "Computer MCP",
"version": "0.4.0",
"version": "0.4.1",
"description": "macOS computer use you can leave running: it stays behind your window and never touches passwords.",
"long_description": "A macOS computer-use MCP server built for the hours you are not watching. It acts in windows behind the one you are in and leaves your pointer alone, it says so when something fails, several can run at once, and it will not go near your password manager. Every action is written to an append-only audit log. Runs in any MCP client, macOS, MIT, no account.",
"author": {
Expand Down
Loading
Loading