A local, general-purpose **GrokBot-like CLI agent**. It observes the environment, chooses tools, adapts to results, and verifies its work. Uses your existing xAI/OpenAI-compatible model configuration; no separate search API key.
For action tasks the agent briefly explains its approach, then starts. Multi-stage tasks get a short live plan. You can add instructions while it works, answer a question, or interrupt and resume. Simple questions remain simple answers.
While running, enter additional instructions to steer the next step. **Ctrl-C** or **`/stop`** stops the turn and saves its state. In the REPL, `/plan` shows the current plan, `/session` shows its ID, and `/exit` or `/quit` exits when idle. During work `/exit` and `/quit` stop the current turn first. At an explicit question, new text answers that question. Already queued idle inputs remain separate tasks.
Progress, plans and questions go to stderr; final answers go to stdout. `lazyboy chat` remains streaming chat without tools. `lazyboy web` serves the Grok Bot-shaped conversation UI (sidebar, bubbles, composer, **我的電腦** overlay) as a phone-installable PWA. `lazyboy help` lists commands and settings.
Set `LAZYBOY_WEB_TOKEN` before starting `lazyboy serve` to require authentication. The web UI prompts for this token and uses an HttpOnly session cookie for API calls, event streams, avatars and the remote desktop. Sessions last 12 hours and expire when the server restarts. Command-line API clients can continue using `Authorization: Bearer <token>`.
Run `lazyboy serve` in one terminal, then create identities with `lazyboy agents create <name>` and open separate chats with `lazyboy agent --name <name>`. Agents learn private memories and public expertise from their conversations. They can delegate to an existing agent or create a temporary worker while you keep chatting.
In named-agent mode, ordinary text is new chat. Use `/tasks` and `/task <id> say|stop|resume` to manage background work. Closing a chat leaves the service and its tasks running. Agent identity and task ownership are separate: one agent can help another without losing its own conversation.
See [team setup and behavior](docs/TEAM.md) for commands, budgets, privacy boundaries and recovery. `LAZYBOY_DATA_DIR` defaults to `~/.lazyboy/team`; existing single-session commands keep their original behavior.
| Desktop GUI | Parent: `screenshot` (read-only). Clicks: `spawn_subagent kind=computerUse`, which gets `computer` (screenshot/snapshot/click/move/drag/type/key/scroll/wait via xdotool on `DISPLAY=:1`; `snapshot` lists on-screen elements with centre coordinates from the AT-SPI accessibility tree). One computerUse per agent computer. Passwords still `request_box_help`. |
| MCP | `get_mcp_tools`, `call_mcp_tool`, `get_mcp_server_status`, `add_mcp_server`, `remove_mcp_server`. Config: `~/.lazyboy/mcp.json` (or `LAZYBOY_MCP_CONFIG`). Prefer a connector over the browser for that service. |
| My computer (box) | Docker Linux desktop (TigerVNC + minimal XFCE in lazyBoy's Arc-Dark/粉圓 look, zh-TW/Asia/Taipei, **Chromium** + 終端機 + xdotool + AT-SPI). Named agents each get their own container; opening an agent starts it and the UI confirms ready/error. Session CLI keeps `lazyboy-box`. Default tools: `shell`, `read`, `await_shell`, `screenshot`. Profile: `/home/box/chrome-profile` on that seat. Viewer:`lazyboy computer` or the agent overlay. |
Long commands return a session ID and incremental output; `external_write_stdin` polls, sends input, closes stdin or terminates the command. One foreground command at a time, piped I/O, default ten-minute deadline. The explicit local `external_shell` retains its 30-second limit. Default `shell` runs on the box and continues in the background when its foreground wait expires; use `await_shell` to observe it. Full command output is saved under `.lazyboy-output/`; large tool results are also stored there with a readable preview and path.
`external_read_file` accepts a zero-based line `offset` and line `limit`; `external_search_files` searches names or literal content; `external_edit_file` requires one unique exact match. File tools and browser file exchange check workspace paths and symlinks. Only `external_*` tools operate on the local machine; `shell` and `read` use the box.
Browser tools now default to **Docker Chromium**, attached to the desktop browser at `/home/box/chrome-profile`. Automation and human login share this profile; browser uploads/downloads use `/workspace` paths and explicit `copy_to_box`/`copy_from_box` transfer files. `browser_release` disconnects automation without closing the desktop. The old local browser is available only with `LAZYBOY_BROWSER_SURFACE=local`; its owner profiles are preserved and are not merged into Docker. See [surface comparison](docs/SURFACES.md) for differences and configuration.
`web_fetch` is a direct anonymous HTTP GET from the host: browser-like headers, no cookies, public hosts only (redirects are re-checked), body capped at 2 MiB, HTML reduced to readable text with link footnotes, non-UTF-8 charsets decoded, and results cached for ten minutes per URL. Only when a site refuses plain HTTP (401/403/429/503, or an empty JavaScript shell) and the model configuration is official xAI does it fall back to xAI native browsing; that result is marked `content_kind=model_rendered_web_content` and carries `fallback_reason`. `web_search` uses a remote search service with no browser cookies: official xAI configuration reuses the existing model API key for native web search; for the reconstructed AiService contract, set `LAZYBOY_WEB_BACKEND_URL` and, when required, `LAZYBOY_WEB_TOKEN`. That gateway must provide the reconstructed `RunWebSearch` JSON contract; a normal OpenAI-compatible chat endpoint alone does not provide it. Missing search configuration produces an explicit error, never a hidden browser fallback.
For login, OTP or captcha, `browser_handoff` shows the Docker viewer URL and parks the turn until you reply. For irreversible public actions, the agent follows the existing explicit-approval rule; plans themselves do not require approval.
Session stop reasons: `answer` (no tool calls, or standalone `send_message(final=true)`), `done` (optional `report_done`), `blocked`, `budget_exhausted`, `failed`, `cancelled`. One-shot exits 0 for answer/done, 1 for blocked/budget/failed, 130 for cancellation. The REPL remains usable after any turn outcome. Named foreground answers stream directly; background/legacy delivery uses `send_message`. Ending a turn is not independent proof of arbitrary task correctness.
`make start` rebuilds both services and reapplies computer limits to existing containers. Each computer is limited to 1536 MiB RAM (no additional swap), 2 CPUs and 512 processes; new containers use 256 MiB shared memory. The default maximum is three running computers, including computers recovered from previous server runs. Idle computers are stopped when a slot is needed; their workspace and browser profile volumes are retained. Busy computers are not evicted. `LAZYBOY_COMPUTER_MAX` overrides the running count.
Chat history scrolls continuously and only mounts nearby messages. Desktop chrome is hidden by CSS without a DOM mutation feedback loop. Regression checks: `node tests/novnc_memory_ui.mjs` and `node tests/history_memory_ui.mjs` (with the frontend running).