mm-web-client
A web client for the Mini-Me ACP agent, providing a fancy interface similar to Claude Desktop.
Installation
Ensure you have Go installed on your system.
-
Navigate to the directory:
cd mm-web-client -
Download dependencies:
go mod download
Usage
The server acts as a bridge between the web interface and the Mini-Me agent process.
Running the server
You can run the server directly using go run:
go run ./cmd/server [-port <port>] [-cwd <dir>] [-web <dir>] <agent_path> [agent_args...]
-host: address to listen on (default127.0.0.1: only this machine can connect). In a VM or a container, use-host 0.0.0.0so the host machine can reach it (port forwarding, or the VM's IP) — anyone else who can reach that address can too.-token: the access token (see below). Prefer theSIDEKICK_TOKENenvironment variable: a flag is visible in the process list.-allow-host: host names (comma-separated) the browser may use to reach sidekick, besideslocalhostand IP addresses — e.g.-allow-host my-vm.local. Any other name is refused (protection against DNS rebinding).-port: HTTP port (default6767— not 8080, which is llama-server's default port).-cwd: the project directory the agent works in (default: the directory the server is started from). ACP requires an absolute path: this is where the agent runs its commands and stores its sessions (.mm/sessions).-web: serve the web UI from this directory instead of the one embedded in the binary (useful while editingweb/: a reload shows the changes without rebuilding).-version: print the version and exit: the release tag (fromrelease.env) for a release build, otherwise the commit id (-dirtyif the working tree had changes), ordevundergo run.
The agent's logs (banner, warnings, [acp] trail) are printed on the server's stderr.
Context and tokens
Next to the model, the header shows the context window. When the agent reports its usage (ACP usage_update, experimental), a bar shows how full it is (orange from 70%, red from 90%) with the tokens in context and the session's cost if any; otherwise only the window size from the agent's banner (ctx 8.2k). Hovering it gives the details. When the agent returns token counts with its answer (usage in the prompt response), each turn ends with a line such as ↑ 4.0k in · ↓ 500 out · 150 thinking tokens. Nothing is estimated: what the agent does not send is not shown.
Access token
sidekick gives a shell, the agent and the files of the working directory to whoever talks to it, so every request needs a token. At start-up it prints the URL to open:
🔑 Open http://localhost:6767/?token=q3Xf9…kL2w
Opening it stores the token in a cookie (HttpOnly, SameSite=Strict) and removes it from the address bar; reloads and new tabs then work as long as the browser keeps the session. Without the cookie, everything is refused (401), static files and WebSockets included.
A new token is made at each start: open the new URL after a restart (tabs already open reconnect by themselves once it is opened). To keep the same URL across restarts, set it yourself:
export SIDEKICK_TOKEN="$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')"
Files, editor and terminal
📁 Files (in the header) shows a tree of the agent's working directory (-cwd):
- clicking a file opens it in a Monaco tab; Ctrl/Cmd+S or Save writes it back;
- +📄 / +📁 in the tree's header, or a right click, create a file or a folder (in the selected folder); a right click also offers Rename and Delete. With the tree focused, F2 renames and Delete deletes the selected entry. Open tabs follow a rename;
- after each agent tool call (and each command run in the terminal), the tree and the tabs without local changes are reloaded from disk. If a file you are editing was changed on disk meanwhile, saving asks before overwriting it.
Drag and drop:
- files and folders dropped from your computer onto the tree are copied into the folder under the pointer (or at the top); an existing file is only replaced after confirmation;
- a row of the tree dragged onto a folder moves it there (open tabs follow);
- files dropped onto the chat — or picked with 📎 — are copied into
.sidekick/uploads/(never replacing a file:spec.mdbecomesspec-1.md) and attached to the next message; a row dragged from the tree onto the chat is attached as is. Attachments are sent as ACPresource_links (file://URIs) and listed in the message text. Uploads are limited to 200 MB per file.
⌨️ Terminal opens a shell ($SHELL, as a login shell) in the working directory. Hiding the panel keeps it running; when it exits, Enter starts a new one. Not available on Windows.
Only the working directory is reachable from the tree and the editor: ../ and symlinks pointing outside it are refused. Binary files and files over 2 MB are not opened; .git is not listed. The panels can be resized by dragging their edges.
The tree uses the icons of VS Code's Material Icon Theme (MIT), with the same rules: by file name, else by extension, folders by name, with their light-theme variants.
All the libraries the web UI uses (Tailwind, marked, highlight.js, Monaco, xterm.js, the Material icons) are embedded in the binary, in web/vendor/: the page loads nothing from the network, and works offline.
./vendor.sh writes web/vendor/ from the versions pinned at its top. To update a library: ./vendor.sh --outdated lists the pinned and published versions; change the version in the script (its comments say which updates need more than that), run ./vendor.sh, check the UI, commit web/vendor/.
Security: sidekick gives a shell, the agent and the files of the working directory to whoever talks to it, hence the access token on every request. By default it only listens on 127.0.0.1; with -host 0.0.0.0, anyone who can reach the address can try (a warning is printed), and the token travels in clear over HTTP: on a shared network, keep 127.0.0.1 in the VM and use an SSH tunnel (ssh -L 6767:localhost:6767 my-vm). Requests must name the server as localhost, an IP address or a -allow-host name (protection against DNS rebinding), and the WebSockets only accept pages served by sidekick itself.
What the agent writes is untrusted (it may repeat HTML read in a file or a web page): the chat filters it with DOMPurify — no scripts, event handlers, javascript: links, styles, frames or forms; links open in a new tab. Behind that, a Content-Security-Policy only lets the page run the scripts sidekick serves and load nothing from elsewhere (so an image URL in a message cannot carry data out), and the page cannot be shown in another site's frame.
Examples
1. Using the default port (6767):
go run ./cmd/server mm --config config.yaml
2. Specifying a different port (e.g., 9000):
go run ./cmd/server -port 9000 mm --config config.yaml
3. If mm is in your PATH and you want to use a config file in the current directory:
go run ./cmd/server -port 9000 mm --config config.yaml
4. If you are pointing to a specific binary path:
go run ./cmd/server -port 9000 ./path/to/mm --config ./config.yaml
Building the binary
To compile the server into an executable:
go build -o mm-web-client ./cmd/server
./mm-web-client [-port <port>] <agent_path> [agent_args...]
Once running, the web interface will be available at http://localhost:<port>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
|