- Rust 78.8%
- JavaScript 12.7%
- Shell 5%
- Python 2.5%
- HTML 0.9%
- Other 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Bitwarden computes its inline menu's logins for the active tab of the window Chrome last focused, not for the focused field's tab, and keeps the old list when focus moves between two sites' login fields. deskd focused the window with the browser seat only, but a window seat0 still focuses (the one shown last) stays activated, so Chrome never took it as focused: its menu listed the previous sign-in's site (seen live: USAA's menu listing Capital One's logins). The site check on the focused field's tab passed in that case. Now sign_in focuses the window on both seats, and checks with Bitwarden's service worker that its focused field is in this tab, this tab's window is Chrome's focused one, every menu entry is a saved login for the tab's URL, and the buttons show those entries; until then it refocuses and has Bitwarden recompute, or clicks the field again (blurred first, since any navigation in any tab clears Bitwarden's focused field). It checks again right before clicking, and after filling confirms the chosen login's last-used date moved, clearing the form otherwise. Switching, closing and removing tabs wait for a sign-in in progress. tests/signin_cross_site.sh: 3x4 7/12 -> 12/12, 5x4 18/20 -> 20/20; with other agents' focus stolen every 2 s 12/12. No run filled a wrong login. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
| crates | ||
| docs | ||
| patches/sway | ||
| scripts | ||
| spikes | ||
| tests | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| PLAN.md | ||
| README.md | ||
deskhand
Gives AI agents (Claude Code and other MCP clients) their own desks on a Linux desktop without interfering with the user's session or with each other.
Agents run in "agentland", a headless nested sway with one seat and one output per agent. A single shared browser process (Helium, driven over the Chrome DevTools Protocol) lives in agentland; each agent's tabs are windows on its own workspace. Logins go through the Bitwarden browser extension's autofill, so passwords never enter the model's context. The user can take over any desk in a viewer window and hand it back.
This is not a security sandbox: the aim is no interference by default, not containment.
Status: the browser side works. Native desktop apps and desktop notifications are planned (see PLAN.md).
Components
| Crate | What |
|---|---|
crates/deskd |
Daemon: starts agentland and the browser, serves a JSON-RPC control socket |
crates/deskhand-mcp |
stdio MCP server, one per agent session; starts deskd if needed |
crates/deskctl |
CLI: status, stop, run a tool as an agent, open the viewer |
crates/deskview |
Take-over viewer: shows an agent's desk and forwards your input to it |
crates/proto |
Shared protocol types |
Agent tools include browser_open, navigate, click, type, key,
scroll, tabs, select_tab, close_tab, screenshot, ui_tree,
wait_for, run_script, desk_size and sign_in.
agentland needs a patched sway (patches/sway/, six patches on sway 1.12)
that adds per-seat client binding and a few seat commands; see
docs/sway-patch.md.
Build
Needs Rust, and for the patched sway: meson, ninja, a C compiler, and the sway/wlroots 0.20 development headers.
scripts/build-sway.sh # fetches sway 1.12, applies patches/sway, installs it
cargo build --release # deskd, deskhand-mcp, deskctl, deskview
cargo test
Register with an MCP client by pointing it at target/release/deskhand-mcp.
Documentation
- docs/usage.md - components, environment variables, agent model
- docs/bitwarden-setup.md - setting up the agent browser profile
- docs/sway-patch.md - what the sway patches change
- docs/development.md - development dependencies
- docs/spikes.md - results of the initial experiments
- PLAN.md - original design and roadmap
License
MIT; see LICENSE. The sway patches in patches/sway/ are derived
from sway and, like sway, are under the MIT license.