Open-source, self-hosted alternative to OpenAI Dots, Grok Bot. Built to be undetectable by anti-bot systems.
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
host: every task end is told, an approval adds one server once, and no state nobody sets - A task whose task.created could not be delivered is failed with a task.failed event in the same transaction (the guest's type: a client follows one), so the web no longer shows it running for good; a commit point covers it. - markDelivered marks the row and its run in one statement. - add_mcp_server: the host uses up the approval that allowed the call (approvals.used_at, migration 0013), found in one statement with jsonb equality instead of the newest 500 and a hand-made canonical JSON; a call refused for its entry keeps its approval. The permission is typed. - Dot DISABLED and VM IDLE, which nothing ever wrote, are gone from the states, the checks (migration 0014), the queries and the web. - Unused exports removed (latestId, activeForDot, hasPending, isVmState, isDotState, API_TOKEN_ENV, MIN_TOKEN_LENGTH). - One BackgroundWork for the scheduler and the lifecycle; syncGuest marks a Dot suspect itself when its push fails. - The scheduler alone checks a message, a note and "always"; /api/stream resolves its Dot with historyDotId. - The MCP secrets of a push are read in one query; EventLog.stream keeps one id instead of every replayed one. - The event schemas and the declared event types are held equal by the typecheck, so the parsers need no cast. - start.test waits for the three requests instead of 200 ms; the pre-push hook says what only CI runs; docs follow. | 7 天前 | |
browser: never pinned; the image takes the newest release and the engine reads the server it finds A Dot keeps the golden image it was made from and boots every new runtime disk, so the engine already talked to servers other than the one its pinned copy of the interface described. The engine now reads the interface from the installed server when it starts (nanobot/dots/server_interface.py, server_capture.py run as dot by the server's own python): the page tools are what that server serves, a page tool it does not serve is not offered (GET /tools says so), and a Dot whose server cannot be read offers no page tool and its launches say why. With nothing in the engine tied to a version, the image no longer pins one: each build asks PyPI for the newest invisible-playwright-mcp, the newest invisible-playwright it accepts and the invisible-core that one pins (browser-release.ts). The three enter the inputs digest, pins.env and the manifest, which records what was installed. mcp-requirements.lock and capture-mcp-interface.py go; the copy of the interface becomes a test fixture. The owner's no-other-browser rule is checked at build on what was actually installed (builder/other-browsers.txt), and the golden image workflow runs every six hours so a new release is published as a prebuilt image. | 4 天前 | |
api tests: the test of every Dot's channels removes the channels it added It added two channels and left them running for the rest of the file and its teardown, the only channels there; on one Windows run that teardown did not finish in 60 s (not reproduced in twelve runs under load here). A test stops what it starts: the two channels are removed at its end, and the teardown is what it was before they came. | 7 天前 | |
browser: never pinned; the image takes the newest release and the engine reads the server it finds A Dot keeps the golden image it was made from and boots every new runtime disk, so the engine already talked to servers other than the one its pinned copy of the interface described. The engine now reads the interface from the installed server when it starts (nanobot/dots/server_interface.py, server_capture.py run as dot by the server's own python): the page tools are what that server serves, a page tool it does not serve is not offered (GET /tools says so), and a Dot whose server cannot be read offers no page tool and its launches say why. With nothing in the engine tied to a version, the image no longer pins one: each build asks PyPI for the newest invisible-playwright-mcp, the newest invisible-playwright it accepts and the invisible-core that one pins (browser-release.ts). The three enter the inputs digest, pins.env and the manifest, which records what was installed. mcp-requirements.lock and capture-mcp-interface.py go; the copy of the interface becomes a test fixture. The owner's no-other-browser rule is checked at build on what was actually installed (builder/other-browsers.txt), and the golden image workflow runs every six hours so a new release is published as a prebuilt image. | 4 天前 | |
smoke and dependencies: the stand-in is a server package, and the capture runs on the server's python The engine smoke found its stand-in by fake_mcp_server.py on the command line; installed the way the real server is, it runs as `python -I -B -m invisible_playwright_mcp`, and that command line is what the checks look for. test_dependencies names server_capture.py as a module another interpreter runs: its invisible_playwright_mcp import is the installed server's, not a dependency of the engine. | 4 天前 | |
smoke and dependencies: the stand-in is a server package, and the capture runs on the server's python The engine smoke found its stand-in by fake_mcp_server.py on the command line; installed the way the real server is, it runs as `python -I -B -m invisible_playwright_mcp`, and that command line is what the checks look for. test_dependencies names server_capture.py as a module another interpreter runs: its invisible_playwright_mcp import is the installed server's, not a dependency of the engine. | 4 天前 | |
licenses: nothing GPL is installed by default; the WhatsApp client is an opt-in install, and the GeoIP notices name the data licenses (S3) What and why npm ci installed Baileys and its GPL-3.0 dependency libsignal for everyone. Now no package of the default install needs a GPL license: - Baileys is declared by no workspace (not regular, dev, optional or peer) and is out of the root package-lock.json (49 packages fewer: libsignal, curve25519-js, whatsapp-rust-bridge and what only the client needed). - It lives in optional/whatsapp/: its own package.json (Baileys 7.0.0-rc14, one exact version) and package-lock.json (integrity hash of every package), outside the workspaces. One command installs it: npm run whatsapp:install (npm ci --prefix optional/whatsapp --ignore-scripts). - packages/channels/src/whatsapp-baileys/client.ts is the one file that names the library. It looks for it in that folder when a connection opens, loads it by path only if it is there, and otherwise throws WhatsAppClientMissingError, whose message is the command and INVISIBLE_DOTS_WHATSAPP=1. That text is the channel status, is logged at server start when the variable is set without the client, and is what linking answers when WhatsApp is off (WHATSAPP_ENABLE_HELP). - Nothing imports the library by name, not even as types: the adapter writes down what it uses of it (WhatsAppClient) and compiles without it. A typecheck with the client installed (npm run typecheck:whatsapp, tsconfig.whatsapp.json, test-optin/ shape.ts) proves the real module has that shape and that the key groups are the library's own, which the old compile-time check did. The tests that need the real library moved to packages/channels/test-optin and run with npm run test:whatsapp (vitest.whatsapp.config.ts); a new CI job, whatsapp-client, installs the client the way a person does and runs both, with PostgreSQL. The command bundle no longer lists baileys as external: it has no import of it. - tests/repo/default-install-licenses.test.ts scans the root lock for licenses: no GPL or AGPL (SPDX expressions read with OR/AND), a license stated for every package, LGPL only among @img/sharp-* (Next.js's optional image binaries, named in the notices), and the same scan flags libsignal in the opt-in lock. tests/repo/whatsapp-optin.test.ts now proves the opt-in shape: no workspace declares it, it is outside the workspaces, pinned with integrity, one documented command, one loader, no static import, not in the bundle. GeoIP notices The first entry said the merged file is GPL-3.0, which is the license GitHub shows on daijro/geoip-all-in-one: the license of its scripts. Read at the pinned release (2026.09.30): its README states no license for the merged data and only credits IP2Location LITE, GeoLite2 and DB-IP. geoip-notices.ts now lists the actual data licenses of the sources (CC BY-SA 4.0 for IP2Location LITE, IPinfo and IPLocate.io; the GeoLite2 EULA; CC BY 4.0 for DB-IP Lite; CC0 1.0 for the tdulcet GeoFeed + Whois + ASN database, which sapics lists as PDDL 1.0; ODbL 1.0 for the OpenStreetMap-derived time zone boundaries), with GEOIP_STATEMENT: the image is built by the person on their own machine, invisible_dots does not publish or redistribute it, and whoever shares it meets those terms. Every golden manifest records it as notices_statement beside notices. THIRD_PARTY_NOTICES.md, the README, the image builder README and the architecture document say the same; the third-party notices test pins the source list and license of each source and keeps the notices, the statement and the manifest equal. Tests removed or moved (none of a feature that went away) - packages/channels/test/whatsapp-auth.test.ts (9 tests) moved to packages/channels/test-optin/auth-state.test.ts, unchanged in what it asserts: it needs the real BufferJSON, initAuthCreds and protobuf, which are not in the default install. It runs in the whatsapp suite on PGlite and PostgreSQL. - packages/channels/test/baileys.test.ts: "reading a Baileys message" (5 tests) and "the connector on a socket that cannot connect" (1) moved to test-optin/reading.test.ts for the same reason; endOf and the addresses (4 tests) stay in the default suite. - hub-whatsapp.test.ts "goes with the Dot" used the real library only to give the hub a session whose writes must not come back; it now uses a JSON stand-in for the library's three helpers (the real ones are in test-optin/auth-state.test.ts). - tests/repo/whatsapp-optin.test.ts: the five old checks are replaced by checks of the new shape; "pinned to one exact version in the channels package and the lock file", "declared by no other package" and "imported by the glue file alone" no longer apply because the dependency is not in the channels package or the root lock and no source imports it. Floors - vitest: linux 1187 -> 1196, win32 1190 -> 1199 (measured 1199 on win32). - postgres: min_passed 675 -> 659 and pg 273 -> 264, LOWERED: the 9 pg runs and 9 PGlite runs of the auth-state tests moved to the whatsapp suite, and the 6 moved glue tests (measured 659 passed, 264 pg, against a real PostgreSQL 18.4). - whatsapp (new): linux 24 with 9 pg (CI, PostgreSQL), win32 15 (no PostgreSQL). Suites: typecheck, typecheck:whatsapp, vitest 1199 passed (win32), postgres subset 659 passed with 264 pg, whatsapp suite 24 passed with PostgreSQL and 15 without, go test, engine 2778 passed, web build, english and claims gates clean. | 12 天前 | |
channels tests: the 429 poll test has a bot of its own It failed now and then in CI (four runs since 2026-10-08), always right after the test that polls TOKEN every few milliseconds with a 409: a poll of that test still on its way when it ended was answered after the next test had queued its 429 on the same token, as Telegram answers a request whose client has gone, so the stray poll took the 429 and the new poller connected without the error the test waits for. The 429 test now uses a token no other test polls. | 7 天前 | |
browser: never pinned; the image takes the newest release and the engine reads the server it finds A Dot keeps the golden image it was made from and boots every new runtime disk, so the engine already talked to servers other than the one its pinned copy of the interface described. The engine now reads the interface from the installed server when it starts (nanobot/dots/server_interface.py, server_capture.py run as dot by the server's own python): the page tools are what that server serves, a page tool it does not serve is not offered (GET /tools says so), and a Dot whose server cannot be read offers no page tool and its launches say why. With nothing in the engine tied to a version, the image no longer pins one: each build asks PyPI for the newest invisible-playwright-mcp, the newest invisible-playwright it accepts and the invisible-core that one pins (browser-release.ts). The three enter the inputs digest, pins.env and the manifest, which records what was installed. mcp-requirements.lock and capture-mcp-interface.py go; the copy of the interface becomes a test fixture. The owner's no-other-browser rule is checked at build on what was actually installed (builder/other-browsers.txt), and the golden image workflow runs every six hours so a new release is published as a prebuilt image. | 4 天前 | |
guest: dot-install only installs, the images are what their inputs say, and the Go copies of the protocol are held - dot-install refused nothing apt reads as an action: "foo-" removed foo, as root. A name can no longer end in "-"; a test runs the real script against stubs. - The VM proxy's setup is runtime/vmproxy.py, staged on the runtime ISO: a bad value, a host that does not resolve and no default route each say so (exit 3, 4, 5) instead of all reading "not socks5"; the firewall still drops all. The smoke runs the file itself. - dot-agentd is built one way everywhere (-trimpath -buildvcs=false -ldflags=-s -w): a commit no longer changes the binary and the runtime ISO. go.mod pins the toolchain, setup-go@v6 reads it, a repo test keeps every spelling equal. - The golden image's apt packages come from an Ubuntu snapshot (pins.json apt_snapshot, in the inputs digest); the browser environment installs wheels only, with no cache left in the image. - tests/repo/agentd-protocol.test.ts compares the Go routes and constants (and the engine's defaults) with packages/shared; a Linux test runs the real dot-agentd under the real GuestClient: proof, auth, exec, files, the agent proxy and its SSE. - vm-manager: one assertImages, the VM bounds from CONFIG_BOUNDS, the pid file in its own module; one resolveImageVersion and publishImage for the golden, runtime and prebuilt images. - Fixed-sleep tests wait for their signal; the docs no longer say the images are never published or speak of CD-ROMs. | 7 天前 | |
repo: delete the earlier TypeScript engine and agent guest-runtime/ and guest/invisible-dots-agent/ are replaced by the Python engine; no host code imported them. Their workspaces, the agent bundle on the runtime disk, its CI build step and tests/e2e (it drove the old agent's tools) go with them. | 13 天前 | |
docs: the README animation is built from photos in the tree, with new characters The six hero GIFs were rendered from pages that lived only in a scratch folder, so changing one character meant editing frames. docs/hero/ now holds every piece, in three layers, each made from the one before: photos/ characters.png as an image model draws it, on white; cut_out.py turns it into one cut-out per theme (shadows kept on light, removed on dark, and only the white connected to the edge touched, so the eyes stay) html/ wide, mobile and small pages that compose the photos; renderLoop(t) draws the frame at second t, and opened in a browser each page plays its own loop build.mjs photos -> frames (Chromium, 12 a second) -> docs/images/hero-*.gif, with the same palette and dither as before A fourth page, html/social.html, builds docs/images/social-preview.png, the repository's social preview, from the same photos. The characters are new: the same four, colours inverted, each with a role it can carry (a hard hat, sunglasses, a beret, a magnifying glass), all still angry. The scenes, their words and their timing are unchanged. | 7 天前 | |
wip: invisible_dots first integration (libvirt design, before the QEMU conversion) | 16 天前 | |
Community files: how to contribute, the code of conduct and the security policy, and issue and PR templates that ask for what a report of this project needs (doctor, logs, commit, host) | 11 天前 | |
Community files: how to contribute, the code of conduct and the security policy, and issue and PR templates that ask for what a report of this project needs (doctor, logs, commit, host) | 11 天前 | |
dots: invisible-playwright-mcp's interface under its own name The command is the pinned package's ui, reached through its command group so the .env beside it is read. Nothing of the loop, the browser or the page is re-implemented here. | 19 天前 | |
docs: MCP servers in the architecture and the guide; no longer out of scope Section 7 declares them and their permission, 8.3 says where they run, when they start and what the model gets, 4.3 how their secrets travel, 5.3 and 9.6 the routes, 8.8 the engine's manager. The guide has a section on them, the two commands, and the README one row. | 8 天前 | |
Community files: how to contribute, the code of conduct and the security policy, and issue and PR templates that ask for what a report of this project needs (doctor, logs, commit, host) | 11 天前 | |
clients: one wording for an approval everywhere, the CLI reads what it shows and can stop what it starts - The tool and permission labels move from the web to packages/shared (labels.ts, still checked against permissions.py): Telegram, WhatsApp and the CLI ask "The Dot wants to run a command" with "Run commands (high risk)", as the web card does, and the CLI names the Dot. - The event reader moves from the web to the SDK: `logs` reads only the newest events and follows on; `approvals --all` keeps the newest 500 and `status` reads the 10 it shows. - New CLI commands: cancel, delete --yes, update with the config version (a concurrent save is a 409). The CLI's version comes from its package. - The web's tool and approval steps are one model (steps.ts) for the chat, the task story and the activity; one outcome table and one duration format. - The inbox keys answer only while the approvals list has the focus (WCAG 2.1.4); useResource and the Dot shell's context keep their identity across renders. - setup --all no longer sends the person to a sign-in that does not exist; the MCP panel says the Dot can add a server; the e2e contract declares every CLI command run.ts runs, and a test holds it; apps/web's second vitest config is gone; docs follow. | 7 天前 | |
host: the pieces every package uses live in shared, so a package never depends on an app Clock, Logger, silentLogger, errorMessage, ControlPlaneError, notFound and the stderr logger move from apps/scheduler to packages/shared; packages/channels and apps/api import them from there, and channels keeps the scheduler for its tests only. One abortableSleep replaces four copies (scheduler, CLI, SDK, WhatsApp); the one shared had slept the whole time on a signal that had already aborted. The API reports its package's version, as the CLI does, instead of a hard-coded 0.1.0. | 7 天前 | |
merge lane-lic: Baileys and libsignal opt in, true GeoIP licences Brings in S3 (lane-lic, tip a39316c2): the WhatsApp client (Baileys, which depends on libsignal, GPL-3.0) is no longer in the default npm install; it lives under optional/whatsapp with its own lock file and is installed by npm run whatsapp:install. A test asserts that a default install holds no GPL package; the GeoIP data is described with its true licences. Conflicts and resolutions: - .github/test-floors.json: kept the final review's playwright floor and its description, added this lane's whatsapp floor and its description, and the counts of the previous merge. Measured values replace them in the floors commit that follows. - .github/scripts/test-guard.mjs, tests/repo/test-guard.test.ts: both sides added a suite name to the usage text, the comment and the list CI must run; the result accepts whatsapp and playwright both. - package-lock.json: regenerated from the final review's lock file with npm install --package-lock-only after packages/channels/package.json dropped baileys, so the lock holds neither baileys nor libsignal (the opt-in client has its own lock under optional/whatsapp). - packages/channels/src/whatsapp-baileys/baileys.ts: the final review added textContent (linkPreview: null, so Baileys fetches no link of a text from the control plane) and exported BaileysConnection; this lane moved the library behind client.ts and added socketConfig. Both stay; WhatsAppSocket.sendMessage in client.ts now types linkPreview, so the typecheck made with the client installed holds textContent against the adapter's view of the socket. - packages/channels/test/baileys.test.ts: the final review's two tests of what is sent. The one that runs Baileys' own generateWAMessageContent needs the library, so it moved to packages/channels/test-optin/ sending.test.ts (npm run test:whatsapp); the one with a fake socket needs no library and stays in the default suite. No test removed. Verified on this merge: typecheck, vitest 2272 passed, typecheck:whatsapp, test:whatsapp 16 passed on a Windows host. | 12 天前 | |
QEMU direct on Linux and Windows, PGlite, no QMP, review fixes, real-VM e2e | 16 天前 | |
wip: invisible_dots first integration (libvirt design, before the QEMU conversion) | 16 天前 | |
bench: agent benchmarks on real Dots, through Harbor, and a suite of 25 tasks of our own Harbor (the harness of Terminal-Bench) runs each task in a new Dot: dots_harbor/ is its environment (the Dot is created through the API, the task's Dockerfile is replayed as dot, with apt through dot-install, and the task's root paths are moved under /home/dot/bench) and its agent (the instruction goes to the Dot as a task). Every call goes through bridge.ts, on the end-to-end run's outside driver. Harbor's registry datasets run the same way. tasks/, written by author.py from fixed seeds: shell, files, coding, data analysis, the computer's settings, questions with one answer, two long tasks, and what a Dot is for (its own automation, a careful cleanup, a request it must refuse). In Dots: the oracle scores 25/25 and doing nothing 0/25; the Dot with z-ai/glm-5.3-flash scored 23/25 in 9 minutes, 4 at a time (one miss was the grader's rounding, now fixed). | 10 天前 | |
licenses: nothing GPL is installed by default; the WhatsApp client is an opt-in install, and the GeoIP notices name the data licenses (S3) What and why npm ci installed Baileys and its GPL-3.0 dependency libsignal for everyone. Now no package of the default install needs a GPL license: - Baileys is declared by no workspace (not regular, dev, optional or peer) and is out of the root package-lock.json (49 packages fewer: libsignal, curve25519-js, whatsapp-rust-bridge and what only the client needed). - It lives in optional/whatsapp/: its own package.json (Baileys 7.0.0-rc14, one exact version) and package-lock.json (integrity hash of every package), outside the workspaces. One command installs it: npm run whatsapp:install (npm ci --prefix optional/whatsapp --ignore-scripts). - packages/channels/src/whatsapp-baileys/client.ts is the one file that names the library. It looks for it in that folder when a connection opens, loads it by path only if it is there, and otherwise throws WhatsAppClientMissingError, whose message is the command and INVISIBLE_DOTS_WHATSAPP=1. That text is the channel status, is logged at server start when the variable is set without the client, and is what linking answers when WhatsApp is off (WHATSAPP_ENABLE_HELP). - Nothing imports the library by name, not even as types: the adapter writes down what it uses of it (WhatsAppClient) and compiles without it. A typecheck with the client installed (npm run typecheck:whatsapp, tsconfig.whatsapp.json, test-optin/ shape.ts) proves the real module has that shape and that the key groups are the library's own, which the old compile-time check did. The tests that need the real library moved to packages/channels/test-optin and run with npm run test:whatsapp (vitest.whatsapp.config.ts); a new CI job, whatsapp-client, installs the client the way a person does and runs both, with PostgreSQL. The command bundle no longer lists baileys as external: it has no import of it. - tests/repo/default-install-licenses.test.ts scans the root lock for licenses: no GPL or AGPL (SPDX expressions read with OR/AND), a license stated for every package, LGPL only among @img/sharp-* (Next.js's optional image binaries, named in the notices), and the same scan flags libsignal in the opt-in lock. tests/repo/whatsapp-optin.test.ts now proves the opt-in shape: no workspace declares it, it is outside the workspaces, pinned with integrity, one documented command, one loader, no static import, not in the bundle. GeoIP notices The first entry said the merged file is GPL-3.0, which is the license GitHub shows on daijro/geoip-all-in-one: the license of its scripts. Read at the pinned release (2026.09.30): its README states no license for the merged data and only credits IP2Location LITE, GeoLite2 and DB-IP. geoip-notices.ts now lists the actual data licenses of the sources (CC BY-SA 4.0 for IP2Location LITE, IPinfo and IPLocate.io; the GeoLite2 EULA; CC BY 4.0 for DB-IP Lite; CC0 1.0 for the tdulcet GeoFeed + Whois + ASN database, which sapics lists as PDDL 1.0; ODbL 1.0 for the OpenStreetMap-derived time zone boundaries), with GEOIP_STATEMENT: the image is built by the person on their own machine, invisible_dots does not publish or redistribute it, and whoever shares it meets those terms. Every golden manifest records it as notices_statement beside notices. THIRD_PARTY_NOTICES.md, the README, the image builder README and the architecture document say the same; the third-party notices test pins the source list and license of each source and keeps the notices, the statement and the manifest equal. Tests removed or moved (none of a feature that went away) - packages/channels/test/whatsapp-auth.test.ts (9 tests) moved to packages/channels/test-optin/auth-state.test.ts, unchanged in what it asserts: it needs the real BufferJSON, initAuthCreds and protobuf, which are not in the default install. It runs in the whatsapp suite on PGlite and PostgreSQL. - packages/channels/test/baileys.test.ts: "reading a Baileys message" (5 tests) and "the connector on a socket that cannot connect" (1) moved to test-optin/reading.test.ts for the same reason; endOf and the addresses (4 tests) stay in the default suite. - hub-whatsapp.test.ts "goes with the Dot" used the real library only to give the hub a session whose writes must not come back; it now uses a JSON stand-in for the library's three helpers (the real ones are in test-optin/auth-state.test.ts). - tests/repo/whatsapp-optin.test.ts: the five old checks are replaced by checks of the new shape; "pinned to one exact version in the channels package and the lock file", "declared by no other package" and "imported by the glue file alone" no longer apply because the dependency is not in the channels package or the root lock and no source imports it. Floors - vitest: linux 1187 -> 1196, win32 1190 -> 1199 (measured 1199 on win32). - postgres: min_passed 675 -> 659 and pg 273 -> 264, LOWERED: the 9 pg runs and 9 PGlite runs of the auth-state tests moved to the whatsapp suite, and the 6 moved glue tests (measured 659 passed, 264 pg, against a real PostgreSQL 18.4). - whatsapp (new): linux 24 with 9 pg (CI, PostgreSQL), win32 15 (no PostgreSQL). Suites: typecheck, typecheck:whatsapp, vitest 1199 passed (win32), postgres subset 659 passed with 264 pg, whatsapp suite 24 passed with PostgreSQL and 15 without, go test, engine 2778 passed, web build, english and claims gates clean. | 12 天前 | |
guest: dot-install only installs, the images are what their inputs say, and the Go copies of the protocol are held - dot-install refused nothing apt reads as an action: "foo-" removed foo, as root. A name can no longer end in "-"; a test runs the real script against stubs. - The VM proxy's setup is runtime/vmproxy.py, staged on the runtime ISO: a bad value, a host that does not resolve and no default route each say so (exit 3, 4, 5) instead of all reading "not socks5"; the firewall still drops all. The smoke runs the file itself. - dot-agentd is built one way everywhere (-trimpath -buildvcs=false -ldflags=-s -w): a commit no longer changes the binary and the runtime ISO. go.mod pins the toolchain, setup-go@v6 reads it, a repo test keeps every spelling equal. - The golden image's apt packages come from an Ubuntu snapshot (pins.json apt_snapshot, in the inputs digest); the browser environment installs wheels only, with no cache left in the image. - tests/repo/agentd-protocol.test.ts compares the Go routes and constants (and the engine's defaults) with packages/shared; a Linux test runs the real dot-agentd under the real GuestClient: proof, auth, exec, files, the agent proxy and its SSE. - vm-manager: one assertImages, the VM bounds from CONFIG_BOUNDS, the pid file in its own module; one resolveImageVersion and publishImage for the golden, runtime and prebuilt images. - Fixed-sleep tests wait for their signal; the docs no longer say the images are never published or speak of CD-ROMs. | 7 天前 | |
licenses: nothing GPL is installed by default; the WhatsApp client is an opt-in install, and the GeoIP notices name the data licenses (S3) What and why npm ci installed Baileys and its GPL-3.0 dependency libsignal for everyone. Now no package of the default install needs a GPL license: - Baileys is declared by no workspace (not regular, dev, optional or peer) and is out of the root package-lock.json (49 packages fewer: libsignal, curve25519-js, whatsapp-rust-bridge and what only the client needed). - It lives in optional/whatsapp/: its own package.json (Baileys 7.0.0-rc14, one exact version) and package-lock.json (integrity hash of every package), outside the workspaces. One command installs it: npm run whatsapp:install (npm ci --prefix optional/whatsapp --ignore-scripts). - packages/channels/src/whatsapp-baileys/client.ts is the one file that names the library. It looks for it in that folder when a connection opens, loads it by path only if it is there, and otherwise throws WhatsAppClientMissingError, whose message is the command and INVISIBLE_DOTS_WHATSAPP=1. That text is the channel status, is logged at server start when the variable is set without the client, and is what linking answers when WhatsApp is off (WHATSAPP_ENABLE_HELP). - Nothing imports the library by name, not even as types: the adapter writes down what it uses of it (WhatsAppClient) and compiles without it. A typecheck with the client installed (npm run typecheck:whatsapp, tsconfig.whatsapp.json, test-optin/ shape.ts) proves the real module has that shape and that the key groups are the library's own, which the old compile-time check did. The tests that need the real library moved to packages/channels/test-optin and run with npm run test:whatsapp (vitest.whatsapp.config.ts); a new CI job, whatsapp-client, installs the client the way a person does and runs both, with PostgreSQL. The command bundle no longer lists baileys as external: it has no import of it. - tests/repo/default-install-licenses.test.ts scans the root lock for licenses: no GPL or AGPL (SPDX expressions read with OR/AND), a license stated for every package, LGPL only among @img/sharp-* (Next.js's optional image binaries, named in the notices), and the same scan flags libsignal in the opt-in lock. tests/repo/whatsapp-optin.test.ts now proves the opt-in shape: no workspace declares it, it is outside the workspaces, pinned with integrity, one documented command, one loader, no static import, not in the bundle. GeoIP notices The first entry said the merged file is GPL-3.0, which is the license GitHub shows on daijro/geoip-all-in-one: the license of its scripts. Read at the pinned release (2026.09.30): its README states no license for the merged data and only credits IP2Location LITE, GeoLite2 and DB-IP. geoip-notices.ts now lists the actual data licenses of the sources (CC BY-SA 4.0 for IP2Location LITE, IPinfo and IPLocate.io; the GeoLite2 EULA; CC BY 4.0 for DB-IP Lite; CC0 1.0 for the tdulcet GeoFeed + Whois + ASN database, which sapics lists as PDDL 1.0; ODbL 1.0 for the OpenStreetMap-derived time zone boundaries), with GEOIP_STATEMENT: the image is built by the person on their own machine, invisible_dots does not publish or redistribute it, and whoever shares it meets those terms. Every golden manifest records it as notices_statement beside notices. THIRD_PARTY_NOTICES.md, the README, the image builder README and the architecture document say the same; the third-party notices test pins the source list and license of each source and keeps the notices, the statement and the manifest equal. Tests removed or moved (none of a feature that went away) - packages/channels/test/whatsapp-auth.test.ts (9 tests) moved to packages/channels/test-optin/auth-state.test.ts, unchanged in what it asserts: it needs the real BufferJSON, initAuthCreds and protobuf, which are not in the default install. It runs in the whatsapp suite on PGlite and PostgreSQL. - packages/channels/test/baileys.test.ts: "reading a Baileys message" (5 tests) and "the connector on a socket that cannot connect" (1) moved to test-optin/reading.test.ts for the same reason; endOf and the addresses (4 tests) stay in the default suite. - hub-whatsapp.test.ts "goes with the Dot" used the real library only to give the hub a session whose writes must not come back; it now uses a JSON stand-in for the library's three helpers (the real ones are in test-optin/auth-state.test.ts). - tests/repo/whatsapp-optin.test.ts: the five old checks are replaced by checks of the new shape; "pinned to one exact version in the channels package and the lock file", "declared by no other package" and "imported by the glue file alone" no longer apply because the dependency is not in the channels package or the root lock and no source imports it. Floors - vitest: linux 1187 -> 1196, win32 1190 -> 1199 (measured 1199 on win32). - postgres: min_passed 675 -> 659 and pg 273 -> 264, LOWERED: the 9 pg runs and 9 PGlite runs of the auth-state tests moved to the whatsapp suite, and the 6 moved glue tests (measured 659 passed, 264 pg, against a real PostgreSQL 18.4). - whatsapp (new): linux 24 with 9 pg (CI, PostgreSQL), win32 15 (no PostgreSQL). Suites: typecheck, typecheck:whatsapp, vitest 1199 passed (win32), postgres subset 659 passed with 264 pg, whatsapp suite 24 passed with PostgreSQL and 15 without, go test, engine 2778 passed, web build, english and claims gates clean. | 12 天前 |
<div align="center">
<picture>
<source media="(max-width: 374px) and (prefers-color-scheme: dark)" srcset="docs/images/hero-small-dark.gif">
<source media="(max-width: 374px)" srcset="docs/images/hero-small-light.gif">
<source media="(max-width: 1239px) and (prefers-color-scheme: dark)" srcset="docs/images/hero-mobile-dark.gif">
<source media="(max-width: 1239px)" srcset="docs/images/hero-mobile-light.gif">
<source media="(prefers-color-scheme: dark)" srcset="docs/images/hero-dark.gif">
<img alt="invisible_dots,一个开源、可自托管的 OpenAI Dots、Meta Muse、Grok Bot、Manus Cue 和 Claude Cowork 替代方案。动画演示了 Dot 的工作方式:只需在对话中告诉它一次,让它每月保存一家店铺的发票并将总额发送到 Telegram,它便会在自己的计算机上独立运作(一台桌面电脑,配有终端、文件以及一个保存着店铺登录状态的 Firefox),将操作步骤沉淀为一项技能,在添加月度自动化之前会先征询确认,之后便每月准时发送总额;多个 Dot,各占一台计算机。" src="docs/images/hero-light.gif" width="100%">
</picture>
</div>
OpenAI Dots 和 Grok Bot 的开源、可自托管替代方案。专为规避反机器人系统检测而构建。
## 快速开始
你需要 Node 24+、Go 1.25+、Git 以及硬件虚拟化支持(x86-64),另需一个 OpenRouter 密钥。
**Windows**(PowerShell):
winget install -e --id OpenJS.NodeJS.LTS; winget install -e --id GoLang.Go; winget install -e --id Git.Git
git clone https://github.com/feder-cr/invisible_dots; cd invisible_dots
npm ci; npm run build --workspace @invisible-dots/cli
node apps/cli/dist/invisible-dots.mjs setup --all
node apps/cli/dist/invisible-dots.mjs server
Linux (Ubuntu 24.04):
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash - && sudo apt-get install -y nodejs git && sudo snap install go --classic
git clone https://github.com/feder-cr/invisible_dots && cd invisible_dots
npm ci && npm run build --workspace @invisible-dots/cli
node apps/cli/dist/invisible-dots.mjs setup --all
node apps/cli/dist/invisible-dots.mjs server
setup --all 会安装 QEMU 并启用硬件加速(KVM 或 Windows Hypervisor Platform),然后构建或下载 Dot 的镜像;重启后再次运行即可从中断处继续。接着打开 http://127.0.0.2:3000,粘贴你的 OpenRouter key,创建你的第一个 Dot。每一步及其可能的失败情况,参见指南中的快速入门。
可以向 Dot 提出什么
任何需要一台电脑和人类判断力的事情,无论需要多长时间:
打开一个名为 research 的浏览器身份,访问 https://example.com,告诉我页面的标题和第一句话。保持浏览器打开。
每天早上,查询未来两周内米兰到里斯本的单程票价,写入 ~/workspace/fares.csv,并告诉我最便宜的日期。
使用 shopping 身份登录商店,将本月的发票下载到 ~/documents,并记住发票页面的位置以便下次使用。
Dot 拥有什么
| 一台专属电脑 | 一台硬件加速的虚拟机,配有 Linux 桌面和持久化磁盘。空闲时休眠,收到新消息、任务或自动化指令时自动唤醒。 |
| 不被拦截的浏览器 | invisible_playwright_mcp:以 C++ 层面修补的 Firefox,指纹在引擎内部设置。每个身份拥有独立的 cookies 和登录状态。 |
| 记忆与技能 | 它会像 Claude Code 一样,在自己的主文件夹中编写笔记和操作指南,并在下一次任务时读取它们。 |
| 你的 MCP servers | 你可以声明任意 MCP server——无论是其电脑上的程序还是一个 URL,与 Claude Code 相同。密钥不会写入配置文件。 |
| 你设定的权限 | 每个工具都对应一项权限:允许、询问或拒绝。选择"询问"时,请求会等待在你的收件箱中,重启后依然有效,且只执行一次。 |
| 任务与自动化 | 一个带有优先级和启动时间的队列,以及它自己的周期性任务,其电脑会在预定时间准时启动。 |
| 多种交互方式 | Web UI、命令行、带实时事件的 HTTP API、Telegram,以及可选启用的 WhatsApp。 |
| 崩溃不丢数据 | 重启或 kill -9 后,你看到已接受的每条消息和任务都会保留,被中断的工具调用也绝不会被重复执行。 |
文档
相关项目
这个项目的各个组成部分。 一个 Dot 的浏览器是 invisible_playwright_mcp,基于 invisible_playwright 和 invisible_core;引擎则 fork 自 nanobot。
许可证
MIT,详见 LICENSE。第三方组件及其许可证:THIRD_PARTY_NOTICES.md。
免责声明
本项目按原样提供,不作任何担保。使用风险自负,请遵守您所在司法管辖区的法律法规。Dot 使用您的账户、通过您的网络连接进行操作:请尊重其访问站点的服务条款及其 robots.txt 规则。
Built by Federico Elia
项目介绍
求职助手AI智能代理AIHawk致力于简化求职过程,通过自动化职位申请流程。借助人工智能,它能够帮助用户以定制化的方式申请多个职位。【此简介由AI生成】