# Connect and call > Build a small client with the TypeScript or Python SDK: connect with your token, start an agent, read its reply, answer it, and hear events. Source: https://hivemind.griiken.com/guide/api-connect/ In this tutorial you build a client that lists your agents, starts one, reads its reply, answers its questions and follows what happens. It takes about ten minutes. {` Make a Hivemind API token and write a small client with the \`hivemind-api\` SDK that connects to my workspace, starts an agent, reads its reply and prints the events it hears. 1. Ask me which workspace folder to drive, whether I prefer TypeScript (Node 20 or newer, or Bun) or Python (3.9 or newer), and whether the client only reads (\`view\`) or also starts agents (\`agents\`). 2. Check Hivemind runs with the folder open: \`hive ctl agents\` must not exit 3. If it does, ask me to run \`hivemind \`. 3. Make the token: \`hive grant create api-client -w --role --expires 7d --json\`. Keep the token out of this chat and out of git: write \`HIVE_DRIVE_TOKEN\`, \`HIVE_DRIVE_SOCK\` (the \`socket\` field) and \`HIVE_WORKSPACE\` (the folder) to a git-ignored \`.env\`. 4. Install the SDK that comes with the app. On macOS or Linux: \`npm install ~/.hivemind-app/sdk/hivemind-api.tgz\` or \`pip install ~/.hivemind-app/sdk/python\`. On Windows: \`npm install %LOCALAPPDATA%\\hivemind\\sdk\\hivemind-api.tgz\` or \`pip install %LOCALAPPDATA%\\hivemind\\sdk\\python\`. Only on a computer without Hivemind, install it from the release, where is the version of the app my program talks to: \`npm install https://github.com/dip497/hivemind/releases/download/v/hivemind-api-.tgz\` or \`pip install https://github.com/dip497/hivemind/releases/download/v/hivemind_api--py3-none-any.whl\`. 5. Write the client. \`connect()\` reads the token, workspace and socket from those variables. Print \`hive.as\` (Python: \`hive.as_\`), then \`hive.agents.list()\`. 6. With an \`agents\` token: \`hive.agents.start\` with program set to an agent from \`hive agents list\` and prompt "Say hello", then \`hive.agents.read\` the tile. If \`finalStatus\` is \`waiting\`, show me what it asks and answer only after I say so, with \`hive.agents.answer(tile, reply.waiting.since, ...)\`. 7. Print \`agent.event\` events with \`hive.on\`. Catch \`ApiError\` and print its \`code\`. 8. Run it for 30 seconds and show me what it printed. At the end, tell me the token's id from \`hive grant list\` and how to revoke it: \`hive grant revoke \`. `} ## What you'll learn [#what-youll-learn] - How a program says who it is, with a token. - How to start an agent, read its reply and answer it. - How to follow what your agents do, as it happens. ## Before you start [#before-you-start] - Hivemind is running with your project open. - Node 20 or newer (or Bun), or Python 3.9 or newer. - A token for that project, made as in [Make an API token](https://hivemind.griiken.com/guide/api-tokens/). Use `agents` to follow every step here; `view` reads only. - The token in your environment, never in your code: ```bash export HIVE_DRIVE_TOKEN=hgr_… # from hive grant create export HIVE_WORKSPACE=~/work/api # the project folder export HIVE_DRIVE_SOCK=~/.config/hivemind/drive.sock # the socket it printed ``` The Python package uses only the standard library. `connect()` reads the token, the workspace and the socket from the variables above. Without them, it uses this computer's app. ```ts TypeScript import { connect, ApiError } from "hivemind-api"; const hive = await connect(); // or: await connect({ token: "hgr_…", workspace: "/home/you/work/api", socket: "…/drive.sock" }) console.log(hive.as); ``` ```python Python from hivemind_api import connect, ApiError with connect() as hive: # or: connect(token="hgr_…", workspace="/home/you/work/api", socket="…/drive.sock") print(hive.as_) ``` Check it worked: it prints your token's name, role and workspace: ```text { client: "dashboard", role: "agents", workspace: "/home/you/work/api" } ``` ```ts TypeScript const { agents } = await hive.agents.list(); console.log(agents); const { tile } = await hive.agents.start({ program: "claude", prompt: "Run the tests" }); ``` ```python Python print(hive.agents.list()["agents"]) tile = hive.agents.start({"program": "claude", "prompt": "Run the tests"})["tile"] ``` Check it worked: a new agent tile opens in the app. `program` is an agent from `hive agents list`. `agents.read` waits for the agent to finish replying. If it stops to ask you something, answer it. ```ts TypeScript const reply = await hive.agents.read(tile, { timeoutMs: 600_000 }); if (reply.finalStatus === "waiting") { await hive.agents.answer(tile, reply.waiting!.since, { decision: "allow" }); } console.log(reply.text); ``` ```python Python reply = hive.agents.read(tile, timeout_ms=600_000) if reply["finalStatus"] == "waiting": hive.agents.answer(tile, reply["waiting"]["since"], {"decision": "allow"}) print(reply["text"]) ``` | `finalStatus` | Means | |---|---| | `turn` | The reply is in `text`. | | `timeout` | It is still working. Read again. | | `working` | Read with `timeoutMs` 0: it is still working. | | `idle` | It was sent nothing since you last read it, and is not working. Send it a task. | | `waiting` | It asks you something. Answer with `agents.answer`: `allow` or `deny` a permission, or `{text}` for a question. | | `closed` | Its tile was closed. | Check it worked: the agent's tile turns amber while it waits, then goes back to work after your answer. ```ts TypeScript const off = hive.on("agent.event", (repo, event) => console.log(event.kind, event.tile)); // later: off(); ``` ```python Python off = hive.on("agent.event", lambda repo, event: print(event["kind"], event["tile"])) # later: off() ``` | Event | Tells you | |---|---| | `agent.changed` | An agent appeared, changed or went. | | `agent.event` | An agent finished replying (`turnEnded`), started waiting on you (`waiting`), was answered, or reported. | | `status.changed` | An agent's status changed. | Check it worked: start an agent in the app. Your client prints `came`. Every refusal is one `ApiError` with a `code`. `call` runs any method by name. ```ts TypeScript try { await hive.call("agent.start", [hive.workspace!, { program: "claude" }]); } catch (e) { if (e instanceof ApiError && e.code === "FORBIDDEN") console.log("this role may not start agents"); } hive.close(); ``` ```python Python try: hive.call("agent.start", [hive.workspace, {"program": "claude"}]) except ApiError as e: print(e.code) # "FORBIDDEN" ``` Check it worked: with a `view` token, it prints the refusal. The codes are listed on [Protocol](https://hivemind.griiken.com/guide/api-protocol/#error-codes). For Python with `asyncio`, import from `hivemind_api.aio`: `async with await connect() as hive:`. The methods are the same, awaited. ## What the SDK gives you [#what-the-sdk-gives-you] Both SDKs have the same shape: `as` (Python `as_`), `workspace`, `call(method, params, timeout)`, `notice`, `on(event, fn)` that returns `off`, `closed` and `close()`. Helpers: | Helper | Methods | |---|---| | `agents` | `list`, `since`, `start`, `read`, `send`, `answer`, `output`, `interrupt`, `close` | | `frames` | `open`, `close` | | `terminals` | `write`, `close` | Everything else is on [Methods by role](https://hivemind.griiken.com/guide/api-methods/), through `call`. **Other languages:** see [Protocol](https://hivemind.griiken.com/guide/api-protocol/) for the raw messages. ## What you did [#what-you-did] - Your program proved who it is with a token, at one role. - It started an agent, read its reply and answered its question. - It followed your agents through events, and handled a refusal. ## Next [#next] - [Methods by role](https://hivemind.griiken.com/guide/api-methods/): everything else you can call. - Revoke the token when you are done: `hive grant revoke `. --- # Methods by role > Every method a program's token can call, grouped by the smallest role that allows it, with its params and an example. Source: https://hivemind.griiken.com/guide/api-methods/ Every method a token can call, from workspace API version `0.30`. A role allows its own methods and those of every role above it on this page. {` Using the methods on this page, write a script that watches my Hivemind workspace and tells me when an agent waits on me. 1. Ask me which workspace folder to watch. The script needs only the \`view\` role. Check Hivemind runs with the folder open: \`hive ctl agents\` must not exit 3. 2. Make a token: \`hive grant create waiting-watcher -w --role view --expires 30d --json\`. Keep the token out of this chat and out of git: put \`HIVE_DRIVE_TOKEN\`, \`HIVE_DRIVE_SOCK\` (the \`socket\` field) and \`HIVE_WORKSPACE\` in a git-ignored \`.env\`. 3. Connect and say hello as the Protocol page shows. Call \`agent.list\` with \`[""]\` and print each agent with its state and what it waits on. 4. Listen for \`agent.event\` events. When one has kind \`waiting\`, call \`agent.output\` with \`["", 20]\` and print those lines. 5. Use only methods this page lists under view; any other is refused with \`FORBIDDEN\`. 6. Run it, start an agent in the app that asks a question, and show me the script's output. At the end, tell me how to stop the script and how to revoke the token: \`hive grant revoke \`, the id from \`hive grant list\`. `} `repo` is the workspace's folder. `tile` is a tile's id from `agent.list` or `agent.start`. Each call is sent as `{"id": 1, "method": "…", "params": [...]}` ([Protocol](https://hivemind.griiken.com/guide/api-protocol/)). The example column shows `params`. ## view [#view] ### Agents [#agents] | Method | Params | Returns | Example params | |---|---|---|---| | `agent.list` | `repo` | `{seq, agents}`: every agent now, its state and what it waits on | `["/home/you/work/api"]` | | `agent.since` | `repo`, `seq` | the changes and events after `seq`, or null: list again | `["/home/you/work/api", 41]` | | `agent.read` | `tile`, `timeoutMs`? | its reply when it finishes: `{text, finalStatus, truncated}` | `["t-3f2a", 600000]` | | `agent.output` | `tile`, `lines`? | the last lines it printed (40 by default), as plain text | `["t-3f2a", 20]` | | `agent.diff` | `tile` | `{files, patch, truncated}`: what it changed since its last commit | `["t-3f2a"]` | | `agent.sessions` | `place`, `program`, `limit`? | past sessions of that agent in a folder, to resume | `["/home/you/work/api", "claude", 10]` | | `agent.startable` | `repo` | the agents that can start, their models and modes, and the frames | `["/home/you/work/api"]` | | `agent.conversation` | `tile`, `cursor`? | what the agent and you said, from its session file | `["t-3f2a"]` | | `agent.tool` | `tile`, `use` | one tool use from that conversation, in full | `["t-3f2a", "toolu_01"]` | | `status.all` | | every agent's status | `[]` | | `link.list` | | which agent pipes into which, and which started which | `[]` | ### Files, git and issues [#files-git-and-issues] | Method | Params | Returns | Example params | |---|---|---|---| | `git.status` | `repo` | branch, ahead and behind, changed files | `["/home/you/work/api"]` | | `git.diff` | `repo`, `scope`, `file`? | `{patch}` | `["/home/you/work/api", {"kind": "working"}]` | | `git.listFiles` | `repo` | tracked and untracked files | `["/home/you/work/api"]` | | `git.listBranches` | `repo` | `{current, local, remote}` | `["/home/you/work/api"]` | | `git.fileContents` | `repo`, `file`, `rev` | a file at `HEAD`, `INDEX` or `WORKING` | `["/home/you/work/api", "README.md", "HEAD"]` | | `worktree.list` | `repo` | the repository's worktrees | `["/home/you/work/api"]` | | `file.read` | `repo`, `file` | a file's text, inside the workspace | `["/home/you/work/api", "package.json"]` | | `issue.list` | `root` | issues; `root` is the workspace's `.hivemind` folder | `["/home/you/work/api/.hivemind"]` | | `issue.read` | `root`, `id` | one issue, with its sections | `["/home/you/work/api/.hivemind", "API-4"]` | | `review.list` | `repo` | comments left on diffs | `["/home/you/work/api"]` | ### Canvas, widgets, terminals and views [#canvas-widgets-terminals-and-views] | Method | Returns or does | Example params | |---|---|---| | `store.open`, `store.core`, `store.view`, `store.objects`, `store.objectsWithIds` | the canvas layout and objects | `["/home/you/work/api"]` | | `widget.all`, `widget.packages`, `widget.asset` | what widgets draw, which are installed, their images | `["/home/you/work/api"]` | | `terminal.open` with `attachOnly` | watch a running terminal; output comes as `terminal.data` | `[{"tileId": "t-3f2a", "attachOnly": true, "cols": 120, "rows": 40}]` | | `terminal.show`, `terminal.history`, `terminal.flow`, `terminal.ack`, `terminal.detach`, `terminal.watchActivity` | follow terminals; these get no answer | `["t-3f2a", true]` | | `tile.watchLines` | the last line each named terminal shows, such as `214 tests passed`, or for an agent that keeps a conversation what it last said (from 0.35); it replaces the terminals you watched, `[]` stops, and changes come as `tile.lines`. From 0.34 | `[["t-3f2a", "t-9b1c"]]` | | `tile.readLines` | the same lines once, without watching. From 0.35 | `[["t-3f2a"]]` | | `terminal.saved` | what a sleeping agent last showed | `["t-3f2a"]` | | `presence.set` | where your pointer is, for others in the workspace | `["/home/you/work/api", null]` | | `appearance.get` | the app's theme; a colour of the person's own for the accent comes as `accentCustom` (`{ brand, accent, working? }`, from 0.35), which wins over `accent` while set | `[]` | | `view.list`, `view.file`, `view.open`, `view.post`, `view.screen`, `view.close` | open an installed view that is ready for phones | `[]` | ## edit [#edit] | Method | Params | Does | Example params | |---|---|---|---| | `widget.press` | `repo`, `id`, `{action}` or `{click: true}` | press a widget's button or card | `["/home/you/work/api", "w-1", {"click": true}]` | | `tool.open` | `repo`, `{tool, frame?, url?}` | place a tool's tile; returns `{tile}` | `["/home/you/work/api", {"tool": "@dip497/worktrees"}]` | | `git.handOff` | `repo`, `branch`, `bundle` | hand over a branch of your own; it lands as `handoff//` | `["/home/you/work/api", "fix", ""]` | ## terminals [#terminals] | Method | Params | Does | Example params | |---|---|---|---| | `terminal.write` | `tile`, `data` | type into a terminal, while you hold its keyboard | `["t-3f2a", "ls\r"]` | | `terminal.resize`, `terminal.fit` | `tile`, `cols`, `rows` | size it | `["t-3f2a", 120, 40]` | | `terminal.keyboard.ask`, `terminal.keyboard.give` | `tile`, … | ask for its keyboard, or hand it on | `["t-3f2a"]` | ## agents [#agents-1] | Method | Params | Does | Example params | |---|---|---|---| | `agent.start` | `repo`, `{program, frame?, prompt?, model?, mode?, name?, resume?, supervise?, report?}` | start an agent; returns `{tile}`. With `supervise`, its permission questions come to you. | `["/home/you/work/api", {"program": "claude", "prompt": "Run the tests"}]` | | `agent.send` | `tile`, `text` | a message, typed in as its next prompt | `["t-3f2a", "Now fix the failing test"]` | | `agent.answer` | `tile`, `since`, `{text}`, `{decision, feedback?, always?}` or `{answers}` | answer what it waits on: a question, a permission, a plan. `since` is the `waiting.since` that `agent.list` shows; `decision` is `allow` or `deny`. | `["t-3f2a", 1760000000000, {"decision": "allow"}]` | | `agent.interrupt` | `tile` | stop its current reply | `["t-3f2a"]` | | `agent.keys` | `tile`, `keys` | type keys: `Enter`, `Escape`, `Up`, `C-c`, … | `["t-3f2a", ["Down", "Enter"]]` | | `agent.rename` | `tile`, `name` | rename it; empty goes back to its own name | `["t-3f2a", "tests"]` | | `agent.sleep`, `agent.wake` | `repo`, `target`?, `force`? | put to sleep or wake a tile, a frame, or every agent | `["/home/you/work/api", "t-3f2a"]` | | `agent.close` | `tile` | end it and take its tile off the canvas | `["t-3f2a"]` | | `agent.places`, `agent.folders` | `repo`, `folder`? | where in the workspace an agent may start | `["/home/you/work/api"]` | | `frame.open` | `repo`, `{path}` or `{worktree: {branch, base?}}` | a frame on a folder, or on a new worktree | `["/home/you/work/api", {"worktree": {"branch": "fix-login"}}]` | | `frame.close` | `repo`, `frame`, `{closeTiles?, removeWorktree?, force?}`? | close a frame | `["/home/you/work/api", "f-2", {"closeTiles": true}]` | | `terminal.open`, `terminal.close` | | start or end a terminal | | | `link.connect`, `link.disconnect` | `src`, `dst`? | pipe one agent's replies into another as prompts | `["t-3f2a", "t-9c1b"]` | ## No role [#no-role] No token can call the methods that commit, push, pull, stage or discard; write files; create or change issues and review comments; create or remove worktrees; let people in or change their roles; or make or revoke tokens. That does not keep a program away from your files. With `terminals` it types into a shell, and with `agents` it starts agents. Either can run any command there. Full parameters and results are in [`spec/workspace-api.md`](https://github.com/dip497/hivemind/blob/main/spec/workspace-api.md). --- # Protocol > The raw messages a program sends and receives on the workspace API: the hello line, calls, answers, events and error codes, for any language. Source: https://hivemind.griiken.com/guide/api-protocol/ The messages behind the SDKs, for writing a client in any language. This page reflects workspace API version `0.30`. {` Using the messages on this page, write a client for the Hivemind workspace API in the language I name. 1. Ask me for the language and the workspace folder. Make a token with the smallest role it needs: \`hive grant create -w --role view --expires 7d --json\`. Keep the token out of this chat and out of git: read it from the environment variable \`HIVE_DRIVE_TOKEN\`, with \`HIVE_DRIVE_SOCK\` and \`HIVE_WORKSPACE\`. 2. Connect to \`HIVE_DRIVE_SOCK\` (a Unix socket on Linux and macOS, a named pipe on Windows). Within 10 seconds send one line: \`{"hello": {"token": "", "workspace": ""}}\`. 3. Send calls as one JSON line each, \`{"id": n, "method": "...", "params": [...]}\`. Match answers by \`id\`; they can come out of order. A line without an \`id\` is an event, or a JSON list of events. 4. Handle every error code in the table on this page. 5. Call \`agent.list\` for the folder, print the result, then print events for 30 seconds. Show me the output. `} ## Find the socket [#find-the-socket] `hive grant create` prints the socket's path (`socket` with `--json`). By default it is: | System | Socket | |---|---| | Linux | `~/.config/hivemind/drive.sock`, or `$XDG_CONFIG_HOME/hivemind/drive.sock` | | macOS | `~/Library/Application Support/hivemind/drive.sock` | | Windows | A named pipe. Use the path `hive grant create` prints. | The app or `hive host` must be running, with the workspace open. ## Messages [#messages] Every message is one line of JSON, both ways. ### Hello [#hello] Send this within 10 seconds of connecting: ```json {"hello": {"token": "hgr_…", "workspace": "/home/you/work/api"}} ``` `workspace` is the workspace's folder. Leave it out when the token reaches only one workspace. | You get back | Means | |---|---| | `{"hello": {"api": "0.30", "as": {"client": "dashboard", "role": "view", "workspace": "/home/you/work/api"}}}` | You are in. `role` is what you may do. | | `{"error": {"code": "FORBIDDEN", "message": "…"}}` | Wrong, revoked or expired token, or a workspace it does not reach. The connection closes. | | `{"error": {"code": "BAD_REQUEST", "message": "…"}}` | No hello, no workspace named, or the workspace is not open. The connection closes. | ### Calls and answers [#calls-and-answers] A call has an `id` you choose, a `method` and a list of `params`. Its answer has the same `id`, and either a `result` or an `error`: ```json {"id": 1, "method": "agent.list", "params": ["/home/you/work/api"]} {"id": 1, "result": {"seq": 0, "agents": []}} ``` ```json {"id": 2, "method": "agent.start", "params": ["/home/you/work/api", {"program": "claude", "prompt": "Run the tests"}]} {"id": 2, "error": {"code": "FORBIDDEN", "message": "agent.start is not open to your role on this workspace"}} ``` Where a method takes a folder (`repo`), give the workspace's folder. Answers can come out of order, so match them by `id`. ### Events [#events] A line without an `id` is an event, `{"event": "…", "params": [...]}`, about the workspace's tiles. Several events from one moment may arrive as a JSON list on one line. - `agent.changed`: an agent appeared, changed or went. - `agent.event`: an agent finished replying (`turnEnded`), started waiting on you (`waiting`), was answered (`answered`), came, went, or reported. - `status.changed`: an agent's status changed. - `terminal.data`: output of a terminal you opened. - `tile.lines`: the last line of terminals you watch (`tile.watchLines`) changed, at most every 250 ms. - `file.changed`: files changed in the workspace. ## Error codes [#error-codes] | Code | Means | |---|---| | `FORBIDDEN` | The role does not allow it. Nothing ran. | | `BAD_REQUEST` | Wrong params, or a path outside the workspace. Nothing ran. | | `UNKNOWN_METHOD` | No method by that name. | | `NOT_FOUND` | No such tile, frame or workspace. | | `ASLEEP` | The agent is asleep: wake it first. | | `NO_AGENT` | The tile runs no agent (a tool, a browser, a shell), and the method asks an agent's reply. | | `UNSUPPORTED` | The agent cannot do that: it does not tell Hivemind when it finishes replying, or keeps no sessions. | | `TIMEOUT` | What it waited on did not come in time. | | `UNAVAILABLE` | It needs one of your windows open. | | `RATE_LIMITED` | Too many started at once. Ask again later. | | `DEPTH_EXCEEDED` | Agents started by agents, too many levels deep. Start it from higher up. | | `OCCLUDED` | Something is drawn over the tile `tile.look` would picture; the message names it. Nothing was pictured. | | `FAILED` | It ran and failed. `message` says why. | ## A whole example [#a-whole-example] This connects, lists the agents and tries to start one. With a `view` token the start is refused. Both run on Linux and macOS, over a Unix socket. ```python Python import json, os, socket SOCK = os.environ["HIVE_DRIVE_SOCK"] TOKEN = os.environ["HIVE_DRIVE_TOKEN"] FOLDER = os.environ["HIVE_WORKSPACE"] s = socket.socket(socket.AF_UNIX) s.connect(SOCK) f = s.makefile("rw") def send(msg): f.write(json.dumps(msg) + "\n") f.flush() def call(id, method, *params): send({"id": id, "method": method, "params": list(params)}) while True: msg = json.loads(f.readline()) if isinstance(msg, dict) and msg.get("id") == id: # not an event return msg send({"hello": {"token": TOKEN, "workspace": FOLDER}}) print(f.readline()) # {"hello": {"api": "0.30", "as": {…}}} print(call(1, "agent.list", FOLDER)) # {'id': 1, 'result': {'seq': 0, …}} print(call(2, "agent.start", FOLDER, {"program": "claude", "prompt": "Run the tests"})) ``` ```js Node import net from "node:net"; import readline from "node:readline"; const { HIVE_DRIVE_SOCK, HIVE_DRIVE_TOKEN, HIVE_WORKSPACE } = process.env; const socket = net.connect(HIVE_DRIVE_SOCK); const waiting = new Map(); let next = 1; const call = (method, ...params) => new Promise((resolve) => { const id = next++; waiting.set(id, resolve); socket.write(JSON.stringify({ id, method, params }) + "\n"); }); readline.createInterface({ input: socket }).on("line", (line) => { const msg = JSON.parse(line); if (waiting.has(msg.id)) { waiting.get(msg.id)(msg); waiting.delete(msg.id); } else console.log(line); // the hello, then events }); socket.write(JSON.stringify({ hello: { token: HIVE_DRIVE_TOKEN, workspace: HIVE_WORKSPACE } }) + "\n"); console.log(await call("agent.list", HIVE_WORKSPACE)); console.log(await call("agent.start", HIVE_WORKSPACE, { program: "claude", prompt: "Run the tests" })); socket.end(); ``` ## Start an agent and wait for its reply [#start-an-agent-and-wait-for-its-reply] With an `agents` token: ```json {"id": 3, "method": "agent.start", "params": ["/home/you/work/api", {"program": "claude", "prompt": "Run the tests"}]} {"id": 3, "result": {"tile": "…"}} {"id": 4, "method": "agent.read", "params": ["", 600000]} {"id": 4, "result": {"text": "…", "finalStatus": "turn", "truncated": false}} ``` `agent.read` waits up to the milliseconds you give for the agent to finish replying. `finalStatus` is `turn`, `timeout`, `working`, `idle`, `closed` or `waiting`. A tile that runs no agent is refused `NO_AGENT`, and an agent asleep `ASLEEP`. The full protocol is [`spec/workspace-api.md`](https://github.com/dip497/hivemind/blob/main/spec/workspace-api.md) in the repository. --- # Make an API token > Make a token so one of your programs can drive a workspace, choose its role, and revoke it when you are done. Source: https://hivemind.griiken.com/guide/api-tokens/ Make a token when a program of yours should drive a workspace: a dashboard, a script, an orchestrator. {` Make a Hivemind API token for one of my programs, at the smallest role it needs, and store it safely. 1. Ask me what the program is called, which workspace folder it drives, and what it does. Choose the role from that: \`view\` only reads; \`edit\` also presses widgets and opens tool tiles; \`terminals\` also types into terminals; \`agents\` also starts, answers and closes agents. Tell me the role you chose and why. 2. Check Hivemind runs with that folder open: \`hive ctl agents\` must not exit 3. If it does, ask me to open the folder with \`hivemind \`. 3. Make it, with an expiry unless I ask otherwise: \`hive grant create -w --role --expires 30d --json\`. The output holds \`token\` (shown only this once) and \`socket\`. 4. Never show the token in this chat and never put it in a file git tracks. Write it to a git-ignored \`.env\` beside the program as \`HIVE_DRIVE_TOKEN=…\`, with \`HIVE_DRIVE_SOCK=\` and \`HIVE_WORKSPACE=\`. Check \`git check-ignore .env\` confirms it is ignored; add it to \`.gitignore\` if not. 5. Check it works: with those variables loaded, \`hive ctl agents --json\` prints the workspace's agents. At the end, tell me the token's id and role from \`hive grant list\`, where the token is stored, and that \`hive grant revoke \` takes it back. `} ## Before you start [#before-you-start] - Hivemind is running with the workspace open, or `hive host` serves it. - You know what the program does, so you can pick the smallest role. See [Choose a role](#choose-a-role). ## Make the token [#make-the-token] Open the workspace, then **Settings → API access**. Under **New token**, name what uses it, for example *my dashboard*. Pick what it may do. Press **Create token**, then **Copy**. The token is shown this once. A token made in Settings reaches the workspace in that window and never expires. To make a read-only token that lasts 30 days, run: ```bash hive grant create dashboard -w ~/work/api --role view --expires 30d ``` It prints the token first, shown once (long lines wrapped here): ```text hgr_… dashboard may view in api, until 2026-11-17T09:00:00Z (`hive grant revoke 1a2b3c4d5e6f`). It connects to ~/.config/hivemind/drive.sock and says {"hello": {"token": "", "workspace": ""}}. ``` | Option | Means | |---|---| | `` | What the program is called. It shows in the token list and the audit log. | | `-w`, `--workspace` | A workspace it may drive: its folder, name or id. Repeat it for more. | | `--role` | `view`, `edit`, `terminals` or `agents`. Without it, `agents`. | | `--expires` | How long it lasts: `12h`, `30d`. Without it, until you revoke it. | | `--json` | Prints `{grant, token, socket}`. | Hivemind keeps only a hash of each token. A lost token cannot be shown again, so make a new one. Settings → API access: the New token form with a name, a role menu set to Drive agents, and Create token; the Tokens list is empty. ## Choose a role [#choose-a-role] Each role can do everything the roles above it can. People and programs get the same four roles. | Role | For a person, the app says | For a token, **API access** says | Can | |---|---|---|---| | `view` | **Can view** | **View** | see the canvas, terminals, agents and their replies, files, diffs, issues and review comments | | `edit` | **Can edit board** | **Edit** | also move, add and close tiles, press widgets, open a tool's tile | | `terminals` | **Can use terminals** | **Use terminals** | also type into terminals (a person once given the keyboard) | | `agents` | **Can drive agents** | **Drive agents** | also start, answer, message, put to sleep and close agents, which means running commands on your computer. A person gets it only while they are here, after a warning. | A dashboard needs `view`; an orchestrator that starts agents needs `agents`. A call the role does not allow is answered `FORBIDDEN` and never runs. The full list is on [Methods by role](https://hivemind.griiken.com/guide/api-methods/). ## Check it worked [#check-it-worked] To see your tokens, run: ```bash hive grant list ``` ```text 1a2b3c4d5e6f dashboard view /home/you/work/api expires 2026-11-17T09:00:00Z last used never ``` **Settings → API access** shows the same list, with when each token was last used. ## Revoke a token [#revoke-a-token] Press **Revoke** in **Settings → API access**, or run it with the id from `hive grant list`: ```bash hive grant revoke 1a2b3c4d5e6f ``` Revoking closes the program's connections at once. An expired token closes them at that moment too. ## If it didn't work [#if-it-didnt-work] | What you see | Fix | |---|---| | `hive ctl` exits 3 | Neither the app nor `hive host` is running. Open the workspace with `hivemind `. | | `FORBIDDEN` on hello | The token is wrong, revoked or expired, or does not reach that workspace. Make a new one. | | `BAD_REQUEST` on hello | Name the workspace's folder, and open it in the app first. | More in [Troubleshooting](https://hivemind.griiken.com/guide/troubleshooting/). ## Related [#related] - [API overview](https://hivemind.griiken.com/guide/api/): how tokens and roles fit together. - [Connect and call](https://hivemind.griiken.com/guide/api-connect/): use the token from a program. --- # API overview > Let a program of your own drive a workspace: start agents, read their replies, follow who is waiting, all with a token you can revoke. Source: https://hivemind.griiken.com/guide/api/ The API lets a program on your computer drive a workspace the way you do. Think of an orchestrator that hands work to agents, a dashboard of who is waiting, or a script your CI calls. {` Write me a small script that lists the agents in my Hivemind workspace that are waiting on me, using a read-only API token. 1. Ask me which project folder is the workspace. Check Hivemind runs with it open: \`hive ctl agents\` must not exit 3. If it does, ask me to open it with \`hivemind \`. 2. Make a token with the smallest role, \`view\`: \`hive grant create waiting-list -w --role view --expires 30d --json\`. The output holds \`token\` and \`socket\`. Never print the token in this chat and never write it to a file git tracks. Put it in a git-ignored \`.env\` as \`HIVE_DRIVE_TOKEN\`, with \`HIVE_DRIVE_SOCK\` (the socket) and \`HIVE_WORKSPACE\` (the folder). 3. Check the token works: with those variables set, \`hive ctl agents --json\` prints the workspace's agents. 4. Write the script in TypeScript or Python with the \`hivemind-api\` SDK (it comes with the app: \`npm install ~/.hivemind-app/sdk/hivemind-api.tgz\` or \`pip install ~/.hivemind-app/sdk/python\`; on Windows the folder is \`%LOCALAPPDATA%\\hivemind\\sdk\`). \`connect()\` reads the token, workspace and socket from those variables. Call \`hive.agents.list()\` and print each agent whose \`waiting\` field is set, with its name and what it waits on. 5. Run it and show me the output. At the end, tell me the token's id from \`hive grant list\` and that \`hive grant revoke \` takes it back. `} ![Diagram: Every call is checked against the token's role](https://hivemind.griiken.com/guide/images/api-drive.svg) - **Your program** → **drive socket**: a hello with its token. - Each call → the token's **role**. Allowed: it reaches **the workspace**, its agents, terminals and board. Not allowed: refused with `FORBIDDEN`. ## How it works [#how-it-works] Your program talks to the app through a local connection that only your user can open (`drive.sock`, a named pipe on Windows). The app serves it, or `hive host` when that runs instead. | Piece | What it is | |---|---| | **Token** | A secret your program sends first. You make it in **Settings → API access** or with `hive grant create`. It is shown once. | | **Role** | What the token may do: `view`, `edit`, `terminals` or `agents`. These are the same roles people get when you [share a workspace](https://hivemind.griiken.com/guide/multiplayer/). | | **Messages** | One line of JSON per message, both ways. You send calls; the app sends answers and events. | ## Why it works this way [#why-it-works-this-way] A token reaches only the workspaces you name, at one role. A call the role does not allow is refused before it runs. Revoking a token closes its connections at once. So a program never does more than you chose, and never for longer than you allow. Whatever its role, a program cannot share the workspace, let people in, change their roles, or make or revoke tokens. Those stay with you. The `terminals` and `agents` roles can still change files and run any command, `git push` included. They do it through a shell they type into, or an agent they start. ## Write a client [#write-a-client] Use the `hivemind-api` SDK for TypeScript or Python: [Connect and call](https://hivemind.griiken.com/guide/api-connect/) walks through it. For any other language, the [Protocol](https://hivemind.griiken.com/guide/api-protocol/) page has the raw messages. ## What to do with it [#what-to-do-with-it] Pick the smallest role that does the job. Say hello, call a method, hear events. Every method, and the role it needs. The raw messages, for any language. ## Without writing a client [#without-writing-a-client] `hive ctl` speaks the same API. To act as the program, give it the token: ```bash export HIVE_DRIVE_TOKEN=hgr_… export HIVE_WORKSPACE=~/work/api # only when the token reaches several workspaces hive ctl agents --json hive ctl spawn --agent claude --prompt "Run the tests" # needs the agents role ``` A [tool's service](https://hivemind.griiken.com/guide/tool-plugins/#a-service-that-keeps-running) gets its own token this way. It is made when the service starts and revoked when it stops. --- # Agent states > What working, needs you, idle, exited and asleep mean on an agent's tile, and how Hivemind knows. Source: https://hivemind.griiken.com/guide/agent-states/ Every agent's tile shows one state: what the agent is doing, and whether it waits on you. The same state shows on its row in the Layers panel, its frame, and in your notifications. {` Tell me what each of my Hivemind agents is doing right now. Do not change anything. 1. Run \`hive ctl agents --json\`. If it exits 3, tell me Hivemind is not open on this project and stop. 2. Group the agents by state: needs you first, then working, then idle, then exited and asleep. 3. For each agent that needs me, say what it is waiting on, in one line. 4. Suggest which one I should answer first, and why. `} Agents grouped by state: two agents under Waiting on you that want permission, six under Working, three under Ready for work, none Stopped. ## The states [#the-states] | State | Colour | Means | |---|---|---| | **working** | white | busy on its task | | **needs you** | amber | waiting for a person: a permission question or a question with options | | **blocked** | amber | waiting on a person for another reason | | **review?** | amber | waiting for you to approve its plan | | **approval?** | amber | a supervised worker, waiting for its lead to approve a tool. Its lead answers, so the app does not tell you | | **idle** | grey | at its prompt, ready for a task | | **exited** | grey, red if it failed | its program has stopped | | asleep | — | put to sleep: its program stopped, its conversation kept, with **Resume** | A dot on a row means the agent finished since you last looked. **Mark as read** in the row's ⋮ menu clears it. Amber always means a person is being waited on. When a frame is collapsed, its dot shows the most urgent state inside it, so needs you wins. ![Diagram: How an agent moves between states](https://hivemind.griiken.com/guide/images/agent-states.svg) - Start → **idle**. - idle → **working**: a turn starts. working → idle: the turn ends, and a dot shows until you look. - working → **needs you**: it asks you. needs you → working: you answer. - idle → **asleep**: **Sleep**. asleep → idle: **Resume**. - Any state → **exited**: its program stops. ## How it works [#how-it-works] ![Diagram: How Hivemind knows](https://hivemind.griiken.com/guide/images/agent-state-sources.svg) - **Hooks** → **background process**: the agent tells Hivemind when it starts working, stops to ask, or finishes replying. Exact and immediate. - **Screen rules** → background process: for an agent that sends nothing, rules in its agent file read its screen for its prompt, its questions and its spinner. - The screen decides until the agent's first hook arrives. From then on, the hooks do. - Background process → **everywhere it shows**: the tile, the Layers panel, notifications and your phone. - The computer that runs an agent works out its state. Other devices show what it says. Which of the two an agent uses is in its agent file. See [Add your own agent](https://hivemind.griiken.com/guide/agent-providers/). ## Why it works this way [#why-it-works-this-way] An agent's own messages are the only exact source, but not every agent sends them. Reading the screen covers the rest, so every agent shows a state. Only agents that tell Hivemind when they finish replying can work for another agent: the lead needs to know when a reply is complete. ## What to do with it [#what-to-do-with-it] - [Know who is waiting](https://hivemind.griiken.com/guide/know-who-is-waiting/): the bell, notifications and push. - [Run agents](https://hivemind.griiken.com/guide/agents/): sleep and resume. - [Coordinate agents](https://hivemind.griiken.com/guide/agent-workflows/): which agents can be workers. --- # Architecture overview > What runs on your computer, on your server, on other machines and on your phone, how the parts talk, and what stays on your computer. Source: https://hivemind.griiken.com/guide/architecture/ Your agents build the workspace they work in. They start other agents, open views, add widgets and run tools with the same `hive` command you use. This page shows the parts behind that, and where each one runs. {` Map my Hivemind setup onto the parts on the "Architecture overview" page. Do not change anything. 1. Run \`hive --version\` and \`hive daemon status\`: is the background process running? 2. Run \`hive ctl agents --json\`. If it exits 3, the app is not open on this project; say so and go on. 3. Run \`hive network show\`, \`hive machine list\` and \`hive host status\` (it may say no host runs here). 4. For each part on the page (desktop app, background process, hive command, network server, phone page, machines, host, HiveHub), tell me whether it runs or is set up here, and what links to it. `} ![Diagram: What runs where](https://hivemind.griiken.com/guide/images/architecture.svg) - **Desktop app**, on your computer: the windows, the canvas and views. It starts the background process and hive-net. - **Background process**, on your computer: runs every terminal and agent, and works out each agent's state. It talks to the app over a local socket. - **Your agents** run in terminals of the background process. Their hooks tell it what they do. - **hive command**: you, your agents and your programs drive the app through `drive.sock`. - Desktop app → **HiveHub**: https, to install plugins. - Desktop app → **network server**: encrypted end to end. Your server relays it, and serves the **phone page** over https. - Desktop app → **machine**: ssh. Network server ↔ **host**: relay. - Stays on this computer: your keys, settings, API tokens and saved screens. ## The parts [#the-parts] Windows, the main process, and the sockets it serves. What keeps your agents running when the app closes. How you and your agents drive the app. Agents, views, widgets and tools, and HiveHub. Keys, the relay, and your own server. What your phone sees, and how. Agents on another computer. Every file Hivemind keeps. ## For agents [#for-agents] Everything an agent does goes through `hive ctl` on the drive socket, or the same methods from your own program with a token ([API](https://hivemind.griiken.com/guide/api/)). Which part each one touches: | Part | `hive ctl` | API methods | |---|---|---| | Agents in the background process | `agents`, `spawn`, `send`, `keys`, `read`, `stream`, `sessions`, `sleep`, `wake`, `rename`, `close` | `agent.*`, `status.all`, `terminal.*` | | Agents working together | `workflow`, `approve`, `approval`, `report`, `inbox`, `connect`, `disconnect` | `link.connect`, `link.disconnect` | | Workspace and frames | `frames`, `frame add`, `list-workspaces` | `frame.open`, `frame.close`, `worktree.list`, `store.*` | | Desktop app windows | `focus`, `open-review` | `presence.set`, `appearance.get` | | Plugins | `plugin list`, `plugin open`, `plugin commands`, `plugin call`, `plugin close`, `open-tool`, `view emit` | `widget.*`, `tool.open`, `view.*` | | Issues | `set-state`, `add-comment`, `mark-acceptance`, `delete-issue` | `issue.list`, `issue.read` | | hive-net, phone, machines, hosts | none: use `hive network`, `hive machine`, `hive host` | none | `hive ctl` needs the app or `hive host` running for the workspace; it exits 3 when neither is. Every command is in the [CLI reference](https://hivemind.griiken.com/guide/cli/), every method in [Methods](https://hivemind.griiken.com/guide/api-methods/). --- # Terminals and the background process > How the background process runs every terminal and agent, keeps their screens, and keeps them running when the app closes. Source: https://hivemind.griiken.com/guide/background-process/ Every terminal and agent runs in the background process, not in the window. The window only shows them. So closing the app, or updating it, stops nothing unless you choose **Stop everything** as you quit. {` Check the Hivemind background process on this computer. Do not change anything. 1. Run \`hive daemon status\` and tell me whether it runs. 2. Run \`hive ps\` and list the sessions it keeps, with their folders. 3. If the app is open, run \`hive ctl agents --json\` and match each agent to its session. Tell me anything that runs with no tile, and any tile whose program has stopped. `} ![Diagram: From an agent to its tile](https://hivemind.griiken.com/guide/images/terminal-bytes.svg) - **Agent program** → **background process**: what it prints. Your keys go the other way. - Background process → **desktop app**: the output, live. The app draws it in the tile. - Desktop app → background process: attach. The screen is replayed first, then output goes on live. - Background process → **saved screens**: a copy of each screen on disk, kept 30 days. ## What is kept [#what-is-kept] | When | What happens | |---|---| | You quit (⌘Q on a Mac, Ctrl+Q elsewhere, or closing the last window) while something runs | The app asks: **Keep them running**, **Stop everything** or **Cancel**. With nothing running it quits at once. | | You quit and choose Keep them running | Terminals and agents keep running. | | You quit and choose Stop everything | The background process stops, as `hive daemon stop` does. Each session's screen is saved, and the next start brings it back: agents that can resume continue their conversation. Agents on other machines keep running. | | The background process restarts, or the computer reboots | Agents that can resume continue their conversation; others start fresh. Screens replay from disk. | | You close a tile (×) | Its program ends. | | You put an agent to sleep | Its program ends. Its tile keeps its name and conversation, with **Resume**. | Tick **Don't ask again** in that question to keep your choice. Change it back in Settings → About and updates → **When you quit while agents run**. **Quit and stop agents**, in the Open Recent menu (Ctrl+R), stops everything without asking. A quit started by an update, by `hive`, or by any program rather than you never asks and stops nothing. ## It also works out agent states [#it-also-works-out-agent-states] Each agent's hooks and screen reach the background process, which decides the agent's state. See [Agent states](https://hivemind.griiken.com/guide/agent-states/). ## Without the app [#without-the-app] On a computer without the app, `hive daemon start` runs the same background process. [Machines and hosts](https://hivemind.griiken.com/guide/remote-machines/) use this. --- # Data and where it is stored > Every file Hivemind keeps, which folder it is in, and what is never written down. Source: https://hivemind.griiken.com/guide/data-and-storage/ Hivemind keeps your data on your own computers: in two folders, and in your project's own `.hivemind/` folder. {` List what Hivemind keeps on this computer, using the "Data and where it is stored" page. Do not change or print the contents of any key or token file. 1. Find the app data folder for this system from the page (or \`$HIVEMIND_APP_DATA\` if set) and the config folder (\`$XDG_CONFIG_HOME/hivemind\`, else \`~/.config/hivemind\`). 2. For each row of the page's tables, say whether the file or folder exists here and how big it is. 3. Say which ones I would back up, and which a reinstall would make again. `} ## The two folders [#the-two-folders] | Folder | Linux | macOS | Windows | |---|---|---|---| | Config folder | `~/.config/hivemind` | `~/.config/hivemind` | `~/.config/hivemind` | | App data folder | `~/.config/hivemind` | `~/Library/Application Support/hivemind` | `%APPDATA%\hivemind` | `XDG_CONFIG_HOME`, when set, replaces `~/.config`. `HIVEMIND_APP_DATA` names another app data folder. ## What is where [#what-is-where] | What | Where | Note | |---|---|---| | Settings | config folder, `settings.json` | shared by the app and `hive`. Every setting: [Settings](https://hivemind.griiken.com/guide/settings/) | | Agent files | config folder, `agents/` | a project may add its own in `.hivemind/agents/` | | Views, widgets and tools you install | config folder, `packages/` | each version's files in `packages/store/`, never changed; which version is in use and whether it is on in `packages/installed.json`. A project may add its own views in `.hivemind/views/` | | Saved machines | config folder, `machines.json` | | | Each workspace's layout: frames, tiles, viewport | app data folder, `workspaces/` | one file per project; shared workspaces in `shared/` | | Window sizes and places | app data folder, `window-state.json` | | | Saved screens | app data folder, `sessions/` | kept 30 days, so a screen survives a reboot | | This device's keys | app data folder, `identity/` | never leave this computer | | API tokens | app data folder, `grants.json` | only a hash of each token | | Issues | your project, `.hivemind/` | Markdown, in your repository | | Logs | app data folder | which file for what: [Logs and bug reports](https://hivemind.griiken.com/guide/logs-and-bug-reports/) | | What updates changed in your data | each folder's `migrations/`: `ledger.json` and `backups/` | [When an update changes your data](https://hivemind.griiken.com/guide/data-updates/) | A host keeps the same files in its own data folder on the server. What a widget draws is never saved: it is drawn again each time. --- # When an update changes your data > How a new version moves the files on your computer to the shape it reads, once, with a backup, and how to put them back. Source: https://hivemind.griiken.com/guide/data-updates/ Sometimes a new version keeps your data in a new shape: the views, widgets and tools you installed moved into packages, for example. The first time the new version starts, it moves your data to that shape, once. Nothing for you to do. {` Show me what Hivemind updates changed in my data on this computer, using the "When an update changes your data" page. 1. Run \`hive migrations --json\` and list, for each data folder, the changes that ran, which version ran each and when, and whether its backup is still kept. 2. If anything is still to run or failed, say what and why, and what the page says to do about it. 3. Do not run \`hive migrations restore\` unless I ask for it. `} ## What happens on the first start [#what-happens-on-the-first-start] The app, a `hive` command or `hive host`, whichever starts first, runs each change this version has that your data has not had yet, in order: 1. It copies the files that change will touch into `migrations/backups//`. 2. It makes the change. 3. It writes the change into `migrations/ledger.json`, with the version that made it and when. Each data folder keeps its own ledger: the config folder and the app data folder ([Data and where it is stored](https://hivemind.griiken.com/guide/data-and-storage/)), which are one folder on Linux. If a second Hivemind process starts meanwhile, it waits up to two minutes for the first to finish, and says so. A change that was cut off (a crash, a power cut) runs again on the next start, from where it was. A `hive` command started while an older app still runs leaves the files that app reads where they are, and says `quit Hivemind to finish updating your data`. Quit the app and start it again. ## See what changed [#see-what-changed] ```bash hive migrations ``` It lists each change that ran, by which version, how long it took and where its backup is; any change still to run; and the last one that failed, with why. `--json` gives the same for a script or an agent. A plugin a change could not keep (its files no longer pass the checks) is named in that change's result, and its folder stays in the backup. ## Put it back [#put-it-back] ```bash hive migrations restore 0001-adopt-plugins-as-packages ``` This puts back the files as they were before that change, and before every change after it, and takes them out of the ledger. Quit the app and stop `hive host` first: it refuses while either runs, and changes nothing. The next start makes the changes again, so use it with the version you want to stay on (see [Update and roll back](https://hivemind.griiken.com/guide/update-and-roll-back/)). The backups of the last three changes, and of any made in the last 90 days, are kept. A change is dropped from Hivemind six months after it shipped. ## A version older than your data [#a-version-older-than-your-data] If you go back to an older version after a newer one changed your data, the older one says once that your data was updated by the newer one, and starts anyway. `hive migrations restore` names the change to put back. --- # The desktop app > What a window, the main process and its helpers each do, and the sockets the app listens on. Source: https://hivemind.griiken.com/guide/desktop-app/ The desktop app is one program. Each window draws a workspace. One main process does the rest: it keeps your settings and workspaces, and starts the helpers that run your agents and reach your other devices. ![Diagram: Inside the desktop app](https://hivemind.griiken.com/guide/images/desktop-processes.svg) - **Window** ↔ **main process**: the app's own messages (IPC). A window draws the canvas, tiles and views. It opens no file and no connection itself. - **hive ctl, programs** → main process: `drive.sock`, with a token. See [The hive command](https://hivemind.griiken.com/guide/hive-cli/). - **Browser tab** → main process: a WebSocket on 127.0.0.1. See [Open the app in a browser tab](https://hivemind.griiken.com/guide/browser-tab/). - Main process ↔ **background process**: a local socket. See [Terminals and the background process](https://hivemind.griiken.com/guide/background-process/). - Main process ↔ **hive-net**: a local socket. See [Devices and hive-net](https://hivemind.griiken.com/guide/how-devices-connect/). - Close every window: the background process keeps your terminals and agents running. ## Windows and workspaces [#windows-and-workspaces] Each window shows one workspace. Open a second window for a second project; both share the one main process and the one background process. The main process saves each workspace's layout as you change it, and each window's size and place. Where: [Data and where it is stored](https://hivemind.griiken.com/guide/data-and-storage/). ## Plugins in a window [#plugins-in-a-window] A window runs views, widgets and tools, each in a different place. What each can reach: [Trust, permissions and privacy](https://hivemind.griiken.com/guide/security-and-privacy/). --- # The hive command and its sockets > What hive does on its own, how hive ctl reaches the app or a host, and the two local sockets behind it. Source: https://hivemind.griiken.com/guide/hive-cli/ `hive` is one command for you and your agents. Most of it works alone: issues, plugins, machines, your network. `hive ctl` drives a running workspace: the app, or `hive host` on a server. An agent in a tile uses the same `hive ctl` you type. {` Check that the hive command can drive my Hivemind workspace. Do not change anything. 1. Run \`hive --version\`. 2. Run \`hive ctl agents --json\` in this project. If it exits 3, the app is not open here and no host runs; tell me and stop. Otherwise summarise what it lists. 3. Run \`hive ctl list-workspaces\` and tell me which workspaces this computer knows. 4. If \`$HIVEMIND_TILE\` is set, tell me I am an agent in a tile, and which one. `} ![Diagram: Two local sockets](https://hivemind.griiken.com/guide/images/drive-sockets.svg) - **hive ctl** and **your program** → **drive socket** (`drive.sock`): a hello with a token, then calls. The app or `hive host` checks the token's role. See [API](https://hivemind.griiken.com/guide/api/). - **Agent hook** → **control socket** (`hcp.sock`): one `agent.event` each time the agent starts a turn, asks, or finishes. - The background process owns the control socket, works out the agent's state, and passes each event on to the app or host (`hcp-host.sock`). - `hive ctl report` and `hive ctl inbox` use the control socket too. - Like the drive socket, the control socket opens only for your user: a file with mode 0600, or a named pipe on Windows. ## Inside a tile [#inside-a-tile] Hivemind starts each agent with `HIVEMIND_TILE` set to its tile's id, and a token for that tile. So `hive ctl` in a tile acts as that agent: a worker it spawns is its own, and `hive ctl report` answers its lead. The variables are in [Environment variables](https://hivemind.griiken.com/guide/environment-variables/). ## Teach your agent [#teach-your-agent] The `hive` skills teach an agent every `hive ctl` command: [Use these docs from your agent](https://hivemind.griiken.com/guide/docs-for-agents/). Every command is in the [CLI reference](https://hivemind.griiken.com/guide/cli/). --- # Devices and hive-net > How your computers, phone and guests find each other and talk: directly, through your relay, always encrypted end to end. Source: https://hivemind.griiken.com/guide/how-devices-connect/ hive-net is the part of Hivemind that reaches your other devices and the people you let in. It runs beside the app on each computer and host. Every device has its own key. Devices find each other by that key, then talk directly when they can, or through your relay when they cannot. {`Explain how my Hivemind devices connect, using the "How devices connect" page and what this computer reports. Run only read-only commands: \`hive network show\`, \`hive network doctor\` and, if \`hive host status\` answers, that too. Tell me: which network this computer is on, which relay, lookup and access servers it uses, whether they answer, and what a phone or a guest elsewhere would need to reach me. Do not change anything.`} ![Diagram: Two devices, one key each](https://hivemind.griiken.com/guide/images/devices-net.svg) - **Your computer** ↔ **another device**: direct, when the network lets them. - Otherwise both ↔ your **network server**, which relays between them. - Each device has its own key, and encrypts with it. - The server's roles are in the table under [Across networks](#across-networks). ## How it works [#how-it-works] ### On one network [#on-one-network] With no server, **Settings → Servers** reads *Local network*. Devices find each other on that network, and nothing leaves it. The six words of an invite work only here. ### Across networks [#across-networks] To reach a device elsewhere, you run your own [network server](https://hivemind.griiken.com/guide/self-hosting/). It has up to four parts: | Part | Does | |---|---| | Relay | Passes traffic between devices that cannot reach each other directly. | | Lookup | Lets a device find another by its id, and find which device hosts a workspace. | | Access | Lets in only the devices you enrol, and guests they vouch for. | | Push | Tells your phones when an agent needs you. | ### Encrypted end to end [#encrypted-end-to-end] Traffic between two devices is encrypted with their own keys. The relay passes it on but cannot read it. Push notices are encrypted to the phone, so the server cannot read them either. What your server does know: which devices are enrolled, and which device hosts a workspace. ### Invites and the three words [#invites-and-the-three-words] An [invite](https://hivemind.griiken.com/guide/connect/) carries a code: six words, a link or a QR code. When another device uses it, both screens show three words. They come from the code and both devices' keys. If anyone sits between the two devices, the words differ. So you answer only when they match. ### The phone page [#the-phone-page] Your phone reaches your computer the same way, from a page your server serves. See [The phone page](https://hivemind.griiken.com/guide/phone-page/). ## Why it works this way [#why-it-works-this-way] - **No hosted server.** Your traffic and your list of devices stay on machines you run. - **Keys, not accounts.** A device is who its key says. Nothing to sign up for, and nothing to leak but the key. - **The three words.** A code can be overheard. The words catch it. ## What to do with it [#what-to-do-with-it] - [Set up your own network server](https://hivemind.griiken.com/guide/self-hosting/) - [Connect your devices](https://hivemind.griiken.com/guide/connect/) - [Answer agents from your phone](https://hivemind.griiken.com/guide/phone/) - [Trust, permissions and privacy](https://hivemind.griiken.com/guide/security-and-privacy/) - Every server option: [hive-net reference](https://hivemind.griiken.com/guide/hive-net/) --- # The plugin index > What a hub serves, how the app and hive read it, and what happens to an entry they cannot read. Source: https://hivemind.griiken.com/guide/hub-index/ A hub lists its plugins in one file, `index.json`. HiveHub serves its own at `/api/v1/index.json` on its site. **Settings → Plugins** and `hive agents install`, `hive views install`, `hive widgets install` and `hive tools install` read it. ## What the index holds [#what-the-index-holds] The index is `{ "version": 1, "plugins": [...] }`. Each entry names one plugin: | Field | What it says | |---|---| | `id`, `type` | the plugin's id and its kind: `agent`, `view`, `widget`, `tool` or `package` | | `name`, `description`, `author`, `version` | what the list shows | | `path`, `source` | the folder of its files, and the https address they are under | | `files` | every file, each with its SHA-256 | | `minAppVersion` | the oldest Hivemind it runs on: an agent's or tool's own, or for a view, widget or package the release that first reads a field it uses ([since.ts](https://github.com/dip497/hivemind/blob/main/packages/hive-hub/src/since.ts)) | | `bin`, `icon` | an agent's program and its mark | | `category` | where it is listed | | `members` | a package's plugins: each one's kind, id, name and permissions | How each file is checked before it installs: [What you install from HiveHub](https://hivemind.griiken.com/guide/security-and-privacy/#what-you-install-from-hivehub). ## An entry the app cannot read [#an-entry-the-app-cannot-read] The app reads each entry on its own. An entry it cannot read is skipped, and the rest are still listed. That happens when its id does not fit its kind, a field is missing or malformed, or its kind is one this Hivemind does not know. - `hive views install @owner/name` and the other install commands say why, when the plugin you asked for is the one skipped. - The app writes each skipped entry and its reason to its log. A file that is not a version 1 index at all is refused as a whole. ## Limits [#limits] An index lists at most 2,000 plugins and is at most 4 MB. Past 2,000, the rest are skipped and the app says how many were listed. ## The hub kit [#the-hub-kit] The index format and its reader are one package in the Hivemind repository, the hub kit (`@hivemind/hub`). The app and `hive` read every index with it. The kit also holds the checks a plugin folder must pass. A hub built on the kit runs them before it lists a plugin. The app runs the same checks on the files it downloaded, before it installs them: - at most 200 files, 2 MB per file and 8 MB in all, each a plain relative path; - one manifest Hivemind accepts: `hivemind-package.json`, `agent.yaml`, `hivemind-view.json`, `widget.json` or `hivemind-tool.json`; - in a package, every member checked as that kind is checked alone, and owned by the package's owner; - an id that fits its kind, and a category Hivemind knows; - a view's entry file, a widget's code or drawing, and a version on widgets and tools. A folder that fails, or that says it is another plugin than the one listed, is not installed, and the install says why. A hub that cannot read a whole folder in one go, such as one on a Cloudflare Worker, reads it a few files at a time. `firstReads` names the manifests and README at the folder's top, from its paths and sizes. With their texts, `planRead` names everything else to read, which for a package is only what installs, and the few files whose text the checks read. `listedFile` keeps each file's size, SHA-256 and, for those few, its text. `checkPluginListing` then gives the answer `checkPluginFolder` gives for the same files. Give it only the files `planRead` names: it holds every file it is given to the limits, so a package's sources beside its members would count. Each Hivemind release carries the kit as `hivemind-hub-.tgz`. Its one dependency, `zod`, comes from npm. It runs in Node, Bun and a Cloudflare Worker. A hub depends on it by its address on the release, for example: ```bash npm install https://github.com/dip497/hivemind/releases/download/v/hivemind-hub-.tgz ``` A hub's checks are then those of one Hivemind release. --- # The phone page > What the phone page is, how it sees your agents through your own server, and what a phone may and may not do. Source: https://hivemind.griiken.com/guide/phone-page/ The phone page is Hivemind on your phone: a web page your phone's browser opens. Your own network server serves it, at `/phone/`. It reaches your computer through that server, because a browser cannot reach a device directly. The page comes inside hive-net, so your server always serves the page of its own release. When hive-net is upgraded, the running server starts the new one in its place, and the phone gets the new page on its next open. An upgrade does not sign your phone out: its key is kept by its browser, not by the server. ![Diagram: How your phone sees an agent](https://hivemind.griiken.com/guide/images/phone-flow.svg) - **Agent** → **background process**: its hook says it asks something. - Background process → **desktop app** (or `hive host`): the agent's new state. - Desktop app → **network server** → **phone page**: every agent and what waits on you, relayed, encrypted end to end. - Network server → phone: a push notice when the page is closed, encrypted to the phone. ## What a phone may do [#what-a-phone-may-do] A paired phone acts as you, but only for what a phone is for: | May | May not | |---|---| | Watch and type into a running terminal | Start, size or close a terminal | | Answer an agent, and send it a message | Edit the canvas, or read your files | | See what waits on you, and get a push | Host a workspace | | Show a view made for phones | Hold your person key: it never leaves your computer | | Unpair itself | | To pair one, see [Answer agents from your phone](https://hivemind.griiken.com/guide/phone/). --- # Plugins > The four kinds of plugin, where each sits on screen, where HiveHub fits, and how to add or make one. Source: https://hivemind.griiken.com/guide/plugins/ A plugin adds something to Hivemind. Your agents can make one, install one and open one while they work. The **Windows** view and the **Issues** tool ship with the app as plugins too. {` Tell me about the Hivemind plugins on this computer. Do not change anything. 1. Run \`hive plugins list --json\`. For each plugin, say its kind (agent, view, widget or tool), whether it is on, and any problem it reports. 2. Say which ones can read my files or run programs (agents and tools can), and which run with no files and no network (views and widgets). 3. If I said what I want to add, find a match: get the \`hivehub\` command with \`curl -fsSL https://hivehub.griiken.workers.dev/hivehub.mjs -o ~/.local/bin/hivehub && chmod +x ~/.local/bin/hivehub\` (it needs Node), run \`hivehub search\` with a few words, and \`hivehub info\` with the best id. Show me what it asks for. Do not install it. At the end, list what I have, what each may touch, and the command that would install your suggestion. `} ![Diagram: Where each kind sits](https://hivemind.griiken.com/guide/images/plugins-kinds.svg) - **View**: draws the whole workspace, in place of **Canvas** or **Windows**. - **Tiles** inside it: an **agent tile** started from an agent file, a **terminal**, and a **tool tile** drawn by a tool. - Each tile is lent to the view. Switching views keeps it running. - **Widget**: a small card that floats above every view. ## The four kinds [#the-four-kinds] | Kind | What it adds | Its file | |---|---|---| | **Agent** | a coding agent's own program, which Hivemind starts and reads | `agent.yaml` | | **View** | a way of drawing the whole workspace | `hivemind-view.json` | | **Widget** | a small live card on the canvas, in every view | `widget.json` | | **Tool** | a new kind of tile | `hivemind-tool.json` | What each kind can reach, and why a tool you install starts switched off: [Trust, permissions and privacy](https://hivemind.griiken.com/guide/security-and-privacy/). Your agents as stars, grouped by project. Amber ones wait on you. A card that lists the agents waiting on you. A tile that runs your tests several times and shows which fail only sometimes. One `agent.yaml` file tells Hivemind how to start an agent and read its screen. ## Add one [#add-one] Install one from **Settings → Plugins**, on the **HiveHub** tab. What HiveHub lists, how each file is checked, and what you review first: [What HiveHub is](https://hivemind.griiken.com/guide/hivehub/). From a terminal: ```bash hive plugins list # every plugin here, on or off hive plugins install @dip497/worktrees # a tool, widget or view, from HiveHub or a folder hive plugins enable @dip497/worktrees # a tool arrives switched off hive plugins set @you/board columns all # a setting the plugin declares hive agents install claude # agents have their own command ``` Each plugin's page in **Settings → Plugins** has **Settings**, **Read me** and **What it can do**. ## Packages [#packages] Everything you install is a package, and goes in and out as one. A folder that holds one plugin is a package of one. Removing a plugin you installed removes its package. What you set a plugin to stays in your settings, so installing it again finds it. A package's files are copied in and checked before anything you use changes. If an install fails halfway, the version you had stays in use. A package that holds several is a folder with a `hivemind-package.json`. It names a folder for each tool, widget, view and [theme](https://hivemind.griiken.com/guide/packages/#themes), each with its own manifest, and the agent presets it brings: ```json { "apiVersion": 2, "id": "@you/kit", "name": "Kit", "version": "1.0.0", "tools": [{ "path": "tools/prs" }], "widgets": [{ "path": "widgets/dog" }], "views": [{ "path": "views/island" }], "themes": [{ "path": "themes/harbour" }], "agents": [{ "id": "@you/reviewer", "name": "Reviewer", "provider": "claude", "prompt": "Review the diff." }] } ``` Every member's id has the package's owner (`@you/…`). Installing checks each member as its kind is checked, and refuses one whose id another installed package holds. In **Settings → Plugins**, the **Packages** tab lists each package that holds several plugins as one row with one switch. Open it to see its members: what kind each is, whether it is sandboxed or runs in the app, its own switch, and its own page for its settings. Each member is also listed in its kind's tab, marked **Part of** its package. To add one from your computer, choose **Add → Add from a folder**; the review shows what it holds before anything is installed. A plugin that is part of a package changes only with it. Installing it, removing it or switching it on apart from its package is refused, naming the package. You can switch one off on its own, and on again while its package is on. A plugin you installed on its own before is taken over only by a package that lists it in `"replaces": ["@you/name"]`; what you set it to is kept. `hive plugins list` shows which package each plugin belongs to. A package published on HiveHub installs by its id, like a single plugin. Its HiveHub page and the review in **Settings → Plugins** list each member, whether its code is sandboxed or runs in the app, and what it asks for. ### Updates and rollback [#updates-and-rollback] Views, widgets and [live wallpapers](https://hivemind.griiken.com/guide/live-wallpapers/) run in a sandbox that holds them to the permissions they ask for (a live wallpaper asks for none). A theme is data, with no code. Tools run in the app, and an agent preset is instructions an agent follows. So a new package that holds a tool or an agent preset arrives switched off, and one of only views, widgets, themes and live wallpapers arrives on. Installing a newer version of a package keeps its switch, unless something in it needs you to trust it again: a view or widget that asks for a permission it did not have, or a tool or agent preset that is new or changed. Then the package goes off until you switch it on. ```bash hive plugins install ./kit --dry-run # what would change, member by member; installs nothing hive plugins install ./kit # the update, with the same list of changes hive plugins rollback @you/kit # back to the version before, on or off as it was ``` In the app, the same review lists what changed in each member and why the package will switch off, and an opened package has **Roll back to** the version before. The version before the one in use is kept, so a rollback needs no download. Rolling back again returns to the newer one. Settings → Plugins: the Installed and HiveHub tabs, a search box, and the installed agents, views and widgets, each with its count. ## Make one [#make-one] To make your own, use **Add → Make your own…** in the toolbar, or **Add → Make your own** in **Settings → Plugins**. Both write a prompt you hand to a coding agent. From a terminal, start one of any kind: ```bash hive plugins new widget my-widget # or: tool, view ``` Each starter includes `PROMPT.md`: the whole contract for that kind in one file. Write what you want at the top, then hand the file to a coding agent. ## Agents can run a plugin's commands [#agents-can-run-a-plugins-commands] A view, widget or tool can declare `"commands"` in its file and answer them in its code. An agent lists and runs them while the plugin is open: ```bash hive ctl plugin commands hive ctl plugin call @dip497/worktrees list ``` ## What to do next [#what-to-do-next] - [Build a widget](https://hivemind.griiken.com/guide/widgets/), the quickest way to start. - [Write a view](https://hivemind.griiken.com/guide/extension-authoring/) or [Write a tool](https://hivemind.griiken.com/guide/tool-plugins/). - [Add your own agent](https://hivemind.griiken.com/guide/agent-providers/). - [Publish a plugin](https://hivemind.griiken.com/guide/publish-to-hivehub/) on HiveHub, so others can install it. - What a plugin can reach: [Trust, permissions and privacy](https://hivemind.griiken.com/guide/security-and-privacy/). --- # Machines and hosts > How Hivemind runs terminals and agents on another computer: a machine over ssh, or a host over hive-net. Source: https://hivemind.griiken.com/guide/remote-machines/ A frame can sit on another computer. Its terminals and agents then run there, in that computer's own background process, and keep running when you disconnect. There are two ways to reach it. ![Diagram: Two ways to run on another machine](https://hivemind.griiken.com/guide/images/machines-paths.svg) - **Your computer** → **machine**: ssh, with your own `~/.ssh/config` and keys. The app puts its own version of `hive` there and runs `hive daemon bridge`, which joins your own **background process** on that machine. Each person who logs in as the same user has their own. - **Your computer** → **host**: hive-net, directly or through your relay. The host runs `hive host`, whose background process runs the workspace's terminals and agents. - A machine `hive` cannot be put on gets plain ssh terminals, which end when the connection drops. ## Machine or host [#machine-or-host] | | Machine | Host | |---|---|---| | Holds the workspace | no: your computer does | yes, after **Move there** | | Reached by guests and your phone | through your computer | directly, while your computer is off | | Set it up | [Run agents on another computer](https://hivemind.griiken.com/guide/machines/) | [Keep agents running while your laptop sleeps](https://hivemind.griiken.com/guide/host/) | --- # Trust, permissions and privacy > What can reach your files and network, how plugin permissions work, what leaves your computer, and what HiveHub learns. Source: https://hivemind.griiken.com/guide/security-and-privacy/ Hivemind runs on your own computers. This page says what can reach what, and what leaves your machine. {`Review my Hivemind setup for what can touch my files and what leaves this computer, using the "Trust, permissions and privacy" page. Run only read-only commands: \`hive plugins list --json\`, \`hive grant list\`, \`hive network show\` and \`hive config get network\`. Tell me: which tool plugins are switched on (they run with my access), which API tokens exist with their roles and expiry, which network and servers this computer uses, and whether the update check is on. Suggest what to switch off or revoke, but do not change anything.`} ![Diagram: What can reach what](https://hivemind.griiken.com/guide/images/trust-boundary.svg) - **Runs as you**: **agents**, in your terminals, and **tools**, inside the app. They reach your files, programs, logins and network. - **Sandbox**: **views**, in a frame with no Node, and **widgets**, in a worker. No files, no network. They reach **the workspace** only through the permissions they asked for. - **Guests** come in with a [role](https://hivemind.griiken.com/guide/multiplayer/#roles), **your programs** with an [API token](https://hivemind.griiken.com/guide/api-tokens/). A call the role does not allow is refused before it runs. - **Your server** sees only encrypted traffic: see [Encrypted end to end](https://hivemind.griiken.com/guide/how-devices-connect/#encrypted-end-to-end). - **HiveHub** files are checked before they install: see below. ## Permissions [#permissions] - A view or widget lists its permissions in its file. You see them in words, under **What it can do**, before you install it. An unknown one is refused. - Each message it sends is checked against them. With `workspace:prompt`, you also confirm each prompt it writes. - What each permission allows: [Permissions](https://hivemind.griiken.com/guide/extension-authoring/#permissions). What else the sandbox stops: [The sandbox](https://hivemind.griiken.com/guide/extension-authoring/#the-sandbox). ## Sites in a Browser tile [#sites-in-a-browser-tile] A site in a Browser tile asks before it uses your camera, microphone or location, shows notifications, or opens a link in another program (`mailto:`, `zoommtg:`, `slack:`). The question shows over the top of the page and names the site and what it wants, with **Block** and **Allow**. They take a click once the question has been on screen for half a second, so a click meant for the page cannot answer it. Your answer holds for that site until you quit the app. A question you leave for a minute, or whose tab you close, is a no. The **Site permissions** button by the address lists what the site you are on may use: notifications, the camera, the microphone, the location, and anything else you answered. Choose **Allow**, **Block** or **Ask** for each. Allow a site that only checks whether it may and never asks, or take back a **Block**. As in Chrome, a site does not ask to go full screen, copy, hold the pointer or the keys (holding **Esc** gives them back), keep the screen on, or keep its data when the disk runs short. A site never opens a link that runs code or opens files here (`file:`, `javascript:`, `search-ms:`), and never gets your USB, serial or input devices, a speaker or your screen: the app has no chooser for them. A view, or a page a tool shows in its tile, never gets any of these. A tool's own code runs in the app's page and gets what the app uses: notifications and copying. With **Agent browser control** on, an agent drives Browser tiles over the Chrome DevTools Protocol, and through it can give a site any of these without asking you. Switch it on only for agents you trust with your browser. ## Tools start switched off [#tools-start-switched-off] A tool you install starts switched off, and you turn it on yourself. The tools that ship with the app start on. If a tool breaks the app, start it with `HIVEMIND_SAFE_MODE=1 hivemind`: only the tools that ship with the app load. ## What you install from HiveHub [#what-you-install-from-hivehub] HiveHub lists every file of a plugin with its hash, and Hivemind checks each file before it installs: see [Files stay in the author's repository](https://hivemind.griiken.com/guide/hivehub/#files-stay-in-the-authors-repository). - `hive agents install`, from HiveHub or from a repository, prints what the agent runs first. It installs only when you run it again with `--yes`. - When you install from HiveHub, the app sends one request to count the install. It carries no id, no machine name and no headers of its own. HiveHub counts the same plugin from one address once a day. - A plugin installed from a folder is never counted. ## What leaves your computer [#what-leaves-your-computer] | What | Where to | Turn it off | |---|---|---| | The update check | GitHub, for new versions of the app | **Settings → About and updates → Check for new versions** | | The plugin list | HiveHub, for new versions of the agents it adds for you | The same switch. You still reach HiveHub when you browse plugins yourself. | | Traffic to your other devices and guests | Directly, or through the relay of your own [network server](https://hivemind.griiken.com/guide/self-hosting/) | Stay on *Local network* in **Settings → Servers** | With the update check off, the app reaches nothing your network does not name, until you browse plugins yourself. Your agents' own programs talk to their providers as they always do. ## Before you let someone in [#before-you-let-someone-in] Both screens show three words. If they differ, someone sits between you: press **Deny**. An invite link gives at most `terminals`. How: [Share a workspace](https://hivemind.griiken.com/guide/multiplayer/). ## Related [#related] - [Devices and hive-net](https://hivemind.griiken.com/guide/how-devices-connect/) - [Make an API token](https://hivemind.griiken.com/guide/api-tokens/) - [Open the app in a browser tab](https://hivemind.griiken.com/guide/browser-tab/): anyone with its link can use your terminals. - [Plugins](https://hivemind.griiken.com/guide/plugins/) --- # The view protocol > How a view talks to the app: one message port, a hello that says what it may do, and nothing else. Source: https://hivemind.griiken.com/guide/view-protocol/ A view is a web page that draws your workspace. It runs sandboxed and knows only what the app tells it over one message port. Your agents can open a view, and send it data, while they work. ![Diagram: An agent opens a view](https://hivemind.griiken.com/guide/images/view-open.svg) 1. **Agent** → **main process**: `hive ctl plugin open view:` calls `plugin.open` on the drive socket. 2. Main process → **window**: show that view. The agent gets its answer once the window has it. 3. Window → **view**: load its page from `hm-view://`, in a sandboxed frame. Then hand it a message port. 4. View → window: `ready`, with the protocol version it speaks. 5. Window → view: `hello`, with what its permissions let it do. Then the workspace: `structure`, `status` and more. 6. View → window: a `command`, checked against its permissions before it runs. ## Versions [#versions] A view says `"protocol": 1` in `hivemind-view.json`. Newer additions to version 1 are features: `hello` lists the ones this app has, and a view checks with `hm.supports("")` before using one. ## Widgets speak it too [#widgets-speak-it-too] A widget's code runs in a worker, and reaches the workspace through the same client, limited to the permissions in its `widget.json`. Tools do not: they run inside the app. See [Trust, permissions and privacy](https://hivemind.griiken.com/guide/security-and-privacy/). Every call a view can make, and how a script sends it data: [View reference](https://hivemind.griiken.com/guide/extension-authoring/#view-reference). --- # Workspaces, frames and tiles > How Hivemind arranges a project: a workspace holds frames, each frame is bound to one folder, and every tile in it runs there. Source: https://hivemind.griiken.com/guide/workspaces/ A workspace is one project folder and everything open for it: the place your agents work, and the place they arrange as they go. {` Explain my open Hivemind workspace to me. Do not change anything. 1. Run \`hive ctl frames --json\` and \`hive ctl agents --json\`. If either exits 3, tell me Hivemind is not open on this project and stop. 2. For each frame, tell me its name, the folder it is bound to, and whether that folder is the project, a git worktree (check with \`git worktree list\`) or a folder on another machine. 3. For each agent, tell me which frame it is in and what it is doing or waiting on. 4. Point out any frame with no agent, and any agent that waits on me. `} The Layers panel lists projects such as fastapi and excalidraw, each with its agents as rows, some marked needs you. Beside it, the canvas shows one agent's terminal writing router tests. ## How it works [#how-it-works] ![Diagram: A workspace, its frames and their tiles](https://hivemind.griiken.com/guide/images/workspace-nesting.svg) - **Workspace**: one project folder. It holds frames, each bound to one folder. - **Frame on the project folder**: its tiles run in that folder. The default. - **Frame on a git worktree**: its tiles run on that branch, nested under the project. See [Work in a git worktree](https://hivemind.griiken.com/guide/git-worktree/). - **Frame on a machine**: its tiles run on another computer. See [Machines and hosts](https://hivemind.griiken.com/guide/remote-machines/). - **Tiles**: an agent, a terminal, the Code tile, a browser or a tool. Each starts in its frame's folder. A frame's ⋯ menu also arranges its tiles (**Arrange**), starts an agent in it, and adds a tool or widget. Deleting a frame that holds tiles asks whether to **Keep them** or close them with it. ### The Layers panel [#the-layers-panel] The Layers panel lists everything open. Its rail picks what it shows: | Pane | Lists | |---|---| | **Tiles** | **Pinned**, then each project with its worktrees and tiles. Agents a tile started fold under it. | | **Recents** | past agent sessions, newest first. One click resumes one. | | **Machines** | this computer and every machine you added, with how many agents there need you. | Its title menu switches workspace, opens a folder, joins a shared workspace and switches views. Its bell jumps to the next agent that needs you. A row's ⋮ menu pins, renames, closes, snoozes or puts an agent to sleep. Its keys are on [Keyboard shortcuts](https://hivemind.griiken.com/guide/keyboard-shortcuts/). The **View** menu over the tiles filters, groups and sorts them. Your pins, snoozes and what you have read are yours alone, on this computer, even in a shared workspace. ### What is kept [#what-is-kept] Closing the window stops nothing: see [What is kept](https://hivemind.griiken.com/guide/background-process/#what-is-kept). Frames, tile positions, the viewport and open files are saved per project on this computer, not in the repository: see [Data and where it is stored](https://hivemind.griiken.com/guide/data-and-storage/). ## Why it works this way [#why-it-works-this-way] A frame binds a folder so that a tile never asks where to start. You choose the place once, on the frame, and every tile follows it. ## What to do with it [#what-to-do-with-it] - [Work in a git worktree](https://hivemind.griiken.com/guide/git-worktree/) - [Run many agents at once](https://hivemind.griiken.com/guide/run-many-agents/) - [Switch views](https://hivemind.griiken.com/guide/views/) - [Run agents on another computer](https://hivemind.griiken.com/guide/machines/) --- # Add your own agent > Teach Hivemind a coding agent it does not know yet, with one agent.yaml file: how to start it, read its screen and answer it. Source: https://hivemind.griiken.com/guide/agent-providers/ Add an agent when you use a coding agent's program that HiveHub does not list yet. You write one file, `agent.yaml`. No code and no rebuild. {` Write a Hivemind agent file (\`agent.yaml\`) for a coding-agent program on this computer, check it against the real program, and, if I want, offer it to everyone. 1. Probe the real program first. Never guess one agent from another. Ask me which program it is. Find it with \`command -v\`, then run its \`--version\` and \`--help\`, and \`--help\` on its main subcommand. Read its own docs too. For each of these, write down the answer and the line or page that says so, or "could not find it": - how a task is passed: as an argument, or typed into its screen; - whether it has hooks that run when it finishes replying, or before a tool runs, and whether a hook can block; - where it keeps sessions, and how to resume one; - what its screen shows while it works, when it asks permission, and when it asks a question; - which keys allow, deny, or pick an option on those screens. 2. Write \`~/.config/hivemind/agents//agent.yaml\` from the "agent.yaml reference" page: \`manifestVersion: 2\`, an \`id\` equal to the folder name, \`bin\` as the bare program name (never a path), and every field under \`caps\`. Claim a capability only if step 1 proved it. \`turnSignal: true\` and \`supervise: broker\` need \`launch.hcp\` and a hook file beside the manifest. \`resume\` other than \`none\` needs \`session.resume\`. Regular expressions are not allowed in \`detect.rules\`. 3. Check it: \`hive agents validate \`, until it passes. Then \`hive agents install \`, and check \`hive agents list\` shows it with no problem. 4. If Hivemind is open, try it: \`hive ctl spawn --agent --prompt "list the files here"\`. Watch \`hive ctl agents\`: it must read working while the agent works, and waiting when it asks permission. \`hive ctl stream --snapshot\` shows its screen. If you set answer keys, check each with \`hive ctl keys\` on a real question. 5. Offer it to everyone only if I say so. New agents are listed by pull request to the GitHub repository dip497/hivemind-plugins, in \`agents//\` with a \`README.md\`. Use my GitHub account through \`gh\`; if \`gh\` is not signed in, ask me to sign in myself. At the end, show me the file. Say which capabilities you proved and from where, which you left off and why, and the pull request link if you opened one. `} ## Before you start [#before-you-start] - Hivemind is installed. See [Install and run your first agent](https://hivemind.griiken.com/guide/getting-started/). - The agent's own program is installed and on your `PATH`. - You have read its `--help`. Everything you claim in the file must come from the real program. An agent file starts a program in your terminal, with your permissions. There is no sandbox. Before you install someone else's, read its `bin` and `spawn`, and install only agents whose author you trust. ## Write the file [#write-the-file] Run ` --help` and read its docs. Write down how it takes a task, whether it has hooks, and where it keeps sessions. Then note what its screen shows while it works and while it waits on you. Check: you have an answer, with a source, for each. "Could not find it" is an answer. The folder name is the agent's id: ```bash mkdir -p ~/.config/hivemind/agents/acme ``` Start small. Claim only what you proved in step 1: ```yaml ~/.config/hivemind/agents/acme/agent.yaml manifestVersion: 2 id: acme label: Acme Coder bin: acme-coder # the program's name on your PATH, never a path enabled: true caps: promptDelivery: typed # typed into its screen; argv if it takes the task as an argument turnSignal: false # true only with launch.hcp and a hook file resume: none supervise: human # it has its own permission questions blockedDetection: true detect: default: idle rules: - when: { contains: "approve this?" } then: blocked - when: { line: [{ gerundAfterPrefix: ["braille"] }] } # "⠋ Reading files…" then: working ``` Every field is described in the [agent.yaml reference](https://hivemind.griiken.com/guide/agent-yaml/). ```bash hive agents validate ~/.config/hivemind/agents/acme ``` Check: it passes. If not, it names each field it refuses. Fix them and run it again. ```bash hive agents install ~/.config/hivemind/agents/acme ``` Check: `hive agents list` shows `acme`, on, with no problem. ## Check it worked [#check-it-worked] 1. Start it in the open app: ```bash hive ctl spawn --agent acme --prompt "list the files here" ``` 2. Watch its tile. While it works, the tile shows **working**. 3. Give it a task that needs permission, such as editing a file. Check: its tile turns amber and shows **needs you**, and the bell in the Layers panel counts it. `hive ctl agents` shows the same status. ## If it didn't [#if-it-didnt] | You see | Do this | |---|---| | `hive agents validate` refuses a capability | You claimed something that needs wiring. Add the block it names, or set the claim to `false` / `none`. | | The tile stays **idle** while the agent works | Add a `detect` rule for what its screen shows while it works. Capture the real screen with `hive ctl stream --snapshot`. | | A permission question reads as finished, not **needs you** | Add a `blocked` rule for that screen, and set `blockedDetection: true`. | | Something else | [Troubleshooting](https://hivemind.griiken.com/guide/troubleshooting/) | ## Where agent files live [#where-agent-files-live] | Folder | Used for | |---|---| | `~/.config/hivemind/agents//agent.yaml` | your agents, in every workspace | | `/.hivemind/agents//agent.yaml` | agents a repository ships for everyone who opens it | A repository can only add agents. It can never change what an id you already have runs. ```bash hive agents list # every agent, where it came from, and why any is unavailable hive agents remove acme ``` ## Share it [#share-it] Agents are listed on HiveHub by pull request: see [Publish an agent](https://hivemind.griiken.com/guide/publish-to-hivehub/#publish-an-agent). Once it is merged, `hive agents install acme` works for everyone. ## Related [#related] - [agent.yaml reference](https://hivemind.griiken.com/guide/agent-yaml/): every field. - [Run agents](https://hivemind.griiken.com/guide/agents/): install, start and put agents to sleep. - [Plugins](https://hivemind.griiken.com/guide/plugins/): the other kinds of plugin. --- # Write a view > Build your own way of drawing the workspace: a small web page that lists, groups or charts your agents. Source: https://hivemind.griiken.com/guide/extension-authoring/ Build a view that lists every tile with a dot for its status, then change it. It takes about fifteen minutes. {` Build a Hivemind view (a sandboxed web page that draws the whole workspace its own way) and, if I want, publish it on HiveHub. 1. Ask me what the view should show and do, and its name (lowercase letters, digits and dashes). 2. Start it: \`hive plugins new view \`. It takes the owner from the GitHub account \`gh\` is signed in as. If \`gh\` is not signed in, ask me for my GitHub login and pass \`--owner \`. Then run \`npm install\` in the new folder (it needs Node). 3. Read \`PROMPT.md\` in full: it is the whole contract (the SDK, permissions, the sandbox). Write what I asked for under its "What I want", and build only from it. The view has no network, reads only its own files and has no \`window.hive\`. It uses \`@hivemind/view-sdk\`, which the app serves, so do not bundle it. 4. Check it, then build and install it, again after each change: \`hive plugins check .\` must say ok (it names the file and line of each problem), then \`npm run dev\`. Check it prints "installed @owner/name". 5. Show it: \`hive ctl plugin open view:@owner/name\`. If \`hive plugins list\` shows it off, run \`hive plugins enable view:@owner/name\` first. 6. Declare one command in \`hivemind-view.json\` under "commands", answered with \`hm.onCommand\`, that reports what the view shows. Check it with \`hive ctl plugin call @owner/name \`. 7. Done means: \`hive plugins list\` shows it on with no problem, it follows the light and the dark theme (\`applyThemeVars\`), the manifest has a one-line description, a "category" and only the permissions it uses, and \`README.md\` says what it does. 8. Publish only if I say so. Commit \`dist/\` with the source, because HiveHub publishes the pushed commit. Follow the "Publish a plugin" page (https://hivemind.griiken.com/guide/publish-to-hivehub.md) and run \`hivehub publish dist\`. If I must sign in, ask me to open the link and type the code myself. At the end, tell me the view's id, the command others use to install it (\`hive plugins install @owner/name\`), and anything you could not check. `} ## Views others have built [#views-others-have-built] Each is on HiveHub as `@dip497/`. Your agents as stars, grouped by project. Today's work, one row per agent. A board with one column per state. Frames, worktrees, agents and issues on one map. ## What you'll learn [#what-youll-learn] - How to start a view from the starter and switch the window to it. - How a view hears the workspace change and shows each agent's status. - How to rebuild it and see the change. ## Before you start [#before-you-start] - Hivemind is installed and open on a project with a few tiles. See [Install and run your first agent](https://hivemind.griiken.com/guide/getting-started/). - Node 22 or newer, for `npm`. - You know a little TypeScript or JavaScript. ```bash hive plugins new view pulse ``` Check: it prints `created @/pulse`. If it asks for an owner, add `--owner `. ```text pulse/ hivemind-view.json the view's name, id, version and permissions index.html the page, which loads ./main.js src/main.ts your code PROMPT.md the whole contract, for a coding agent dist/ what you install and publish, once built ``` ```bash cd pulse && npm install npm run dev ``` Check: the last line says `installed @/pulse`. `npm run dev` builds `dist/` and installs it in one go. Open the view menu in the toolbar (it shows **Canvas**) and pick **Pulse**. Check: the window shows **Pulse** and one row per tile, each with a dot for its status. Press a row and Hivemind selects that tile. `src/main.ts` connects, follows your theme, and redraws when tiles change: ```ts src/main.ts import { applyThemeVars, connect, statusTone } from "@hivemind/view-sdk"; const hm = await connect(); applyThemeVars(hm); const list = document.querySelector("ul")!; let unsubscribe: (() => void)[] = []; hm.on("structure", ({ tiles }) => { for (const off of unsubscribe) off(); list.replaceChildren(); unsubscribe = tiles.map((tile) => { const dot = Object.assign(document.createElement("span"), { className: "dot" }); const button = document.createElement("button"); button.append(dot, tile.name); button.onclick = () => hm.commands.selectTile(tile.id); const item = document.createElement("li"); item.append(button); list.append(item); return hm.subscribeStatus(tile.id, (s) => { dot.dataset.tone = statusTone(s); }); }); }); ``` `structure` comes again whenever frames or tiles change. The app serves `@hivemind/view-sdk` to every view, so your bundle leaves it out. To draw a state the way the app does, a shape per state in its colour (only "needs you" pulses), put `statusMarkSvg(statusTone(s))` in the row instead of the dot; `STATUS_MARKS` holds each state's word and shape. Add this line inside the `structure` handler, after `list.replaceChildren();`: ```ts document.querySelector("h1")!.textContent = `${tiles.length} tiles`; ``` Run `npm run dev` again. Check: the heading now counts your tiles. Open a terminal and the count goes up. ## What you did [#what-you-did] - You started a view with `hive plugins new view` and installed it with `npm run dev`. - You switched the window to it from the toolbar's view menu. - You read the workspace with `hm.on("structure")` and each agent's status with `hm.subscribeStatus`. ## Next [#next] - Want an agent to build the rest? Write your idea at the top of `PROMPT.md` and hand it the file. - Share it: [Publish a plugin](https://hivemind.griiken.com/guide/publish-to-hivehub/) on HiveHub. - Ship it with your other tools, widgets and views as one: [Packages](https://hivemind.griiken.com/guide/packages/). - A real example with a saved layout and agent commands: [`views/agent-board`](https://github.com/dip497/hivemind-plugins/tree/main/views/agent-board). - Something wrong? See [Troubleshooting](https://hivemind.griiken.com/guide/troubleshooting/). ## View reference [#view-reference] ### What a view can use [#what-a-view-can-use] Check `hm.supports("")` before using a newer feature. | Need | Call | |---|---| | Put live terminals in your layout | `hm.setSurfaceRects(...)` (`surfaces`) | | Show what a tile last said, or what its agent waits on, with Review | `hm.setLineRects([{ tileId, x, y, w, h }])` (`lineSlots`): the app draws it in the room you leave, at least 20px high, and its own **Review** for a permission (never Allow in your room); your view never gets the text | | Save your layout (64 KB, per workspace) | `hm.setLayout(blob)` | | An agent's status as it changes | `hm.subscribeStatus(tileId, (status, info) => …)` | | Show a tile when someone asks to see it: a widget's button, a notification's **View**, `hive ctl focus` | `hm.onReveal((tileId) => …)`: move your camera to it and answer where it is drawn (`{ x, y, w, h }`), or `null` for a tile you do not draw | | What happens: replies, waits, closes | `hm.onEvents(["turn", "needsInput"], cb)` | | How busy a terminal is (0 to 3) | `hm.activity(tileId, cb)` | | A day's history per tile | `await hm.history("2026-09-23")` | | Installed agents, past sessions | `await hm.agents()`, `await hm.sessions("claude", frameId)` | | Start an agent | `hm.commands.spawnAgent(agent, frameId, { prompt, resume })` | | Suggest a prompt (the person confirms) | `await hm.prompt(tileId, "run the tests")` | | Who else is here | `hm.onParticipants(cb)` (`participants`) | | The canvas's widgets | `hm.onWidgets(cb)`, `hm.pressWidget(id, action)` (`widgets`) | | Keep clear of the widget cards over your view | `hm.onWidgetBand(({ edge, width }) => …)` (`widgetBand`): how far the cards reach in from your widget edge, the gap beside them included, or 0 when there are none. It comes at once, then each time cards come or go, start a second column, or the window is resized | | Issues | `hm.onIssues(cb)`, `hm.issues.read(id)`, `create`, `update`, … (`issues`) | | Its settings | `hm.settings`, `hm.on("settings", cb)` (`settings`) | | Draw your own toolbar | `"toolbar": "off"`, then `hm.commands.openHostMenu("views", rect)`, `"add"`, `"appearance"` or `"settings"` opens the app's own (`hostMenu`) | | Messages from your scripts | `hm.onCustom("ci.*", cb)`, sent by `hive ctl view emit ci.build '{…}'` | Each tile in `structure` carries its `icon` (an SVG in `currentColor`) and its `agent`. Each frame carries its `folder`, `branch`, `parentId` (a worktree under its project) and `machine` when it runs on another computer. A view never reads an agent's replies or terminal text, and never answers its permission questions. Every prompt a view writes opens a dialog showing the full text, with **Cancel** focused. ### Colours [#colours] `applyThemeVars(hm)` sets the app's theme on your page as CSS variables, and again each time it changes. 15 colours come from the app and the phone page, each as `--hm-color-`; what each is for is in [the app's colours](https://hivemind.griiken.com/guide/plugin-settings/#the-apps-colours). A release that removes or renames one says so with **Breaking:** in the CHANGELOG. A colour added later reaches only newer apps, so give it a fallback: `var(--hm-color-new, #888)`. ### Permissions [#permissions] A view declares its permissions in `hivemind-view.json`. An unknown one is refused at install. Selection and focus need none. | Permission | Allows | |---|---| | `workspace:spawn` | start tiles, agents and frames | | `workspace:close` | close tiles | | `workspace:edit` | rename tiles, pick a frame's folder | | `workspace:prompt` | `prompt`, and `spawnAgent` with a prompt | | `workspace:sessions` | `sessions`, and `spawnAgent` with `resume` | | `workspace:widgets` | press and click widgets | | `workspace:issues` | read and change issues | ### Manifest fields [#manifest-fields] | Field | Does | |---|---| | `id`, `name`, `version` | its id in your GitHub scope (`@you/name`), its name, its version | | `"description"` | one line under its name wherever views are listed, at most 200 characters | | `"icon"` | an `.svg` in the view's folder (`"icon.svg"`), drawn in one colour like the app's icons, at most 32 KB | | `entry` | the page to load, usually `index.html` | | `protocol` | the view protocol it speaks: `1` | | `permissions` | what it may do (above) | | `"settings"` | fields the app draws on the view's Settings page: see [Plugin settings](https://hivemind.griiken.com/guide/plugin-settings/) | | `"tokens"` | colours of its own that follow the theme and the person can change: see [A view's own colours](https://hivemind.griiken.com/guide/plugin-settings/#a-views-own-colours) | | `"files"` | `true` when it `fetch`es its own files; without it every `fetch` is refused | | `"commands"` | what an agent can run in it (`hm.onCommand(name, handler)`), optionally with `"keys": "mod+alt+k"` | | `"toolbar"` | `"top"`, `"bottom"` (the default), `"hidden"` or `"off"` | | `"widgets": "left"` | start widget cards down the left edge over the view instead of the right, for a view that keeps its own panels on the right; a card the person moved stays put. `hm.onWidgetBand` says how much room they take | | `"layout": "personal"` | keep the layout per person instead of shared | | `"layers": true` | show the app's Layers panel beside the view | | `"phone": true` | offer it on the phone page; use `hm.device.compact` and `hm.device.touch` | | `"category"` | where it is grouped in the Add menu and on HiveHub | | `"description"` | what it shows, in one line: the line on its card on HiveHub | ### The sandbox [#the-sandbox] The page runs on its own `hm-view://` origin with a strict content policy: no `window.hive`, no Node, no network, no inline scripts, and no notifications, camera, microphone or location. It loads its scripts, styles, pictures and fonts from its own files only, and may `fetch` them when its `hivemind-view.json` says `"files": true`: `fetch("./levels.json")` works, and another view's files or any other address are refused. Malformed messages, floods or runaway CPU switch it off for the session and return you to the canvas. - Name your files relatively (`./main.js`, `fetch("./data.json")`): in a browser tab the app serves views under a path. - Fetching its own files needs Hivemind 2026.10.6 or newer, and works in the app and a browser tab. Check `hm.supports("ownFiles")` before you fetch: on the phone page, and in a window that shows another computer's view, it is refused, so bundle what those must show. - Draw on change, and stop work while `document.hidden`. - A form's `submit` event fires, in the app and on the phone page, and the form goes nowhere: handle the event and call `preventDefault()`. - Test without the app with `fakeHost()` from `@hivemind/view-sdk/testing`. ### Commands [#commands] ```bash hive plugins new view [--dir folder] # a starter, with PROMPT.md hive plugins check # its types, its manifest, and its page built and loaded once, with file:line hive plugins install |@owner/name hive plugins list --kind view # installed views, and why any fails to load hive plugins remove ``` --- # Make a live wallpaper > A scene behind your canvas whose creatures are your agents: build one, ship it in a package, publish it. Source: https://hivemind.griiken.com/guide/live-wallpapers/ Make a scene of your own that runs behind your canvas, with one creature for each of your agents, as Shoal's sharks are. You or your coding agent can take it from an idea to HiveHub with the `hive` command. {` Build a Hivemind live wallpaper (a scene drawn behind the canvas in a sandboxed frame, one creature for each of my agents) and, if I want, publish it on HiveHub. 1. Ask me what the scene is: its world, what an agent's creature is, and what a creature does while its agent works, is ready, needs me, and rests. Ask its name (lowercase letters, digits and dashes). 2. Start it: \`hive plugins new wallpaper \`. It writes a package of that name holding the wallpaper in \`wallpapers/\`, with \`startup.wallpaper\` set. It takes the owner from the GitHub account \`gh\` is signed in as. If \`gh\` is not signed in, ask me for my GitHub login and pass \`--owner \`. To add the wallpaper to a package I already have, pass \`--in \` instead. 3. Read \`PROMPT.md\` in full, and the two skills it copied into the package's \`.claude/skills/\`: hivemind-live-wallpaper (the contract) and ascii-character-animation (the craft). Write the scene in \`src/main.ts\` from them. The wallpaper has no network and no permissions. It is told each agent's creature (never a name), where the tiles are, the colours, whether to run, and the pointer and clicks over empty canvas. 4. Where the starter's \`package.json\` is, run \`npm install\` once, then \`npm run build\` after each change, then \`hive plugins check \`. It must say ok. It names the file and line of each problem, and loads the wallpaper in a headless browser to check it says ready and drawn and names only creatures it was sent. 5. Install it: \`hive plugins install \`. Ask me before changing my background. On a yes, run the command the install prints for it (\`--json\` gives it as startWallpaper), or \`hive config set appearance.wallpaper.kind '""'\`. Its id is \`@owner/package/\`. 6. Done means: it draws in my theme's two colours, light and dark; its creatures keep off my tiles; the creature of an agent that needs me goes to the open side of that agent's tile; it draws nothing on its own while held and one settled frame while still; and \`README.md\` says what it is. 7. Publish only if I say so. Commit the package with the wallpaper's \`dist/\`, push it to GitHub, and run \`hivehub publish \`, as https://hivemind.griiken.com/guide/publish-to-hivehub.md says. If I must sign in, ask me to open the link and type the code myself. At the end, tell me the wallpaper's id, the command others use to install it (\`hive plugins install @owner/package\`), and anything you could not check. `} ## What a live wallpaper is [#what-a-live-wallpaper-is] A live wallpaper is a small web page that the app runs behind the canvas, in a sandboxed frame, as it runs a [view](https://hivemind.griiken.com/guide/extension-authoring/). Shoal, Koi Pond, Jellyfish and Fireflies are the ones that come with the app ([how to pick one](https://hivemind.griiken.com/guide/appearance/)). Yours ships in a [package](https://hivemind.griiken.com/guide/packages/), and its id is `@owner/package/`. What it is told is less than a view is: - Each agent's creature: an id that means nothing outside the scene, the program (`claude`, `codex` …), a `kind` from 0 to 1 that is the same for every agent of one program, a `size`, and what the agent is doing: `working`, `ready`, `needs-you` or `resting`. - Where the tiles are on the screen, and whether they are see-through. - The colours to draw in, and whether to run, keep its last frame or show one settled frame. - The pointer and clicks over empty canvas, and a turn an agent finished well. It is never told an agent's name, a folder, a command, a tile's own id or anything a terminal shows. It loads and fetches nothing from the network, has no permissions, never has the keyboard, and cannot change the workspace. The two things it says back are that its first frame is up, and which creature is under the pointer. While the pointer is over empty canvas, the app shows that agent's name and state beside the pointer, and a click there goes to the agent's tile. Like a view, its frame can still open a WebRTC connection, which no page policy in Chromium stops, and so could send what it is told elsewhere. Install live wallpapers, like views, from people you trust. It is not drawn behind a view you installed, which lays its tiles out itself, nor on the [phone page](https://hivemind.griiken.com/guide/phone/). ## Before you start [#before-you-start] - Hivemind 2026.10.8 or newer, open on a project with a few agents. - Node 22 or newer, for `npm`. - You know a little TypeScript or JavaScript, or your coding agent does. ```bash hive plugins new wallpaper pond ``` It writes the package `pond/`. Its `hivemind-package.json` names the wallpaper in `wallpapers/pond` and offers it as the background once it is installed (`startup.wallpaper`). The wallpaper's folder holds its `hivemind-wallpaper.json` and a working scene in `src/main.ts`. A `PROMPT.md` and two skills in the package's `.claude/skills/`, one for the contract and one for drawing in characters, are there for your coding agent. The owner is the GitHub login `gh` is signed in as, or the one you pass with `--owner`. To add a wallpaper to a package you have, run `hive plugins new wallpaper pond --in kit`. Check: `hivemind-package.json` has `"startup": { "wallpaper": "@/pond/pond" }`. The starter draws a working scene. The smallest one that runs on the app's clock looks like this: ```ts src/main.ts import { connectWallpaper } from "@hivemind/view-sdk"; const wp = await connectWallpaper(); const canvas = document.body.appendChild(document.createElement("canvas")); Object.assign(canvas.style, { position: "fixed", inset: "0" }); const g = canvas.getContext("2d")!; const at = new Map(); // Sharp on any screen: the canvas is the viewport times its pixel ratio. wp.on("viewport", ({ w, h, dpr }) => { canvas.width = Math.round(w * dpr); canvas.height = Math.round(h * dpr); Object.assign(canvas.style, { width: `${w}px`, height: `${h}px` }); }); // An agent that closed: its creature goes. wp.on("creatures", (cs) => { for (const id of at.keys()) if (!cs.some((c) => c.id === id)) at.delete(id); }); // Which creature is at a point: the app shows its agent's name, and a click opens its tile. wp.hitTest((x, y) => { for (const [id, p] of at) if (Math.hypot(p.x - x, p.y - y) < 12) return id; return null; }); wp.animate({ step(dt) { const { w, h } = wp.viewport; for (const c of wp.creatures) { const p = at.get(c.id) ?? { x: Math.random() * w, y: Math.random() * h }; p.x = (p.x + (c.state === "working" ? 60 : 15) * dt) % w; at.set(c.id, p); } }, draw() { const { w, h, dpr } = wp.viewport; const { page, text, attention, mono } = wp.look; g.setTransform(dpr, 0, 0, dpr, 0, 0); g.fillStyle = page; g.fillRect(0, 0, w, h); g.font = `16px ${mono}, monospace`; for (const c of wp.creatures) { const p = at.get(c.id); if (!p) continue; g.fillStyle = c.state === "needs-you" ? attention : text; g.fillText("@", p.x, p.y); } }, }); ``` This one does not yet keep off the tiles or go to its agent's tile; the sections below say how. To have your coding agent write it, put your idea at the top of `PROMPT.md` and hand it the file. Where the starter's `package.json` is, run `npm install` once. Then, after each change: ```bash npm run build # writes dist/main.js, the entry its manifest names hive plugins check pond ``` The check reads the package and every member as the install and HiveHub do, with the file and line of each problem. It also loads the wallpaper in a headless browser against a pretend app, and checks that it says it is ready, draws its first frame, and names only creatures it was sent. Check: it ends with `ok`. `--json` gives the same report to an agent. ```bash hive plugins install ./pond ``` A package of live wallpapers, views, widgets and themes holds no code that runs outside a sandbox, so it arrives switched on. Because the package names its wallpaper in `startup.wallpaper`, the app offers it as your background once, and never switches without you. The install prints the command that switches to it; `--json` gives it as `startWallpaper`. To switch yourself: ```bash hive config set appearance.wallpaper.kind '"@/pond/pond"' ``` Or open **Settings → Appearance** and pick it under **Background**, after the built-in scenes. Install again after each change. Check: your agents swim behind the canvas. Point at one and its agent's name shows. Commit the package with the wallpaper's `dist/`, push it to GitHub, and run `hivehub publish pond`. A package publishes as one listing: see [Publish a plugin](https://hivemind.griiken.com/guide/publish-to-hivehub/#publish-a-package). HiveHub lists a package that holds a live wallpaper as needing Hivemind 2026.10.8 or newer. ## What it is told, and what it says [#what-it-is-told-and-what-it-says] The app and the wallpaper talk over one message port. Every message is a JSON object with a `type`, checked on both sides. `@hivemind/view-sdk` speaks it for you: `connectWallpaper()` waits for the app and gives you the values and their changes as `wp.on(…)`. | The app sends | Holds | When | |---|---|---| | `hello` | everything below, at once | once, after it says `ready` | | `viewport` | `{ w, h, dpr }`: its size in CSS pixels, and the screen's pixel ratio | the window is resized or moves to another screen | | `look` | `{ page, text, attention, dark, colour, mono }`: the theme's page, text and needs-you colours as `#rrggbb`, whether the theme is dark, whether to draw in its own colours, and the terminals' font as a CSS font list | the look changes | | `mode` | `run`, `hold` or `still` | see [the clock](#the-clock) | | `creatures` | up to 8 of `{ id, agent, kind, size, state }` | an agent comes, goes or changes state | | `tiles` | `{ tiles, seeThrough }`: each tile, and each panel that is not glass, as `{ x0, y0, x1, y1, id? }` in CSS pixels; `id` is the creature's id on its agent's tile | once a second while it runs, and at most once a frame while the canvas moves | | `done` | `{ id }`: that creature's agent finished a turn well | a turn ends well | | `pointer` | `{ x, y, over }`: the pointer over empty canvas, or gone from it | at most once a frame while it moves there | | `click` | `{ x, y, id }`: a click on empty canvas, and the creature it opened, or `null` for open water | a click | | It sends | Holds | The SDK sends it | |---|---|---| | `ready` | `{ protocol: 1 }` | in `connectWallpaper()` | | `drawn` | nothing: the first frame is up, and the app shows the layer | after the first frame of `animate`, or with `wp.drawn()` | | `hover` | `{ id }`, the creature under the pointer, or `null` | when what `hitTest` answers changes | A creature's `size` is the same for its agent every time, from about 0.78 to 1. Pick what kind of creature it is from `kind`, so all of one program's agents look alike. ## The clock [#the-clock] `wp.animate({ step, draw, settle })` runs your scene on the clock the built-in scenes use: - `step(dt)` moves the scene on by 1/60 of a second, as many times as the time that passed needs (at most four a frame; a busy computer drops the rest). The scene moves at the same speed whatever the frame rate. - `draw(dt)` draws it as it is, at most 30 times a second. Characters read smooth at 30, and it costs half of 60. `animate(scene, { fps: 60 })` asks for more. - `settle()`, if you give it, puts everything where it would be after a while. Without it, the clock runs 360 steps. The mode decides what runs: | Mode | When | What the clock does | |---|---|---| | `run` | the window is in use | steps and draws | | `hold` | the window is hidden, unfocused, idle or covered | nothing. It draws one frame again only when something it shows changes: the size, the look, the creatures or the tiles | | `still` | the person turned off **Animate the background**, or the computer asks for reduced motion | one settled frame: `settle()` and one draw. Again only when something it shows changes | Its first frame is drawn at once, whatever the mode. Never start a timer or a `requestAnimationFrame` loop of your own: while held, a wallpaper that keeps drawing spends the battery on a window nobody sees. ## Keep off the tiles [#keep-off-the-tiles] Your agents' tiles sit over the scene, and their text must stay readable. Use `tiles`: - Pick where a creature goes in the open water between the tiles, and a way there that does not pass under one. - Turn a creature away before it goes under a tile. One a tile was put down over goes out by the nearest side, quickly. - Draw nothing of a creature under a tile. When `seeThrough` is true the tiles are frosted glass, and a creature under one may show through, soft and faint. When an agent needs you, its creature goes to that agent's tile: the tile in `tiles` whose `id` is the creature's. It holds by the open side, the side with more room clear of the other tiles, else the other side, else above or below. When the tile is not on the screen, the creature stays in the open water. ## Hover and click [#hover-and-click] `wp.hitTest((x, y) => id)` answers which creature is at a point of the viewport, or `null`. While the pointer is over empty canvas, the app shows that creature's agent's name and state beside it, and a click there goes to the agent's tile. The wallpaper never learns the name, and the app takes `hover` only for a creature it sent. Every click on empty canvas comes as `click`. Its `id` is the creature the app opened, or `null` for open water: answer a click on open water in your scene, with a ripple or a scatter. The built-in scenes answer the pointer the same way. ## Colours [#colours] - **Your theme's colours.** By default draw in `page` and `text` and the steps between them, so the scene follows every theme. `dark` says which way round: light creatures on a dark page, or ink on paper on a light one. Keep `attention`, the theme's colour for an agent that needs you, for that alone. - **Its own colours.** With `"colour": true` in its manifest, Settings shows the **Colour** switch for it, and `look.colour` says when the person turned it on. Then draw in your scene's own colours: one set for a dark theme and one for a light one. - **Characters.** `mono` is the terminals' font, as a CSS font list. It is the person's choice and may not be on this computer, so end it with a fallback: `` `${mono}, monospace` ``. - **Panel text over it.** With glass on, the Layers panel and the toolbars are frosted glass, and their text sits over your scene. Keep the scene dark enough on a dark theme, and light enough on a light one, that the text reads over every part of it. Test it: the built-in scenes keep the Layers panel's text at 7:1 and its secondary text at 4.5:1 over every point of their water. ## hivemind-wallpaper.json [#hivemind-wallpaperjson] | Field | Needed | Takes | |---|---|---| | `protocol` | yes | `1` | | `name` | yes | up to 60 characters: the name in **Settings → Appearance** | | `entry` | yes | an `.html` page or a `.js` script inside the folder, usually `dist/main.js`. A script is put in a page of the app's own | | `description` | no | one sentence, up to 200 characters, shown under its name | | `colour` | no | `true` when it draws in colours of its own with **Colour** on | | `preview` | no | a `.png`, `.jpg` or `.webp` inside the folder, up to 512 KB, shown in the picker | ```json { "protocol": 1, "name": "Pond", "entry": "dist/main.js", "description": "Koi under lily pads, one for each agent.", "colour": true, "preview": "preview.png" } ``` The folder's name is the last part of its id: lowercase letters, digits and single dashes. ## Ship it in a package [#ship-it-in-a-package] A live wallpaper always comes in a package, which names it in `hivemind-package.json`: ```json "wallpapers": [{ "path": "wallpapers/pond" }], "startup": { "wallpaper": "@you/pond/pond" } ``` `startup.wallpaper` names one of the package's own wallpapers. Once the package is installed and on, the app offers it as the background, once per package, as `startup.view` offers a view. The person chooses; nothing switches without them. A package may hold a live wallpaper alone, or beside a view and a theme that go with it. Archipelago (`@dip497/archipelago` on HiveHub) ships its view with its widgets and a theme, and offers the view with `startup.view`; a wallpaper is offered the same way. Give `startup` both a view and a wallpaper, and the app offers both. The rest of what a package holds, and how to update and roll it back: [Packages](https://hivemind.griiken.com/guide/packages/). ## What turns it off [#what-turns-it-off] The app turns a live wallpaper off for the session, shows a notice, and draws the plain background instead, when it: - sends 8 messages that are malformed, or that name a creature the app did not send; - sends more than 120 messages a second; - asks for a newer protocol than this Hivemind speaks; - takes the keyboard (focuses anything in its frame); - uses 60% of a CPU core for six seconds. The scene runs in a process of its own, so it never slows your terminals, but a busy one is still turned off. Measure what a frame costs: the hivemind-live-wallpaper skill in your package's `.claude/skills/` says how. ## Limits [#limits] | What | Most | |---|---| | Creatures | 8. With more agents, the ones that need you come first, then the ones at work | | Tiles in one `tiles` message | 256 | | Live wallpapers in a package | 8 | | A preview picture | 512 KB | | Frames a second | 30, or what `fps` asks, up to 60 | | Waiting for the app | `connectWallpaper()` gives up after 10 seconds | ## Commands [#commands] ```bash hive plugins new wallpaper # a package holding a working wallpaper, with PROMPT.md hive plugins new wallpaper --in # one more in a package you have hive plugins check # the manifests, and the wallpaper loaded once hive plugins install |@owner/package hive config set appearance.wallpaper.kind '"@owner/package/name"' hivehub publish ``` The `hive plugins` commands are in the [CLI reference](https://hivemind.griiken.com/guide/cli/#plugins). --- # Packages > Put your tools, widgets, views, themes and live wallpapers in one package, check it, install it and publish it on HiveHub, all from the hive command. Source: https://hivemind.griiken.com/guide/packages/ A package puts your own tools, widgets, views, themes and live wallpapers in one box that installs, switches on, updates and rolls back as one. You or your agent can write one from the `hive` command alone, from the first folder to its page on HiveHub. {` Build a Hivemind package that does what I describe, using the hive command. 1. Run \`hive plugins new package \`. If it asks for an owner, ask me for my GitHub login and pass \`--owner \`. Read the PROMPT.md it writes in the new folder: it holds the whole guide. 2. Add each member I asked for: \`hive plugins new tool --in \`, \`hive plugins new widget --in \`, \`hive plugins new view --in \`, \`hive plugins new theme --in \` or \`hive plugins new wallpaper --in \` (a live wallpaper, described at https://hivemind.griiken.com/guide/live-wallpapers.md). Read each member's PROMPT.md before writing its code. For a view or a live wallpaper, run \`npm install\` once where its \`package.json\` is. A theme is one theme.json, described at https://hivemind.griiken.com/guide/packages.md#themes. 3. Run \`hive plugins check \` after each change, and fix every problem it reports at its file and line until it says ok. 4. Run \`hive plugins install \`. If it says the package is off, tell me and ask me to switch it on with \`hive plugins enable \`: only I decide to trust code. 5. Open each member with \`hive ctl plugin open :\`, and look at a tool's tile with \`hive ctl tile look \`. To show me a theme, ask me first, then run \`hive theme use /\`; \`hive theme revert\` puts my look back. At the end, tell me what the package holds and what each member asks for. Do not publish it unless I ask. `} ![Diagram: A package is one box](https://hivemind.griiken.com/guide/images/packages-one-box.svg) - A **package** is one folder. Its `hivemind-package.json` names its **tools**, **widgets**, **views**, **agent presets** and **themes**, each tool, widget, view and theme in a folder of its own with its own manifest. Every member's id has the package's owner: `@you/`, and a theme's `@you/kit/`, after its folder in the package. - Package → **this machine**: `hive plugins install` puts the whole box in, with one switch, one version and a rollback. - Package → **HiveHub**: `hivehub publish` lists the whole box, with every member and what it asks for. A package can also hold **live wallpapers**, scenes behind the canvas whose creatures are your agents. Each is a folder with a `hivemind-wallpaper.json`, named under `wallpapers`, and its id is `@you/kit/`, as a theme's is. How to make one: [Make a live wallpaper](https://hivemind.griiken.com/guide/live-wallpapers/). Which packages arrive switched off, and which updates need your trust again, are in [Plugins](https://hivemind.griiken.com/guide/plugins/#packages). ```bash hive plugins new package kit ``` It writes `kit/` with a `hivemind-package.json` that holds nothing yet, a `README.md`, and a `PROMPT.md` to hand your coding agent. Its owner is the GitHub login `gh` is signed in as, or the one you pass with `--owner`. Start each member inside the package. It is named in `hivemind-package.json` for you, with the package's owner: ```bash hive plugins new tool prs --in kit # kit/tools/prs hive plugins new widget dog --in kit # kit/widgets/dog hive plugins new view board --in kit # kit/views/board, named by its dist/ hive plugins new wallpaper pond --in kit # kit/wallpapers/pond hive plugins add ../counter --to kit # copied to kit/widgets/counter ``` `add` takes one you already wrote. It refuses a plugin whose id is not yours (`@you/`), and changes nothing. Each new member has its own `PROMPT.md` with the guide of its kind: [tools](https://hivemind.griiken.com/guide/tool-plugins/), [widgets](https://hivemind.griiken.com/guide/widgets/), [views](https://hivemind.griiken.com/guide/extension-authoring/) or [live wallpapers](https://hivemind.griiken.com/guide/live-wallpapers/). For a view or a live wallpaper, run `npm install` once where its `package.json` is. ```bash hive plugins check kit ``` It checks `hivemind-package.json`, then every member with that member's own check: its types, its manifest, and its code drawn once. A view is built first. Each problem has its file and line: a member's in its own folder, and a misspelt member path or a member with someone else's id at the line of `hivemind-package.json` that names it. Check: it ends with `ok: package @you/kit`. `--json` gives the same report to an agent. ```bash hive plugins install ./kit ``` It prints the package and each member it holds, with what each asks for. Install again after each change. `--dry-run` shows what would change, member by member, and installs nothing. A package that holds a tool or an agent preset arrives off. Switch it on once you trust what it runs: ```bash hive plugins enable @you/kit hive ctl plugin open tool:@you/prs # or widget:… or view:… hive ctl tile look # what a tool drew, and what its code logged ``` In the app, it is one row in **Settings → Plugins**, with one switch. To open a view as soon as the package is in, name it in `hivemind-package.json`: `"startup": { "view": "@you/board" }`. Once the package is on, the app asks **Open Board?**, and **Open** shows it. **Settings → Plugins** asks under each install it makes. After `hive plugins install`, the app asks in the corner of the window, at once if it is open, or the next time it starts. It asks there once per view: an update or a rollback to a view it offered before does not ask again. The app never switches the view without you, since an agent may be the one installing. To switch at once from a terminal, run the command the install prints: `hive ctl plugin open view:@you/board`. `--json` gives it as `startView.open`. A package's view brings the package's widgets. The first time a workspace shows the view, however it was opened, each of the package's widgets that is on goes down the edge the view keeps for widgets (`"widgets": "left"` in its `hivemind-view.json`, or the right). They show over that view alone, so the canvas and your other views stay clear. To have one over every view, point at it, or Tab to it, and press its pin, **Show on every view**. An agent runs `hive ctl plugin open `; `hive ctl plugin list` names each widget and the view it shows over. **Hide widgets**, in the bottom-right corner, hides them over the view you are in, and each view keeps its own choice. A widget you close with its × stays closed, unless you press **Undo** on the notice that says it was removed, before you switch workspace: the view never brings it to that workspace again, in any window. One that a later version of the package adds comes when the view shows: at once if it is open. A workspace where you had already put some of the package's widgets is left as you arranged it. So the install's `next` does not list them: `hive ctl plugin open widget:…` adds another copy, over every view. To offer one of its live wallpapers as the background, name it the same way: `"startup": { "wallpaper": "@you/kit/pond" }`. It must be one of the package's own. The app offers it once, and never switches without you; `--json` gives the command as `startWallpaper`. See [Make a live wallpaper](https://hivemind.griiken.com/guide/live-wallpapers/#ship-it-in-a-package). Change a member, raise `version` in `hivemind-package.json`, check, and install again. When a change needs your trust again, the package goes off, and the install lists what changed. ```bash hive plugins rollback @you/kit ``` It puts back the version in use before the last update, switched on or off as it was. Commit the package folder, with each view's `dist/`, and push it to GitHub. Then: ```bash hivehub publish kit ``` It shows the package, each member, where its code runs and what it asks for, and publishes when you answer `y`. Anyone can then install it with `hive plugins install @you/kit`. Getting the `hivehub` command and signing in are in [Publish to HiveHub](https://hivemind.griiken.com/guide/publish-to-hivehub/). ## Themes [#themes] A theme is a member that changes how the app looks: colours, an accent, and if you like terminal colours, corners, fonts and a wallpaper. It holds no code, so a package of only themes, views, widgets and live wallpapers arrives switched on. How people apply one is in [Change how Hivemind looks](https://hivemind.griiken.com/guide/appearance/#themes). A theme is a folder in the package holding `theme.json`, named in `hivemind-package.json` (at most 8 in a package): ```json "themes": [{ "path": "themes/harbour" }] ``` Its id is the package's id and its folder: `@you/kit/harbour`. Start one from the look you use now: ```bash hive plugins new theme harbour --in kit # kit/themes/harbour/theme.json hive plugins check kit hive plugins install ./kit hive theme use @you/kit/harbour # see it; hive theme revert goes back ``` Add font, wallpaper and sound files beside `theme.json`, and name them in it by their path in the folder. ### theme.json [#themejson] | Field | Needed | Takes | |---|---|---| | `format` | yes | `1` | | `name` | yes | up to 60 characters | | `mode` | yes | `"dark"` or `"light"` | | `palette` | yes | all 13 colours: `bg`, `bg2`, `bg3`, `bg4`, `line`, `line2`, `fg`, `fg2`, `fg3`, `select`, `ok`, `warn`, `err` | | `accent` | yes | a built-in accent (`graphite`, `indigo`, `volt`, `ember`, `ice`, `pulse`, `rose`, `emerald`, `violet`), or `{ "brand", "accent", "working"? }` colours. `working` is the colour of an agent at work | | `terminal` | no | `background`, `foreground`, `cursor`, `selection` and `ansi`, the 16 terminal colours | | `radius` | no | corners, 0 to 24 | | `fonts` | no | `{ "ui"?, "mono"? }`, each `{ "family", "files": [{ "path", "weight"?, "style"? }] }`: 1 to 4 `.woff2` files of at most 400 KB each | | `wallpaper` | no | `{ "kind" }`, a built-in one (`none`, `aurora`, `ember`, `ice`, `mesh`, `sunset`, `forest`, `nebula`, `mono`), or `{ "image" }` (.png, .jpg, .webp, .avif or .gif) or `{ "video" }` (.webm or .mp4) naming a file in the folder, up to 2 MB; `brightness` 0.4 to 1.1 | | `sounds` | no | `{ "needs"?, "done"?, "error"? }`, each an `.ogg` or `.mp3` of at most 400 KB, copied with the theme | Colours are `#rrggbb`, `rgb()` or `oklch()`, and solid: a theme's colours have no transparency. A file may sit at most four folders deep in the theme's folder. The whole package is at most 8 MB, the [limits HiveHub takes](https://hivemind.griiken.com/guide/hivehub-api/#limits). What a theme leaves out stays as the person has it, and **Revert to previous look** puts back only what it set. `icons`, `cursors`, `scene`, `mascot`, `screens` and `words` are kept for a later format and are refused. ### What the check refuses [#what-the-check-refuses] `hive plugins check`, the install and HiveHub check a theme the same way, and `hive plugins check` sizes the package as HiveHub does. Each refusal names the field or the pair of colours. - `fg` on `bg`, and `fg` on `bg2`, below 4.5:1. - `fg2` on `bg` below 3:1. - The accent's `brand` below 3:1 on `bg` or on `bg2`, the panels and menus: a switch that is on, a slider's thumb or the selected tile's handle in it would be hard to see. - An accent that is the colour of an agent waiting on you: `palette.warn`, the colour needs-you is drawn in for that palette (see below), or `amber`. - Panels on which a diff cannot be read. The app works out a diff's text, syntax colours, +N/−N, line numbers, a folded run's words and a removed line's bar from `bg2`, `bg3`, `fg`, `fg2`, `ok` and `err`, moving each away from its panel as far as it must; when none reaches 4.5:1 (3:1 for the bar's stripes), the refusal names the pair. A mid-grey `bg2` such as `#666666` is refused, even with white text on it. - A file it names that is not in the folder, has the wrong type or is too big. - A colour CSS would draw differently: a part too many, a unit a part does not take, or text after it. For its status chips, what a theme's `err` and `warn` need is fitted, not refused. When a failed or needs-you chip would read under 4.5:1 for its word on its own fill or on `bg2`, or under 3:1 for its mark on `bg2`, `bg3` or `bg4` (a row at rest, under the pointer and selected), the app draws it lighter in the same hue on a dark theme, or darker on a light one, keeping as much of its colour as it can. A status word drawn straight on a tile's header or a selected row is fitted to those too. A view is told the fitted failed and needs-you colours; its `done` is the palette's `ok`, as before. Every command on this page is in the [CLI reference](https://hivemind.griiken.com/guide/cli/#plugins). --- # Write a tool > Add a new kind of tile, such as a pull request panel or a commit browser, drawn by your own code. Source: https://hivemind.griiken.com/guide/tool-plugins/ A tool adds a kind of tile. Write one when you want a panel beside your agents that shows something from your project. {` Build a Hivemind tool plugin, a new kind of tile drawn by React code inside the app, and, if I want, publish it on HiveHub. 1. Ask me what the tile should show and do, and its name (lowercase letters, digits and dashes). 2. Start it: \`hive plugins new tool \`. It takes the owner from the GitHub account \`gh\` is signed in as. If \`gh\` is not signed in, ask me for my GitHub login and pass \`--owner \`. Check the folder has \`hivemind-tool.json\`, \`index.js\`, \`README.md\` and \`PROMPT.md\`. 3. Read \`PROMPT.md\` in full: it is the whole contract (manifest, what a tile gets, the \`hm-plugin://host/\` modules, commands). Write what I asked for under its "What I want". Build only from it; never use \`window.hive\`. 4. Check it, then install it, again after each change: \`hive plugins check \` must say ok (it names the file and line of each problem), then \`hive plugins install \`. A tool runs with my access, so new or changed code arrives switched off; the same code stays as it was. Ask me before you switch it on with \`hive plugins enable tool:@owner/name\`. 5. Open it: \`hive ctl open-tool @owner/name\`. Look at it with \`hive ctl tile look \`: check the picture shows what I asked for and its console has no error. 6. Give it one command in the manifest's "commands", answered with \`hm.onCommand\`, that reports what the tile shows. Check it with \`hive ctl plugin call @owner/name \`. 7. Done means: \`hive plugins list\` shows it on with no problem, it reads well in the light and the dark theme, the manifest has a one-line description, a "category" and only the permissions it uses, and \`README.md\` says what it does and what it runs. 8. Publish only if I say so. Follow the "Publish a plugin" page (https://hivemind.griiken.com/guide/publish-to-hivehub.md): push the folder to a GitHub repository I name, then \`hivehub publish \`. If I must sign in, ask me to open the link and type the code myself. At the end, tell me the tool's id, the command that installs it (\`hive plugins install @owner/name\`), and anything you could not check. `} The Flaky tests tile on the canvas, beside the Layers panel. It lists five tests with a row of eight pass or fail squares each, two marked flaky, each with an Ask an agent to fix button. The Browser, Issues and the Code tile are tools that come with the app. **A tool runs with your access.** It runs inside the app with your files, programs and logins. So a tool you add starts switched off, and you turn it on yourself. Turn on only tools whose author you trust. If one breaks the app, start it with `HIVEMIND_SAFE_MODE=1 hivemind`: no added tool loads. ## Try one [#try-one] 1. Install a tool from HiveHub: ```bash hive plugins install @dip497/worktrees ``` Check: it prints `installed @dip497/worktrees` and says it is off. 2. Switch it on: ```bash hive plugins enable tool:@dip497/worktrees ``` 3. Open its tile: ```bash hive ctl plugin open tool:@dip497/worktrees ``` Check: a tile opens that lists every git worktree of the project. Or do it in **Settings → Plugins**, on the **HiveHub** tab: pick a tool, install it, and turn it on on its page. The HTTP endpoints your code declares, and a panel to call one. Follows a log file, with errors handed to an agent. Known vulnerabilities in your lockfiles. Clean tree, tests, changelog: each checked, each fixable by an agent. Every tool on HiveHub is listed on the **HiveHub** tab; pick **Tools** to see only tools. ## Write one [#write-one] ### Before you start [#before-you-start] - Hivemind is installed and open on a project that is a git repository. - You know a little JavaScript and React. ```bash hive plugins new tool branch ``` Check: it prints `started tool plugin @/branch`. If it asks whose it is, add `--owner `. ```bash cd branch && hive plugins install . && hive plugins enable tool:@/branch ``` Check: `hive plugins list` shows `tool:@/branch` as on. Open it from the frame's **Open** menu, or run `hive ctl open-tool @/branch`. Check: a tile shows **Branch:** and the project's current git branch, with a **Refresh** button. The starter's `index.js` draws the tile with the app's own React. It runs `git` through `host.run`, in the tile's folder: ```js index.js import React, { useEffect, useState } from "hm-plugin://host/react.js"; import { Button } from "hm-plugin://host/sdk.js"; const h = React.createElement; function Tile({ tile, host }) { const [branch, setBranch] = useState("…"); const refresh = () => host.run("git", ["branch", "--show-current"]).then((r) => setBranch(r.stdout.trim() || "(no branch)")); useEffect(() => { void refresh(); }, []); return h("div", { style: { padding: 16, display: "grid", gap: 8 } }, h("h3", { style: { margin: 0 } }, tile.name), h("p", null, "Branch: ", h("code", null, branch)), h(Button, { size: "sm", variant: "outline", onClick: refresh }, "Refresh")); } export default { tiles: { "you-branch": Tile } }; ``` The default export maps each tile kind in `hivemind-tool.json` to the component that draws it. Make the button show the last commit too. Replace the `refresh` line with: ```js const refresh = () => host.run("git", ["log", "-1", "--format=%D: %s"]).then((r) => setBranch(r.stdout.trim())); ``` Install it again with `hive plugins install .`. Changed code arrives switched off, so switch it on again with `hive plugins enable tool:@/branch`, then press **Refresh** in the tile. Check: the tile shows the branch and the last commit's subject. ### Check it worked [#check-it-worked] - `hive plugins list` shows the tool on, with no problem. - Its tile opens from the frame's **Open** menu. ### If it didn't [#if-it-didnt] | You see | Do this | |---|---| | The tile is missing from **Open** | `hive plugins enable tool:`; a tool you add starts off. A tool with `needsRepo` only shows in a frame with a git repository. | | The app misbehaves after you turned a tool on | Start it with `HIVEMIND_SAFE_MODE=1 hivemind`, then switch the tool off on its page. | | Something else | [Troubleshooting](https://hivemind.griiken.com/guide/troubleshooting/) | Next: [Publish a plugin](https://hivemind.griiken.com/guide/publish-to-hivehub/) on HiveHub, or ship it with your widgets and views as one: [Packages](https://hivemind.griiken.com/guide/packages/). ## Tool reference [#tool-reference] ### The manifest [#the-manifest] ```json hivemind-tool.json { "id": "@acme/prs", "name": "Pull requests", "version": "1.0.0", "apiVersion": 1, "description": "One line, shown in Settings.", "category": "git", "entry": "index.js", "permissions": ["workspace:spawn"], "settings": [ { "id": "state", "label": "Show", "type": "choice", "values": ["open", "all"], "default": "open" } ], "tools": [ { "key": "prs", "label": "Pull requests", "description": "What its tile shows.", "tileKind": "acme-prs", "size": { "width": 1100, "height": 760 }, "needsRepo": true, "singleton": true, "glyph": "⇅", "icon": "icon.svg" } ] } ``` | Field | Means | |---|---| | `id` | `@owner/name`; `@hivemind/` is kept for the app's own | | `tools[]` | one entry per kind of tile. `needsRepo` hides it in a frame with no repository. `singleton` focuses the open one instead of opening another. | | `icon` | an `.svg` in the folder (32 KB at most); without one, `glyph` is shown | | `permissions`, `settings` | the same as a view's ([Write a view](https://hivemind.griiken.com/guide/extension-authoring/#permissions)) | | `"commands"` | what an agent can run while a tile of the tool is open | | `"category"` | where it is grouped in the Add menu and on HiveHub | ### What a tile gets [#what-a-tile-gets] | Prop | What it is | |---|---| | `tile` | `{ id, kind, name, frameId }` | | `hm` | the client a view has (`@hivemind/view-sdk`): frames, tiles, agents' status and events, commands, its settings, and its saved state, kept per tile (`hm.hello.layout`, `hm.setLayout`). Each is held to the permissions the manifest declares. | | `host` | what only a tile has: `repoPath`, `cwd`, `run(bin, args, { maxAgeMs, stdin })` (see [Running programs](#running-programs)), `openFile(path)` in the frame's Code tile, `openUrl(url)` in the frame's browser | | `selected` | it has the person's focus | A tile imports the app's own React and parts from `hm-plugin://host/`: `react.js`, `react-jsx-runtime.js`, `sdk.js` and `ui.js`. It bundles none of them. `sdk.js` has `Button`, `PatchView` (a diff), `Markdown`, `Loading`, `Frame` (a page from a server on this machine) and `useTileState(hm, key, initial)`, which keeps a value with the tile across restarts. `ui.js` is the app's whole UI kit (`Button`, `Input`, `Dialog…`, `DropdownMenu…`, `Switch`, `toast`, …). The built-in Issues tile (`apps/desktop/tools/issues` in the repository) is the fullest example of how a tile is built. Its colours are not one to copy: it also paints with app variables outside the 11 below, which may change. Reach the app only through these, never `window.hive`. ### Colours and type [#colours-and-type] A tile paints with the app's own CSS variables, so it follows every theme, dark and light. These 11 are the ones a tile may rely on: each keeps its name and has a value in every theme. Any other `--color-*` or `--font-*` in the app may change without notice. | Variable | What it is | |---|---| | `--color-bg` | the page | | `--color-bg3` | a card or a raised row | | `--color-fg` | text | | `--color-fg3` | quiet text: hints, counts, dates | | `--color-line` | borders and dividers | | `--color-select` | a selected row or text | | `--color-ok` | done, passed, added | | `--color-warn` | needs a look | | `--color-err` | failed, removed | | `--color-info` | a neutral mark, never words: it can be the person's accent, which is held to 3:1 only. Draw a link in `--color-fg`, underlined | | `--font-mono` | the code font | A release that removes or renames one says so with **Breaking:** in the CHANGELOG. A tile's code runs in the app's own page, so it gets the browser rights the app uses and no others: notifications and writing to the clipboard. The camera, the microphone, the location and reading the clipboard are refused. A page that needs them goes in a Browser tile, which asks you: `host.openUrl(url)`. ### Ids, opening and reinstalling [#ids-opening-and-reinstalling] A tool package's id is `@owner/name`. Each tool in it has a full id, `@owner/name/`: `hive plugins list --kind tool` prints it. ```bash hive ctl open-tool @acme/prs # the package's tool, when it has one hive ctl open-tool @acme/prs/prs # by its full id; needed when it has several hive ctl open-tool @acme/prs --state '{"tab":"open"}' # the tile's first state ``` `--state` is a JSON object: each key is what `useTileState(hm, key, initial)` reads when the tile first draws. Installing a tool again with the same code, byte for byte, keeps it on or off as it was. Changed code is switched off, since turning it on trusted the code that was there: switch it on again with `hive plugins enable tool:`. The install says which. ### Running programs [#running-programs] `host.run(bin, args, { maxAgeMs, stdin })` runs a program and answers `{ code, stdout, stderr }`. - `bin` is a program's name, found on the app's `PATH`, which comes from your login shell. A folder on `PATH` inside the tile's own folder is skipped. - It runs in the tile's folder, without a shell: `args` reach it as they are, with no globs or pipes. On Windows a `.cmd` or `.bat` shim is refused, since only a shell can run one. - It is stopped after 60 seconds, and when it writes more than 10 MB. - `maxAgeMs` (up to 5 minutes) answers the same call from a cache while it is that fresh. - `stdin` is text written to its input. ### Show a server on this machine [#show-a-server-on-this-machine] A tool can show a page its own local server serves, such as a dev server or a dashboard. Use `Frame` from `sdk.js`: ```js import { Frame } from "hm-plugin://host/sdk.js"; h(Frame, { src: "http://127.0.0.1:5173/", title: "Dev server" }); ``` Only `http://127.0.0.1:` and `http://localhost:` can be shown; any other address is blocked, and the tile stops and says so. `Frame` runs the page's scripts, forms and popups, and never lets it move the app's window. It gets no camera, microphone, location or notifications: a page that needs them goes in a Browser tile, which asks you. ### Look at it, and see what broke [#look-at-it-and-see-what-broke] ```bash hive ctl tile look --json # a picture of the tile, its state and its console hive ctl plugin list --json # each plugin's state: starting, ready or failed, with why ``` `tile look` brings the tile into view, waits until its code has drawn, and saves a PNG of it. It answers the tool's state, whether it drew, and the last 100 lines its code wrote to the console. When something is drawn over the tile, such as a pinned tile, a dialog or a notification, it refuses with `OCCLUDED` and names it; move it, or wait for the notification, and look again. When the tool's code throws an error nothing catches, a promise of its fails unheard, or the app blocks something it loads, its tile stops and shows why, and `plugin list` reads it as `failed` with that reason. ### Pointer and keys in a tile [#pointer-and-keys-in-a-tile] What the canvas does with input over a tool's tile, so your tile can count on it: | Input | What happens | |---|---| | Left click and drag | Yours. The tile moves only by the bar the app draws on it. | | Right click | Yours: `contextmenu` reaches your tile, and the app shows no menu of its own. On a tile that is not selected, dragging with the right button pans the canvas instead. | | Middle button | Pans the canvas, always. Your tile does not see it. | | Wheel | Yours first. When the tile is not selected and nothing under the pointer scrolls, it also pans the canvas. Ctrl or ⌘ with the wheel zooms the canvas and never reaches your tile. | | Keys | Yours while focus is in your tile, but for the app's own shortcuts (such as Ctrl+Tab, Ctrl+1 to 9 and Ctrl+,), which the app takes first. | | Cursor | Yours: set `cursor` on any element you draw, inside a shadow root too. Where you set none, it is the normal pointer. | ### Commands agents can run [#commands-agents-can-run] Declare them in `hivemind-tool.json`, and answer them in the tile: ```json "commands": [{ "name": "list", "description": "Every worktree, with its branch and what is not committed." }] ``` ```js useEffect(() => hm.onCommand("list", () => trees), [hm, trees]); ``` `hive ctl plugin call @dip497/worktrees list` prints what the handler returns. It works while a tile of the tool is open. With two open, name one with `--tile`. ### A service that keeps running [#a-service-that-keeps-running] A tool can bring a program the app keeps running while the tool is on: an orchestrator, a dashboard, a watcher. It drives workspaces through the [API](https://hivemind.griiken.com/guide/api/), with its own token. ```json "service": { "command": ["node", "service.js"], "role": "agents" } ``` `role` is one of the [roles](https://hivemind.griiken.com/guide/api-tokens/). Once switched on, the service waits until you pick the workspaces it may drive, on the tool's page. Where `hive host` runs it, use `hive plugins workspaces tool: `. It then starts with these variables: | Variable | What it holds | |---|---| | `HIVE_DRIVE_SOCK` | where it connects | | `HIVE_DRIVE_TOKEN` | its token: the first line it sends is `{"hello": {"token": …, "workspace": …}}` | | `HIVE_WORKSPACES` | the folders it may drive, separated as in `PATH` | It restarts after a crash (after 1 s, then 2, 4… up to a minute). It stays stopped after a clean exit, or when its token is revoked. It should exit when its standard input closes. Its output is on its page. ### On a shared canvas [#on-a-shared-canvas] A guest sees a tool's tile if they have the same tool switched on. A tile's programs run on the computer of the person looking at it. ### Commands [#commands] ```bash hive plugins new tool [--dir folder] # a starter, with PROMPT.md and its types hive plugins check # its types, its manifest, and each tile drawn once, with file:line hive plugins api --kind tool # tile, host and hm, as declared hive plugins install |@owner/name # new or changed code off: hive plugins enable @owner/name hive plugins list --kind tool # each tool, and the full id of each of its tiles hive plugins remove @owner/name ``` --- # Build a widget > Make a small live card for your canvas in a few lines of JavaScript, try it, and share it. Source: https://hivemind.griiken.com/guide/widgets/ Build a counter widget, put it on your canvas and change it. It takes about ten minutes. {` Build a Hivemind widget (a small live card on the canvas, drawn by its own code in a worker) and, if I want, publish it on HiveHub. 1. Ask me what the widget should show and do, and its name (lowercase letters, digits and dashes). 2. Start it: \`hive plugins new widget \`. It takes the owner from the GitHub account \`gh\` is signed in as. If \`gh\` is not signed in, ask me for my GitHub login and pass \`--owner \`. Check the folder has \`widget.json\`, \`widget.js\`, \`hive.d.ts\`, \`README.md\` and \`PROMPT.md\`. 3. Read \`PROMPT.md\` in full: it is the whole contract. Write what I asked for under its "What I want". The widget has no network and no files. What it draws and its state are each up to 16 KB. 4. Check it, then install it, again after each change: \`hive plugins check \` must say ok (it names the file and line of each problem), then \`hive plugins install \`. Check it prints "app updated". 5. Put one on the canvas: \`hive ctl plugin open widget:@owner/name\`. If \`hive plugins list\` shows it off, run \`hive plugins enable widget:@owner/name\`. 6. Declare one command in \`widget.json\` under "commands", answered with \`hive.hm.onCommand\`, that reports what the widget shows. Check it with \`hive ctl plugin call @owner/name \`. 7. Done means: \`hive plugins list\` shows it on with no problem, it reads well in the light and the dark theme, and \`README.md\` says what it does. 8. Publish only if I say so. Follow the "Publish a plugin" page (https://hivemind.griiken.com/guide/publish-to-hivehub.md): push the folder to a GitHub repository I name, then \`hivehub publish \`. If I must sign in, ask me to open the link and type the code myself. At the end, tell me the widget's id, the command others use to install it (\`hive plugins install @owner/name\`), and anything you could not check. `} ## What others have built [#what-others-have-built] Each of these is a widget on HiveHub, as `@dip497/`. The agents waiting on you, and for how long. How many agents are busy right now. A light your CI or hooks turn green or red. Passing and failing tests, as your scripts report them. Open issues, day by day. Buttons that start agents with jobs you set. A timer for a block of focused work. What your agents report they spent today. A dog that walks the screen and barks when an agent waits on you. ## What you'll learn [#what-youll-learn] - How to start a widget from the starter and put it on the canvas. - How a widget draws, keeps state and answers a button. - How to change it and see the change. ## Before you start [#before-you-start] - Hivemind is installed and open on a project. See [Install and run your first agent](https://hivemind.griiken.com/guide/getting-started/). - You know a little JavaScript. Make a starter widget called `counter`: ```bash hive plugins new widget counter ``` Check: it prints `created @/counter`. The `counter` folder holds `widget.json`, `widget.js`, `hive.d.ts`, `README.md` and `PROMPT.md`. If it asks for an owner, add `--owner `. ```bash hive plugins install counter ``` Check: it prints `installed @/counter (Counter)` and `app updated`. Open the toolbar's **Add** menu and pick **Counter**. Check: a card shows **0** and **presses**, with a **Press** button. Press it and the number goes up. The starter is two files. `widget.json` names the widget and its options. `widget.js` draws it and answers its button. ```json widget.json { "id": "@you/counter", "name": "Counter", "version": "0.1.0", "description": "Counts presses.", "icon": "icon.svg", "options": [{ "id": "step", "label": "Step", "type": "number", "min": 1, "max": 100, "default": 1 }] } ``` ```js widget.js const draw = () => hive.render({ type: "stack", children: [ { type: "number", value: hive.state?.n ?? 0, label: "presses" }, { type: "button", label: "Press", action: "inc" }, ] }); hive.on("start", draw); hive.on("action", (a) => { if (a === "inc") { hive.setState({ n: (hive.state?.n ?? 0) + Number(hive.options.step ?? 1) }); draw(); } }); ``` `hive.state` is saved with the workspace, so the count survives a restart. In `widget.js`, change `label: "presses"` to `label: "clicks"`. Then install it again: ```bash hive plugins install counter ``` Check: the card now reads **clicks**. Hover the card and press its gear. Set **Step** to 5. Check: each press now adds 5. Everyone in the workspace sees the same option. ## What you did [#what-you-did] - You started a widget with `hive plugins new widget` and installed it with `hive plugins install`. - You drew it with `hive.render`, kept its count in `hive.state`, and answered its button. - You changed it and gave it an option people can set. ## Next [#next] - Want an agent to build the rest? Write your idea at the top of `PROMPT.md` and hand it the file. - Share it: [Publish a plugin](https://hivemind.griiken.com/guide/publish-to-hivehub/) on HiveHub. - Ship it with your other tools, widgets and views as one: [Packages](https://hivemind.griiken.com/guide/packages/). - Something wrong? See [Troubleshooting](https://hivemind.griiken.com/guide/troubleshooting/). ## Widget reference [#widget-reference] ### What your code gets [#what-your-code-gets] | Call | What it does | |---|---| | `hive.render(tree)` | draws the widget | | `hive.state`, `hive.setState(value)` | what it keeps, saved in the workspace | | `hive.options` | its options, as set, or else their defaults | | `hive.on("options", fn)` | the person changed its options | | `hive.notify(text)` | shows a desktop notification, as the person's [notification settings](https://hivemind.griiken.com/guide/know-who-is-waiting/#choose-what-notifies-you) allow (**Do Not Disturb** mutes it), its text cut to 200 characters. At most one shows every 10 seconds: what it sends in between shows once when the time is up, the latest text and how many more came ("and 2 more") | | `hive.moveTo({ x, y }, { over })` | moves its card: `x` and `y` from 0 to 1 across the screen (`y: "bottom"`), over `over` ms | | `hive.spot` | where it last moved to | | `hive.reducedMotion`, `hive.on("motion", fn)` | the person asked for less motion: hold still and do not move the card. A sprite already stops on its first frame | | `hive.on("click", fn)` | its card was clicked, not on a button | | `hive.on("start", fn)` | it was placed, or the app opened | | `hive.on("action", fn)` | one of its buttons was pressed; `fn` gets the button's `action` | | `hive.on("hm", fn)` | the values in `hive.hm` arrived or changed | | `hive.hm` | the workspace, as a view sees it (below) | It runs in a worker: no network, no files. What it draws and its state are each up to 16 KB. ### What it can draw [#what-it-can-draw] | Node | Fields | |---|---| | `stack`, `row` | `children`; on the outermost `stack`, `tint` colours the card as a note: `yellow`, `peach`, `pink`, `violet`, `blue` or `green` | | `text` | `text`, `size: "large"`, `muted: true`, `wrap: true` | | `number` | `value`, `label` | | `meter` | `value`, `max`, `label` | | `button` | `label`, `action` | | `image` | `src` (an image in its folder), `w`, `h` | | `sprite` | `src` (a sheet of frames), `frameW`, `frameH`, `row`, `frames`, `fps`, `scale`, `flip` | A `text` or a button's `label` longer than the card is cut short with "…"; a button shows the whole label when the pointer rests on it. `wrap: true` wraps a `text` onto more lines instead. In a `row`, a `stack` or a `meter` fills the width left over, so the bars of rows drawn one under another end together. A `meter`'s `label` is also its name for a screen reader. Images (`.png`, `.gif`, `.webp`, `.jpg`, `.svg`, up to 1 MB) go in the widget's folder. `"chrome": "none"` drops the card, for a pet that walks the screen. ### Options [#options] `options` uses the settings fields every plugin uses: see [Plugin settings](https://hivemind.griiken.com/guide/plugin-settings/). What someone sets is shared with everyone in the workspace. ### A widget without code [#a-widget-without-code] A widget can be data and a drawing alone. The built-in Sticky note, Checklist and Text are made this way: ```json { "name": "Sticky note", "placement": "board", "size": { "w": 220, "h": 180 }, "options": [{ "id": "color", "label": "Colour", "type": "choice", "values": ["yellow", "pink", "blue"], "default": "yellow" }], "draw": { "type": "stack", "fill": true, "tint": "$options.color", "children": [{ "type": "textarea", "placeholder": "Write something" }] } } ``` `"placement": "board"` pins it to the canvas, so it moves with its frame. `input`, `textarea` and `list` are what people write in. Two people typing at once merge, and undo takes it back. ### Read and drive the workspace [#read-and-drive-the-workspace] `hive.hm` is the same client a view has ([Write a view](https://hivemind.griiken.com/guide/extension-authoring/)). It is held to the permissions `widget.json` asks for: ```json { "name": "Agents at work", "permissions": ["workspace:spawn", "workspace:prompt"] } ``` ```js hive.hm.onEvents(["turn", "needsInput"], (e) => hive.notify(`${e.kind} in ${e.tileId}`)); hive.on("hm", draw); ``` A button that goes to an agent calls `hive.hm.commands.focusTile(tileId)`. The view on screen shows it: the canvas moves to the tile, and a view such as Archipelago is asked to show it (its `hm.onReveal`). An agent can run a command the widget declares under `"commands"`. The widget answers with `hive.hm.onCommand(name, handler)`: ```bash hive ctl plugin call @dip497/progress add '{"text":"Run the tests"}' ``` ### Where it runs [#where-it-runs] ![Diagram: One window runs a widget; everyone sees it](https://hivemind.griiken.com/guide/images/widgets-runner.svg) - **The window that runs `widget.js`**: the first of your own windows with the workspace open. - It → **guests' windows**, **your other windows** on any device, and **your phone** through a widgets view: what it draws, live. - Any of them → that window: a press. Guests can press only if they can edit the board. - Nothing it draws is saved. Nobody else's computer runs your code. On your phone, a view that shows widgets draws them (`hive plugins install @dip497/widgets`). ### Commands [#commands] ```bash hive plugins new widget [--dir folder] # a starter, with PROMPT.md hive plugins check # its types, its widget.json, and its first drawing, with file:line hive plugins install |@owner/name hive plugins list --kind widget # the app's own widgets and the ones you added hive plugins remove # what each placed one holds stays on its canvas ``` --- # Use these docs from your agent > Let your coding agent read these docs through llms.txt or any page as Markdown, and teach it Hivemind with the hive skills. Source: https://hivemind.griiken.com/guide/docs-for-agents/ Your coding agent can read these docs and drive Hivemind for you. Point it at them once, and it looks things up instead of guessing. {` Remember where the Hivemind documentation is, so you read it instead of guessing. 1. Fetch https://hivemind.griiken.com/guide/llms.txt. It lists every page with a one-line description, and each page's address as Markdown. 2. Add a short note to this project's agent instructions (CLAUDE.md, AGENTS.md, or what this agent reads): "Hivemind docs: https://hivemind.griiken.com/guide/llms.txt. Read the page you need as Markdown before using a hive command." 3. Check: find the page about installing Hivemind in that list, read it as Markdown, and tell me the install command for this computer. If writing the instructions file needs a choice only I can make, ask me and wait. `} ## Give it the docs as text [#give-it-the-docs-as-text] | File | Holds | |---|---| | [`/guide/llms.txt`](https://hivemind.griiken.com/guide/llms.txt) | every page, each with its one-line description and its address as Markdown | | [`/guide/llms-full.txt`](https://hivemind.griiken.com/guide/llms-full.txt) | every page in one Markdown file | To get one page as Markdown, add `.md` to its address, as in `https://hivemind.griiken.com/guide/install.md`, or press **Copy page** at the top of the page. **Open** beside it shows the Markdown, or hands the page to Claude, ChatGPT, Cursor or Scira AI. **Check:** ask your agent "How do I install Hivemind?" It answers with the install command from these docs. ## Teach it Hivemind with the hive skills [#teach-it-hivemind-with-the-hive-skills] To let an agent work in Hivemind on its own, add the hive skills to your project. ```bash cd ~/my-project && hive add skill ``` **Check:** `.claude/skills/` now holds `hive-work`, `hive-workflow`, `hivemind` and `hive-browser`. An agent that reads skills learns to pick up issues and to start and coordinate other agents with `hive ctl`. ## Use the prompt on each page [#use-the-prompt-on-each-page] A page that describes something you set up or do starts with a prompt. Paste it into Claude Code, Codex or any coding agent, and it does the job on your computer. Each prompt says what to check at the end. It asks you for anything only you can do, such as a password, a sudo or a DNS record. Each one ends with a `REFERENCE` line: the page as Markdown, for the agent to read. ## Rules for agents that read these docs [#rules-for-agents-that-read-these-docs] - Prefer `hive ctl … --json`, and check `hive --help` before using a flag. - Never ask a person for a token's value. Tell them to make one in **Settings → API access**. - Use the smallest role that does the job. - Ask the person before installing anything, and never type a password. --- # Install and run your first agent > In about five minutes: install Hivemind, start a coding agent in your project, and answer its first question. Source: https://hivemind.griiken.com/guide/getting-started/ In about five minutes you install Hivemind, start a coding agent in a project, and answer the first question it asks you. {` Install Hivemind on this computer, add my coding agent to it, and open a project. 1. Install. On Linux or macOS: \`bash <(curl -fsSL https://hivemind.griiken.com/install.sh)\`. On Windows, in PowerShell: \`irm https://hivemind.griiken.com/install.ps1 | iex\`. On an Intel Mac, stop and tell me: there is no prebuilt app. 2. Check: \`hive --version\` prints a version. If \`hive\` is not found, tell me the line that adds \`~/.local/bin\` to PATH in my shell profile. 3. Check which agent programs are on PATH: \`command -v claude codex opencode\`. Ask me which one to use. If I have none, ask before installing one. 4. Add it: \`hive agents install --yes\`. Check: \`hive agents list --found\` lists it. 5. Ask me which project folder to open, then run \`hivemind \`. Never type a password; if a step needs sudo, ask me to run it. At the end, tell me the version installed and the agent added. Then tell me to press 2 in the app to start the agent, and to ask it to create a file, so I see its tile turn amber when it asks me. `} ## What you'll learn [#what-youll-learn] - How to install Hivemind and add the coding agent you already use. - How to start that agent in a project. - How Hivemind shows you that an agent is waiting, and how you answer it. ## Before you start [#before-you-start] - A computer Hivemind runs on: Linux x86_64, macOS on Apple Silicon, or Windows x64. Others are in [System requirements](https://hivemind.griiken.com/guide/system-requirements/). - A coding agent's own program, installed and signed in, such as `claude`, `codex` or `opencode`. - A project folder, ideally a git repository. Run the installer for your system. ```bash Linux and macOS bash <(curl -fsSL https://hivemind.griiken.com/install.sh) ``` ```powershell Windows (PowerShell) irm https://hivemind.griiken.com/install.ps1 | iex ``` **Check:** `hive --version` prints a version. Other ways to install, such as one exact release or nightly builds, are on [Install](https://hivemind.griiken.com/guide/install/). Start Hivemind in your project's folder. ```bash cd ~/my-project && hivemind . ``` **Check:** the app opens, and the Layers panel on the left lists your project. On its first start, Hivemind finds the agent programs on your `PATH` and adds the matching agents from [HiveHub](https://hivehub.griiken.workers.dev/). Skip this step if the app already added your agent. Otherwise add it by name. ```bash hive agents install claude --yes ``` **Check:** `hive agents list --found` lists it. In the app, the agent is under **Settings → Plugins**. More in [Run agents](https://hivemind.griiken.com/guide/agents/). Click the project's frame on the canvas, then press 2. **Check:** a new tile opens in the frame, and your agent's prompt appears in it. 2 starts your default agent, which you choose in **Settings → Plugins**. Type a small task into the agent's tile, such as `Create a file called hello.txt that says hi`, and press Enter. **Check:** when the agent asks whether it may create the file, its tile turns amber, and the bell at the top of the Layers panel shows **1**. If your agent writes the file without asking, ask it to run a shell command instead. Press the bell. It takes you to the tile that needs you. Answer the agent's question in its tile, for example by choosing **Yes**. **Check:** the tile stops being amber, the bell shows nothing, and `hello.txt` is in your project. ## What you did [#what-you-did] - You installed Hivemind and added your coding agent. - You started the agent in a frame bound to your project folder. - You saw it wait on you, in amber with a count on the bell, and you answered it. ## Next [#next] - [Run many agents at once](https://hivemind.griiken.com/guide/run-many-agents/), each in its own git worktree. - [Know who is waiting](https://hivemind.griiken.com/guide/know-who-is-waiting/): notifications, sounds and your phone. - Every key is on [Keyboard shortcuts](https://hivemind.griiken.com/guide/keyboard-shortcuts/). --- # Hivemind > A workspace your coding agents build and work in: run them side by side, add your own views, widgets and tools, and reach them from anywhere. Source: https://hivemind.griiken.com/guide/ Your agents build the workspace they work in. Hivemind runs your coding agents side by side, and they open views, add widgets and start other agents with the same `hive` command you use. # a folder with agent.yaml; checked before it is copied hive agents install owner/repo[/dir] [--ref tag] # from a GitHub repository # downloaded ones print what they run first: re-run with --yes hive agents validate # check a manifest the way an install would hive agents remove # removes the agent from this machine; it stays removed ``` A plugin is named by its id. Where two kinds have the same id, name it as `:`, as `hive plugins list` prints it (`view:board`). `enable`, `disable`, `set`, `reset`, choosing `workspaces`, and `hive config set plugins.…` are the person's to run. From an agent's tile or with a program's token they are refused (`PERSON_ONLY`, exit 6), saying what to ask the person to run. ## API tokens [#api-tokens] To let a program of yours drive a workspace. Guide: [Make an API token](https://hivemind.griiken.com/guide/api-tokens/). ```text hive grant create -w [--role agents] [--expires 30d] # a token for one program to drive these workspaces hive grant list hive grant revoke ``` ## Settings and upgrade [#settings-and-upgrade] To read and change settings, themes, the installed version and what it changed in your data. Guide: [Settings](https://hivemind.griiken.com/guide/settings/), [Update and roll back](https://hivemind.griiken.com/guide/update-and-roll-back/). ```text hive config path hive config get [dotted.path] hive config set '' hive theme list # the presets, and installed themes as @owner/package/theme hive theme use nord # a preset hive theme use @owner/kit/harbour # a theme: its files are copied beside settings.json hive theme revert # back to the look before the theme hive theme export f.json hive theme import f.json hive upgrade [--dev] hive migrations [--json] hive migrations restore [--json] ``` `hive migrations` lists what updates changed in this computer's data; `restore` puts it back as it was before a change. Guide: [When an update changes your data](https://hivemind.griiken.com/guide/data-updates/). ## Host [#host] To keep workspaces and agents running on a server. Guide: [Keep agents running while your laptop sleeps](https://hivemind.griiken.com/guide/host/). ```text hive host run # serve until stopped (what a service runs); one host per machine hive host status # whether it runs, as which device, where it is reached, its workspaces hive host stop # stop serving; the terminals keep running in the background process hive host pair # print six words, a link and a QR code for your app to enter hive host add # serve a folder on this machine as one of its workspaces (through the app when it runs) hive host install # run it as a service of yours (systemd): at boot, and again if it stops hive host uninstall # stop running it as a service; its terminals keep running ``` ## Sharing and people [#sharing-and-people] To invite people into a workspace and set their roles. Guide: [Share a workspace](https://hivemind.griiken.com/guide/multiplayer/). ```text hive share [--role view|edit|terminals] [--uses n] [--expires 7d] # print an invite link (default: edit, one person, 7 days) hive people requests # who is asking to join now, by number hive people allow [--role view|edit|terminals] # let them in, at their link's role or this one hive people deny # turn them away hive people list # who is on the list, their roles, who is here now hive people role # view, edit, terminals, or agents (only while they are here) hive people remove # take them off; their link stops working hive people rule [ask|invite] # ask (default): you answer each request; # invite: anyone with a valid link is let in at once hive join # join a workspace someone shared, waiting while they decide; # yours to run in a terminal of your own, not from an agent's tile hive network enrol-link [--data ] [--uses n] [--expires 7d] # on your network's server: a link that puts a device on it ``` ## Review comments [#review-comments] To read and answer comments left on an agent's changes. Guide: [Review an agent's changes](https://hivemind.griiken.com/guide/review/). ```text hive review list [--file src/x.ts] [--status open|resolved|all] hive review show # one comment with its replies hive review reply "fixed in 3f2c1a" hive review resolve [--summary "how it was addressed"] hive review reopen hive review watch [--timeout 300] [--file f] # wait for the next comment; exit 4 on timeout ``` ## Terminals that outlive the app [#terminals-that-outlive-the-app] To run terminals in the background process, which keeps them alive while the app is closed. Add `--machine ` to reach a saved machine. ```text hive daemon start|status|stop # the background process; stop keeps sessions as snapshots, restored on start hive ps [--machine build-box] # the sessions running hive run [--attach] [--cwd dir] [--id name] -- npm run dev # start one; with --attach, ctrl-b d detaches hive attach [--read-only] # view and type into one; a unique prefix of its id is enough hive kill # end it and its process ``` ## Machines [#machines] To add other computers over ssh. Guide: [Run agents on another computer](https://hivemind.griiken.com/guide/machines/). ```text hive machine add me@build-box [--label build] # also an ssh alias or ssh://me@build-box:2222; # puts this version's hive in ~/.hivemind/bin there hive machine list hive machine check build # reachable, platform, hive path and version hive machine rename build gpu-box hive machine disable build # kept, not connected; enable turns it back on hive machine remove build # forgotten; its sessions there keep running ``` ## Network and notifications [#network-and-notifications] To choose how your devices reach each other, and to get a push when an agent needs you. Guide: [Set up your own network server](https://hivemind.griiken.com/guide/self-hosting/), reference: [hive-net](https://hivemind.griiken.com/guide/hive-net/). ```text hive network show # which network, who signed it, its servers hive network use local # or a network link, or a signed profile's file hive network doctor # whether its relays answer this computer hive push set https://ntfy.sh/ [--events input.requested,turn.ended] # a plain-text POST when an agent on this machine needs you hive push status | test | off ``` ### `hive notifications` [#hive-notifications] The app's toasts, popups and sounds: the `notifications` settings ([Settings](https://hivemind.griiken.com/guide/settings/#notifications)). Guide: [Know who is waiting](https://hivemind.griiken.com/guide/know-who-is-waiting/#hear-it). ```text hive notifications show [--json] hive notifications set # sound on, sounds.done on, volume 0.4 (or 40%), dnd.start 22:30 hive notifications play needs|done|error [--json] # plays it in the app: {played, why?, pack?} hive notifications recent [--json] # the last 10 moments: agents, sound, popups ``` `set` and `play` are the person's: an agent is refused them (`PERSON_ONLY`, exit 6). `play` and `recent` need the app running; without it they exit 3 (`UNAVAILABLE`). `set` reloads the app. ## Packages (preview) [#packages-preview] To check a package before anything installs it. Installing packages is not built yet. ```text hive packages inspect # check a bundle and show what it would start, running nothing ``` --- # Environment variables > Every environment variable you can set to change how Hivemind, the hive command and the installer behave, and the ones Hivemind sets for you. Source: https://hivemind.griiken.com/guide/environment-variables/ This page lists the environment variables Hivemind reads, and the ones it sets in your tiles and programs. {` Using the Hivemind environment variables reference, tell me which of them are set here and what each changes. Do not change anything. 1. Run \`env | grep -E '^(HIVE|HIVEMIND)_'\`. Never print the value of \`HIVE_DRIVE_TOKEN\`: say only whether it is set. 2. For each variable, say what it does from the reference, and whether it was set by me or by Hivemind (inside a tile, Hivemind sets \`HIVEMIND_TILE\`). 3. If I asked to start the app a certain way (for example with no added tools), give me the exact command, such as \`HIVEMIND_SAFE_MODE=1 hivemind\`. At the end, list what you found in a table. `} ## The app and the hive command [#the-app-and-the-hive-command] | Variable | What it does | |---|---| | `HIVE_SETTINGS` | use this settings file instead of `~/.config/hivemind/settings.json` | | `HIVEMIND_APP_DATA` | use this folder for the app's data: its token and the sockets it serves | | `HIVEMIND_SAFE_MODE=1` | start with no added tool plugins loaded, after one broke the app | | `HIVEMIND_SHELL_ENV=0` | tiles get the app's environment as it is, without reading your login shell's | | `HIVEMIND_HIVE_NET` | the `hive-net` program to use, when it is not where the installer put it | | `HIVE_BIN` | the `hive` program to copy to a [machine](https://hivemind.griiken.com/guide/machines/), when it is not the one beside the app | | `HIVEMIND_PLUGIN_INDEX` | read the plugin catalogue from this address instead of HiveHub | | `HIVE_WHO` | the name the activity log gives your `hive` commands; else your git name or user name | ## The installer [#the-installer] Set these before you run `install.sh` or `install.ps1`. | Variable | What it does | |---|---| | `HIVEMIND_VERSION` | install this exact release, such as `v2026.10.3` | | `HIVEMIND_CHANNEL` | `stable` or `nightly` | | `HIVEMIND_APP_DIR` | where the app goes; default `~/.hivemind-app`, or `%LOCALAPPDATA%\hivemind` on Windows | | `HIVEMIND_BIN_DIR` | where the `hive` and `hivemind` links go; default `~/.local/bin` (Linux and macOS) | | `HIVEMIND_REPO` | the GitHub repository to download from; default `dip497/hivemind` | ## Programs that drive a workspace [#programs-that-drive-a-workspace] A program of yours reads these to reach a workspace. See [Connect and call](https://hivemind.griiken.com/guide/api-connect/). | Variable | What it holds | |---|---| | `HIVE_DRIVE_TOKEN` | the program's token. Keep it out of files git tracks. | | `HIVE_DRIVE_SOCK` | where to connect; else the app's own | | `HIVE_WORKSPACE` | which workspace to drive, when the token reaches several | A tool's service gets `HIVE_DRIVE_SOCK`, `HIVE_DRIVE_TOKEN` and `HIVE_WORKSPACES` (the folders it may drive, separated as in `PATH`). See [Write a tool](https://hivemind.griiken.com/guide/tool-plugins/#a-service-that-keeps-running). ## Set by Hivemind in an agent's tile [#set-by-hivemind-in-an-agents-tile] Hivemind sets these for an agent it can drive. Read them; do not set them yourself. | Variable | What it holds | |---|---| | `HIVEMIND_TILE` | the id of the tile an agent runs in. If it is set, the agent can drive the canvas with `hive ctl`. | | `HIVE_AGENT_ID` | the agent's id, which signs what it writes in the activity log | | `HIVEMIND_GUIDE` | the command that prints how to drive other agents here: `hive guide agents` | | `HIVE_DRIVE_SOCK` | where `hive ctl` connects | The variables for your own network server's Docker setup are on [Set up your own network server](https://hivemind.griiken.com/guide/self-hosting/). --- # Glossary > One word per thing: what each Hivemind word means, in a sentence. Source: https://hivemind.griiken.com/guide/glossary/ These docs use one word for each thing, the word the app shows. {` Read the Hivemind glossary in the reference below. Then read the file or text I point you to about Hivemind (a README, notes, an issue). List each word that means something in the glossary but is not the glossary's word (for example "offer" for invite, "daemon" for background process, "board" for canvas), with the line it is on and the word to use instead. Do not change the file until I say which ones to change. `} ## The workspace [#the-workspace] | Word | What it is | |---|---| | **Workspace** | One project folder and everything open for it. | | **Canvas** | The view that lays your frames, tiles and widgets out on one endless surface. The app also calls it the **board**, as in **Can edit board**. | | **Frame** | A named area bound to one folder: the project, a git worktree, or a folder on another computer. Every tile in it starts in that folder. | | **Tile** | One thing in a frame: an agent, a terminal, the Code tile, a browser or a tool. | | **Layers panel** | The list beside the canvas of your projects, frames and tiles. ⌘B / Ctrl+B shows or hides it. | | **Bell** | The count at the top of the Layers panel of agents waiting on you. Press it to jump to the next one. | | **View** | A way of drawing the workspace: **Canvas**, **Windows**, or one you install. ⌘E / Ctrl+E switches. | | **Worktree** | A second checkout of the same git repository in its own folder, on its own branch, so two agents never edit the same files. | | **Issue** | A piece of work written as a Markdown file in `.hivemind/`, which you and your agents read and update. | ## Agents [#agents] | Word | What it is | |---|---| | **Agent** | A coding agent's own program (Claude Code, Codex, opencode, …) running in a tile, which Hivemind reads and answers. | | **Needs you** | An agent waiting for a person: a permission question, a choice or a plan to approve. Its tile turns amber, with a triangle, and the app tells you. A supervised worker waiting for its lead (**approval?**) is amber too, but its lead answers it, so nothing tells you. | | **Working** | An agent busy on its task. | | **Done** | An agent that finished replying since you last looked: a dot on its row. Notifications call it **Finished**. | | **Idle** | An agent at its prompt, waiting for a task. | | **Exited** | The agent's program has stopped. Red when it failed. | | **Asleep** | An agent put to sleep: its program stopped, its conversation kept, ready to resume. | | **Lead** | The agent, or you in a terminal, that starts other agents with `hive ctl`, sends them work and collects their replies. | | **Worker** | An agent a lead started to do one piece of the work. | | **Supervise** | A worker's permission questions go to the lead's inbox instead of its own screen. | | **Channel** | Which releases you follow: **stable**, or **nightly** builds. | | **Background process** | The `hive` process that keeps terminals and agents running while the app is closed or upgrading. | ## Plugins [#plugins] | Word | What it is | |---|---| | **Plugin** | Something you add to Hivemind: an agent, a view, a widget or a tool. | | **Widget** | A small live card on the canvas, drawn by a few lines of code. | | **Tool** | A plugin that adds a kind of tile, such as a pull request panel. It runs with your access, so it starts switched off. | | **HiveHub** | The catalogue Hivemind installs agents and plugins from. See [What HiveHub is](https://hivemind.griiken.com/guide/hivehub/). | ## Other computers and people [#other-computers-and-people] | Word | What it is | |---|---| | **Machine** | Another computer you added over ssh. Frames, terminals and agents can run on it. | | **Host** | A server that keeps your workspaces and agents running while your laptop sleeps. | | **Network server** | A server you run (`hive-net`) so your devices and guests reach each other across networks. It also serves the phone page. | | **Invite** | A link, QR code or code that lets one device or person in. | | **Role** | What a person or a program may do: `view`, `edit`, `terminals` or `agents`. | | **Token** | A secret a program of yours uses to drive a workspace, with one role. | --- # hive-net reference > Every hive-net serve option, port, certificate setting, push key and file to back up, for your own network server. Source: https://hivemind.griiken.com/guide/hive-net/ `hive-net` is the program that runs your [network server](https://hivemind.griiken.com/guide/self-hosting/). It comes with Hivemind, beside `hive`. This page lists what it takes. {`Using the hive-net reference, write the \`hive-net serve\` command (or the docker compose command from \`infra/\`) for my network server. Ask me first: does the server have a public DNS name, do I have my own certificate or a proxy that ends TLS, which ports may it open, and should anyone be able to use it or only my devices. Show the command, and explain each option in one line. List the ports I must open in my firewall and the files in its data folder I must back up. Do not run anything.`} ## Roles [#roles] `hive-net serve` runs up to four roles on one port. `--all` runs all four. | Flag | Role | Does | |---|---|---| | `--relay` | relay | Carries traffic between devices that cannot reach each other directly. The traffic stays encrypted end to end. | | `--lookup` | lookup | Lets devices find each other, and the device that hosts a workspace, by id. | | `--access` | access | Decides who may use the relay. | | `--push` | push | Tells your phones when an agent needs you, through UnifiedPush, Apple or Google. | ## Serve options [#serve-options] | Option | Default | Does | |---|---|---| | `--data ` | none | Keeps every role's state. | | `--url ` | from `--domain` or `--bind` | How devices reach this server, when that is not what `--domain` or `--bind` says. With it, the network's link is printed. | | `--name ` | none | Names the network. | | `--bind ` | port 3340 on every address, 443 with HTTPS | Where it listens. | | `--domain ` | none | Gets a certificate from Let's Encrypt for this name. | | `--contact ` | none | Your email address for Let's Encrypt. | | `--cert ` `--key ` | none | Your own certificate. Both files are read again every hour. | | `--http-bind ` | port 80 | With HTTPS, the captive-portal check. | | `--quic-bind ` | port 7842 | With HTTPS, address discovery, which helps devices connect directly. | | `--policy closed\|open-pow` | `closed` | `closed` lets in only devices you enrol and guests they vouch for. `open-pow` lets in anyone who solves a proof-of-work puzzle. | | `--pow-bits ` | 20 | How hard the puzzle is, with `open-pow`. | | `--admin-id ` | the admin key in `--data` | The network admin's public key. | | `--access-url ` | none | A relay without the access role asks this access service instead. | | `--access-cache ` | 300 | How long a relay remembers a yes from that service. | | `--dns-bind ` | none | The lookup also answers DNS there. | | `--lookup-limit per-address\|off` | `per-address` | Rate limit on lookups. | | `--phone` | off | Serves the [phone page](https://hivemind.griiken.com/guide/phone/) this hive-net carries, its own release's, at `/phone/`. | | `--phone-folder ` | none | Serves a phone page built here (`crates/hive-web/build.sh`) instead. | | `--views ` | none | Serves the phone page's views on that port, an origin of their own. | | `--push-allow ` | none | Also delivers push to UnifiedPush servers on this network. Repeat it for each. | | `--apns-key <.p8>` `--apns-key-id` `--apns-team` `--apns-topic` | none | Push to iPhones through Apple, for an app build you sign yourself. | | `--fcm ` | none | Push to Android through Google, for an app build you sign yourself. | ## Ports [#ports] | Port | For | |---|---| | 443/tcp, or 3340/tcp without a certificate (`--bind`) | relay, lookup, access and push | | 80/tcp (`--http-bind`) | the captive-portal check, with HTTPS | | 7842/udp (`--quic-bind`) | address discovery | | 3341 or 8443 (`--views`) | the phone page's views. The Docker files use 3341 inside a building and 8443 with a public name. | ## Certificates [#certificates] | You have | Use | |---|---| | A DNS name pointing at the server | `--domain` alone. Let's Encrypt issues and renews it. Port 443 must be reachable. | | Your own certificate | `--cert fullchain.pem --key privkey.pem` | | A proxy that ends TLS | Serve plain HTTP and set `--url https://…`. The proxy must pass WebSockets. | ## Enrol and remove devices [#enrol-and-remove-devices] | Command | Does | |---|---| | `hive network enrol-link --data --uses --expires