{"id":52116762,"url":"https://github.com/pdparchitect/buzznode","last_synced_at":"2026-08-05T03:01:27.814Z","repository":{"id":373959963,"uuid":"1312951719","full_name":"pdparchitect/buzznode","owner":"pdparchitect","description":"A persistent, browser-accessible Linux computer for a single Buzz agent — its own desktop, terminal, filesystem, and long-lived state, joining any Buzz workspace over its relay","archived":false,"fork":false,"pushed_at":"2026-07-31T01:45:24.000Z","size":160,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-31T03:14:37.045Z","etag":null,"topics":["acp","agent-runtime","ai-agents","buzz","buzz-xyz","claude-code","codex","containers","docker","goose","podman","remote-desktop","self-hosted"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pdparchitect.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null,"disclosure":null}},"created_at":"2026-07-26T16:13:11.000Z","updated_at":"2026-07-31T01:45:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pdparchitect/buzznode","commit_stats":null,"previous_names":["pdparchitect/buzznode"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/pdparchitect/buzznode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pdparchitect%2Fbuzznode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pdparchitect%2Fbuzznode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pdparchitect%2Fbuzznode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pdparchitect%2Fbuzznode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pdparchitect","download_url":"https://codeload.github.com/pdparchitect/buzznode/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pdparchitect%2Fbuzznode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36294659,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-08-05T02:00:06.619Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["acp","agent-runtime","ai-agents","buzz","buzz-xyz","claude-code","codex","containers","docker","goose","podman","remote-desktop","self-hosted"],"created_at":"2026-08-05T03:01:26.894Z","updated_at":"2026-08-05T03:01:27.805Z","avatar_url":"https://github.com/pdparchitect.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Buzznode\n\n\u003cimg width=\"1760\" height=\"894\" alt=\"44340f8d-6e7f-4d1c-a11c-06e187b1f68b\" src=\"https://github.com/user-attachments/assets/92db3018-9ce9-4415-9a38-a159dad8faca\" /\u003e\n\nBuzznode is one persistent, browser-accessible Linux computer for one\n[Buzz](https://github.com/block/buzz) agent. It joins an existing Buzz\nworkspace and runs that agent through the headless `buzz-acp` harness.\n\nBuzznode is not a Buzz workspace client. It does not contain Buzz Desktop, and\nit does not run a relay, database, object store, or other server-side Buzz\nservice. Use [Buzzbox](https://github.com/pdparchitect/buzzbox) or another Buzz\nclient to manage the workspace, create agents, and communicate with them. Use\nBuzznode to give one of those agents a dedicated browser, terminal, filesystem,\nruntime login, and long-lived state.\n\n\u003e **Not an official Buzz project.** Buzznode is an independent, community-built\n\u003e environment that packages published Buzz releases. It is not affiliated with,\n\u003e endorsed by, or sponsored by the Buzz project, [buzz.xyz](https://buzz.xyz),\n\u003e or Block, Inc. \"Buzz\" is used here only to describe what this image runs and\n\u003e what it is compatible with; all trademarks belong to their respective owners.\n\u003e Report problems with Buzznode here, not to the upstream Buzz project.\n\n\u003cimg width=\"3456\" height=\"2234\" alt=\"tpsmlhvh-6904 euw devtunnels ms_(MacBook Pro 16_)\" src=\"https://github.com/user-attachments/assets/dd8b96bc-36fc-4978-90b9-c07fc442b2c9\" /\u003e\n\n## Quick start\n\nYou need credentials for a managed agent — either a `buzznode-v1:` enrollment\nbundle, which [Buzzbox](https://github.com/pdparchitect/buzzbox) produces, or\nthe agent's relay URL and private key from any other Buzz client. Buzznode\npublishes native AMD64 and ARM64 images.\n\n### Launcher (recommended)\n\nThe easiest way to run Buzznode is with\n[Launcher](https://github.com/pdparchitect/launcher). Launcher discovers,\ninstalls, starts, stops, and updates Buzznode while managing its container,\nports, and persistent storage for you.\n\n1. [Download the latest Launcher release](https://github.com/pdparchitect/launcher/releases/latest).\n2. Open **Marketplace**, select **Buzznode**, and install it.\n3. Choose **Open agent** when installation finishes, then paste your enrollment\n   bundle into the setup window.\n\nLauncher uses Apple `container` on macOS and Docker on Linux.\n\n### Run the container manually\n\nChoose the container runtime installed on your host.\n\n#### Docker\n\n```bash\ndocker run --detach \\\n  --name buzznode \\\n  --shm-size 1g \\\n  --publish 127.0.0.1:6904:6901 \\\n  ghcr.io/pdparchitect/buzznode:latest\n```\n\n#### Podman\n\n```bash\npodman run --detach \\\n  --name buzznode \\\n  --shm-size 1g \\\n  --publish 127.0.0.1:6904:6901 \\\n  ghcr.io/pdparchitect/buzznode:latest\n```\n\n#### Apple container\n\nApple's [`container`](https://github.com/apple/container) tool requires Apple\nsilicon and macOS 26 or later. Start its service once, then give the browser\ndesktop and agent harness enough memory:\n\n```bash\ncontainer system start\n\ncontainer run --detach \\\n  --name buzznode \\\n  --memory 4g \\\n  --shm-size 1g \\\n  --publish 127.0.0.1:6904:6901 \\\n  ghcr.io/pdparchitect/buzznode:latest\n```\n\nOpen \u003chttp://127.0.0.1:6904\u003e. The setup window asks for the bundle; paste it, or\npress Enter to type the relay URL and private key instead. Pick Codex, Claude\nCode, or Goose, and the node connects to your relay and starts handling messages\nfor that agent.\n\nDocker and Podman select the host's native image automatically; Apple\n`container` selects ARM64 on Apple silicon. These commands are for trying the\nnode out: its state lives in anonymous volumes, so replacing the container\nloses the enrollment and leaves the old volumes behind on disk. For anything\nyou intend to keep, use the\n[persistent setup](#persistent-setup) below.\n\n## Setup in detail\n\nCreate or select a managed agent in the Buzz client associated with your\nrelay. You need either:\n\n- a `buzznode-v1:` enrollment bundle; or\n- the relay URL, agent private key, authorization, and response policy for\n  manual setup.\n\nWhen using Buzzbox, its convenience flow is:\n\n1. Right-click the Buzzbox desktop and choose **Agent Setup → Create New Agent\n   for Buzznode**.\n2. Complete Buzz's managed-agent form and save it.\n3. Copy the `buzznode-v1:` enrollment bundle displayed by Buzzbox.\n\nTo use an existing agent instead, stop its local harness and choose **Agent\nSetup → Move Existing Agent to Buzznode**.\n\nWhen using another Buzz workspace, obtain the managed agent credentials through\nthat workspace's client or provisioning process. Buzznode does not contact,\ndiscover, or require a Buzzbox instance.\n\nOnce the container is running, the first desktop opens a larger terminal setup\nwindow. Paste the enrollment bundle, then choose a Codex, Claude Code, or Goose\nruntime. The wizard confirms completion and waits for Enter before becoming a\nnormal Buzznode terminal; it does not close the window. The bundle supplies:\n\n- the workspace relay WebSocket URL, such as `wss://buzz.example.com`;\n- the agent private key;\n- its authorization tag; and\n- whether anyone, its owner, an allowlist, or nobody may activate it.\n\nBuzznode separately asks for an optional relay API token because Buzzbox does\nnot store that token with the managed agent.\n\nBuzznode validates the bundle's relay, private key, authorization, and response\npolicy before reporting that enrollment was accepted.\n\nThe enrollment bundle is base64-encoded, not encrypted, and contains the agent\nprivate key. Treat it like a password and paste it only into Buzznode setup.\nOnce the node is connected, do not run the same agent's local harness in\nBuzzbox.\n\nThe wizard stores connection credentials in\n`~/.config/buzznode/environment` with mode `0600`, offers to configure the\nselected runtime, and starts `buzz-acp`. Buzznode discovers the channels that\ncontain this agent and handles messages addressed to it.\n\n### Persistent setup\n\nA long-lived node should survive being recreated, so name its volumes and give\nit a restart policy. If you already started the container above, remove it and\nits anonymous volumes first with `docker rm --force --volumes buzznode`.\n\n```bash\ndocker run --detach \\\n  --name buzznode \\\n  --restart unless-stopped \\\n  --shm-size 1g \\\n  --publish 127.0.0.1:6904:6901 \\\n  --volume buzznode-workspace:/workspace \\\n  --volume buzznode-config:/home/agent/.config \\\n  --volume buzznode-data:/home/agent/.local/share \\\n  --volume buzznode-nest:/home/agent/.buzz \\\n  --volume buzznode-codex:/home/agent/.codex \\\n  --volume buzznode-claude:/home/agent/.claude \\\n  ghcr.io/pdparchitect/buzznode:latest\n```\n\nPodman accepts the same command with `podman` in place of `docker`. With\nApple's tool, use `container` in place of `docker`, remove\n`--restart unless-stopped`, and add `--memory 4g`. Apple `container` preserves\nthe named volumes and stopped container but does not expose a Docker-style\nrestart policy; restart it with `container start buzznode`.\n\nSetup then runs once. Enrollment, runtime login, browser sessions, and working\nfiles stay put across `docker rm` and image upgrades. See\n[Persistence](#persistence) for what each volume holds, and\n[One node, one agent](#one-node-one-agent) for running more than one.\n\n### Unattended provisioning\n\nTo skip the wizard, configure the node from its terminal:\n\n```bash\nprintf '%s\\n' \"$BUZZNODE_ENROLLMENT_BUNDLE\" |\n  buzznode configure --enrollment-stdin --runtime codex\nbuzznode runtime-login\nbuzznode start\n```\n\nManual `--relay-url`, `--private-key`, `--auth-tag`, `--respond-to`, and\n`--respond-to-allowlist` options remain available for non-Buzzbox clients. Use\n`buzznode setup` for normal interactive configuration so secrets do not appear\nin shell history. A raw key from `buzz-admin generate-key` is not a replacement\nfor creating a managed agent because it has no Buzz profile, owner attestation,\nor channel membership.\n\n## Deployment model\n\nBuzznode has no runtime dependency on Buzzbox. It can connect to any compatible\nBuzz relay that is reachable from the container, including a hosted relay over\n`wss://`, a relay on another server, or a local development relay.\n\nBuzzbox is only an optional onboarding convenience. Its Agent Setup menu can\ncreate a managed agent and package the relay URL, identity, authorization, and\nresponse policy into a `buzznode-v1:` enrollment bundle. Another Buzz client or\nprovisioning system can supply the same information instead.\n\nThe `buzz-local` Docker network, `ws://buzzbox:3000` relay address, and the two\nprojects' coordinated Makefile examples are strictly for local testing. They\nare not part of the Buzznode architecture and are not required in deployment.\n\n## How the pieces fit\n\n```text\nAny compatible Buzz workspace           Independent Buzznode\n---------------------------------       ---------------------------\nCreate and manage workspace             Run one existing agent\nProvide enrollment or credentials ----\u003e Connect to its configured relay\nAdd agent to channels                   Run Codex, Claude, or Goose\nChat with and mention agent       \u003c---- Handle messages through buzz-acp\n```\n\nThe `buzz` command-line tool remains in the node because `buzz-acp` makes it\navailable to the running agent for Buzz messaging and tools. The graphical\n`buzz-desktop` application is deliberately absent and cannot be started.\n\n## Test locally with Buzzbox\n\n[Buzzbox](https://github.com/pdparchitect/buzzbox) is a ready-to-run Buzz\nworkspace — desktop, relay, and storage in one image — which makes it the\neasiest way to exercise a node end to end. The two remain independent projects;\ntheir Makefiles coordinate only through an optional Docker network and the relay\nURL.\n\nClone Buzzbox next to this repository, then from the `buzzbox` directory:\n\n```bash\nmake up \\\n  BUZZ_NETWORK=buzz-local \\\n  PUBLIC_RELAY_URL=ws://buzzbox:3000\n```\n\nOpen Buzzbox at \u003chttp://127.0.0.1:6903\u003e and choose **Agent Setup → Create New\nAgent for Buzznode**. Complete the Buzz form and copy the enrollment bundle.\n\nFrom this `buzznode` directory:\n\n```bash\nmake up \\\n  BUZZ_NETWORK=buzz-local \\\n  RELAY_URL=ws://buzzbox:3000\n```\n\nOpen Buzznode at \u003chttp://127.0.0.1:6904\u003e. The relay URL is prefilled in the\nsetup wizard for manual setup, but the recommended flow is to paste the\nBuzzbox enrollment bundle. Leave the local API token empty, select a runtime,\nand complete its login.\n\nOnce setup is complete, verify the saved configuration and relay connection:\n\n```bash\nmake connection-test\n```\n\nThe first project started creates `buzz-local`; Docker DNS resolves `buzzbox`\non that network. Each Makefile still owns only its own container. `make stop`\nin either directory does not stop or remove the other project.\n\n## One node, one agent\n\nCreate another Buzznode container with a different container name and volume\nprefix for another agent. Keeping nodes isolated gives each agent its own:\n\n- Buzz identity and harness process;\n- browser sessions and runtime credentials;\n- desktop and filesystem state;\n- `/workspace`; and\n- start, stop, restart, and logs lifecycle.\n\n## What is included\n\n- the headless `buzz-acp`, `buzz`, `buzz-agent`, and `buzz-dev-mcp` tools;\n- Codex with `codex-acp`;\n- Claude Code with `claude-agent-acp`;\n- Goose with native ACP support;\n- Chrome on AMD64 or Chromium on ARM64 for login flows and browser-based agent\n  tasks;\n- a terminal, Git, GitHub CLI, Docker CLI, Python, Node.js, pnpm, and common\n  development tools; and\n- an Openbox desktop exposed through KasmVNC.\n\nBuzznode contains no `buzz-desktop`, `buzz-relay`, PostgreSQL, Redis, or MinIO.\n\nThe desktop is about a quarter of the image. It is kept because the node is\nmeant to be inspectable, because runtime authentication needs a real browser,\nand because it is the substrate for computer use: `scrot`, `xdotool`, `wmctrl`,\nand a Chromium-family browser are already present, so an agent can drive the\nsame display a human watches through KasmVNC. See\n[IMAGE-SIZE.md](IMAGE-SIZE.md) for the measured\nbreakdown and the reasoning, and run `make size-report` to reproduce it.\n\nA purpose-built web application could have taken the desktop's place as the way\nto reach the node: a terminal, a log view, and a file browser served over HTTP\nwould be far smaller than an X session. That was considered and set aside. It\nwould be a second product to design, build, secure, and maintain alongside the\nnode itself, which is not where the early effort belongs. More to the point, it\nwould not actually remove the graphical stack. Runtime authentication needs a\nreal browser, and computer use needs a real display with real input, so the\nbrowser, Xvnc, the fonts, and the software GL renderer stay in the image either\nway — and those are the bulk of the cost. Openbox, tint2, and the rest of the\ndesktop shell add roughly 22 MiB on top of components already being paid for.\nGiven that, the node lives off the land: it surfaces what is already installed\nrather than reimplementing a thinner version of it.\n\n## Node commands\n\n```bash\nbuzznode setup\nbuzznode status\nbuzznode doctor\nbuzznode runtime-login\nbuzznode runtime-login codex device\nbuzznode start\nbuzznode stop\nbuzznode restart\nbuzznode logs\n```\n\nRight-click the desktop for the same agent controls, runtime login actions,\nterminal, browser, task manager, and harness logs. Runtime login opens a\nchooser instead of assuming browser authentication. Codex supports device code,\ndesktop browser, or API-key authentication. Claude Code supports Claude\nsubscription, Anthropic Console, long-lived setup-token, or organization SSO\nflows.\n\n## Relationship to the Launcher desktop base\n\nBuzznode is a product image on top of\n`ghcr.io/pdparchitect/launcher-image-base-desktop`, the same substrate the\nother Launcher desktops use. The base supplies Ubuntu, Node, KasmVNC, Openbox,\nCortile, tint2, kitty, the browser, the GTK theme, the `agent` account, and the\nentrypoint. This repository supplies only the node.\n\nThat split is what the source layout reflects:\n\n| Path                             | What it is                                      |\n| -------------------------------- | ----------------------------------------------- |\n| `Dockerfile`                     | The headless Buzz tools and the agent runtimes  |\n| `overlay/`                       | Files copied over the base's defaults            |\n| `overlay/usr/local/bin/buzznode` | The node CLI                                     |\n| `overlay/etc/desktop/session.d/` | Programs the session runs once it has a display  |\n\nTwo consequences are worth knowing:\n\n- The desktop user is `agent`, homed at `/home/agent`, and the agent harness\n  log lives in `/var/log/launcher-desktop`.\n- Desktop-level settings use the base's names — `DESKTOP_VNC_STATS` and\n  `DESKTOP_TITLE`. Node-level settings keep their `BUZZNODE_*` and `BUZZ_*`\n  names.\n\nTo build against a different base, override `DESKTOP_IMAGE`:\n\n```bash\nmake up DESKTOP_IMAGE=ghcr.io/pdparchitect/launcher-image-base-desktop:0.2.0\n```\n\n## Build locally\n\nFrom this directory:\n\n```bash\nmake check\nmake up\nmake smoke\n```\n\nThe desktop opens at \u003chttp://127.0.0.1:6904\u003e. Useful overrides include:\n\n```bash\nPORT=8080 make up\nPLATFORM=linux/arm64 make build\nDOCKER=podman make up\n```\n\nThe Makefile selects `linux/amd64` or `linux/arm64` from the host by default.\n\n`make stop` removes the node container but preserves its named volumes.\n\n## Pinned components\n\n| Component           | Version   |\n| ------------------- | --------- |\n| Buzz headless tools | `0.5.4`   |\n| Codex               | `0.146.0` |\n| Claude Code         | `2.1.221` |\n| Goose               | `1.45.0`  |\n| Codex ACP adapter   | `1.1.9`   |\n| Claude ACP adapter  | `0.64.2`  |\n\nOn AMD64, the Buzz `.deb` and Goose archive are SHA-256 verified during the\nimage build. Only the required headless Buzz binaries are extracted from the\n`.deb`; the package and its desktop application are not installed. Upstream\ndoes not publish a Linux ARM64 package, so ARM64 builds compile only those\nheadless tools from the pinned tag after verifying its exact Git commit. The\nARM64 Goose archive is independently SHA-256 verified.\n\n## Persistence\n\nKeep separate volumes for:\n\n- `/workspace` — the node's working files;\n- `~/.config` and `~/.local/share` — node, browser, desktop, and Goose state;\n- `~/.buzz` — the Buzz agent nest;\n- `~/.codex` — Codex state; and\n- `~/.claude` — Claude Code state.\n\n## Security\n\nBuzznode is a trusted, single-user workstation:\n\n- the saved agent private key can act as that agent;\n- KasmVNC browser authentication and TLS are disabled;\n- the `agent` user has passwordless sudo;\n- coding agents can operate on `/workspace`;\n- browser sessions and agent credentials persist in volumes; and\n- Codex runs with `sandbox_mode = \"danger-full-access\"`, because its bubblewrap\n  sandbox cannot create a user namespace inside a container, so no sandbox mode\n  is enforceable here whatever is configured. The setting states what is true\n  rather than implying a boundary that does not exist; the boundary is the\n  container. Override with `BUZZNODE_CODEX_SANDBOX_MODE`.\n\nThe provided Makefile binds the desktop to `127.0.0.1`. Keep that default, or\nput Buzznode behind authentication, TLS, and suitable network controls. Never\npublish port `6901` directly to an untrusted network, expose the saved agent\nkey, or reuse a human Buzz private key as the node identity.\n\nSee [RELEASES.md](RELEASES.md) for the image release process.\n\n### Authentication is delegated by design\n\nAccess to the desktop web application is not authenticated. KasmVNC is started\nwith `-disableBasicAuth` and TLS disabled, and the KasmVNC password written on\nfirst boot exists only because KasmVNC checks that the file is there. It is not\nan access control and should not be treated as one.\n\nThis is a deliberate decision, and built-in authentication is not planned. A\nnode reachable beyond loopback is expected to be fronted by whichever access\nlayer already suits its environment: a conventional reverse proxy, or\npreferably a zero-trust access proxy such as Cloudflare Access or an equivalent\nidentity-aware proxy. Those systems already own identity, session lifetime,\ndevice posture, revocation, and audit, and in an enterprise deployment they are\nthe layer that has to be satisfied regardless of what the node does.\n\nAdding a second mechanism inside the node would not strengthen that\narrangement, it would compete with it: two session models to keep aligned, two\nplaces to revoke an operator, and an open question about which one wins when\nthey disagree. Leaving the node unauthenticated keeps a single enforcement\npoint and a single path forward — the proxy is the front door, and there is no\nsecond door to reason about or accidentally leave open.\n\nThe practical consequence is that the loopback bind is the only boundary until\nan access layer is put in front of it. Treat exposing the node without one as\npublishing an unauthenticated root shell, because that is what it is.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpdparchitect%2Fbuzznode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpdparchitect%2Fbuzznode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpdparchitect%2Fbuzznode/lists"}