bots-garden/sidekickpublic⑂ Fork 0
⑂ feature/mermaid-diagram
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/sidekick.git
git clone ssh://git@rickub.com/bots-garden/sidekick.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

🛟 Updated. ed12075 · on feature/mermaid-diagram · k33g · yesterday
README.md · 132 lines · 10.8 KBmarkdown
Blame HistoryOpen raw

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.

  1. Navigate to the directory:

    cd mm-web-client
    
  2. 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 (default 127.0.0.1: only this machine can connect). In a VM or a container, use -host 0.0.0.0 so 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 the SIDEKICK_TOKEN environment variable: a flag is visible in the process list.
  • -allow-host: host names (comma-separated) the browser may use to reach sidekick, besides localhost and IP addresses — e.g. -allow-host my-vm.local. Any other name is refused (protection against DNS rebinding).
  • -port: HTTP port (default 6767 — 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 editing web/: a reload shows the changes without rebuilding).
  • -version: print the version and exit: the release tag (from release.env) for a release build, otherwise the commit id (-dirty if the working tree had changes), or dev under go run.

The agent's logs (banner, warnings, [acp] trail) are printed on the server's stderr.

Copying an answer

Each answer of the agent ends with two buttons: Copy puts its text on the clipboard as the Markdown the model wrote, Copy formatted as rich text (headings, lists, code — for a document or an e-mail), with the Markdown as its plain-text version. Only what the model wrote is copied, not its thoughts or its tool calls. Code blocks keep their own Copy button. Over plain HTTP from another machine (-host 0.0.0.0), the browser gives no clipboard API: both buttons then copy the Markdown.

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;
  • Markdown (.md), AsciiDoc (.adoc, .asciidoc, .asc) and HTML (.html, .htm) files have a Preview button next to Save (Ctrl/Cmd+Shift+V): the tab shows the rendered file instead of its source, and Source goes back. The preview renders what the editor holds, unsaved changes included, and follows it as it changes (the agent's edits too). Images next to the document are shown, links to other files of the project open them in a tab, anchors scroll. Mermaid diagrams are drawn: a ```mermaid block in Markdown; in AsciiDoc a [source,mermaid] listing or the [mermaid] block of asciidoctor-diagram (listing or literal). A diagram with a syntax error shows Mermaid's message in its place, and the diagrams follow the light/dark theme. Each tab remembers its mode;
  • images open as pictures: PNG, JPEG, GIF, WebP, AVIF, BMP and ICO in a tab that shows the file (with its size in pixels), SVG rendered first with Source to edit it — the picture follows the edits. draw.io diagrams (.drawio, .dio) open rendered by the official viewer (pages, layers, zoom), Source shows their XML and the diagram follows the edits; .drawio.svg and .drawio.png exports are shown as the pictures they are;
  • +📄 / +📁 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.md becomes spec-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 ACP resource_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, Asciidoctor.js, Mermaid, the draw.io viewer) 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.

Previewed files are untrusted too. Markdown and AsciiDoc go through the same filter (their ids are prefixed with user-content-, so a heading cannot take the id of one of the page's elements); AsciiDoc is converted in secure mode (include:: reads nothing). An HTML file is shown in a frame sandboxed with every restriction — its scripts do not run, it has no access to sidekick — and under the page's CSP, so it loads nothing from the network: its external styles, scripts and images are missing from the preview. The images of a preview come from /api/raw, which only serves image files (by extension) from the working directory, with a sandboxing CSP of their own (an SVG opened directly cannot run a script). An SVG in the editor is shown as an <img>, where its scripts never run.

Mermaid runs with securityLevel: 'strict': it sanitises labels itself and disables click handlers, the CSP stops what could get through, and each diagram's styles are scoped to its own id.

The draw.io viewer runs in the page: it sanitises the HTML of labels itself, and the CSP stops what could get through — no inline script, event handler or eval runs, nothing loads from another site. Its resources, which would come from viewer.diagrams.net, point into the binary instead: MathJax is not embedded (a formula shows as its source), and the few shape libraries the viewer fetches on demand are missing.

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
121
122
123
124
125
126
127
128
129
130
131
132
# 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](https://go.dev/) installed on your system.

1. Navigate to the directory:
   ```bash
   cd mm-web-client
   ```

2. Download dependencies:
   ```bash
   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`:

```bash
go run ./cmd/server [-port <port>] [-cwd <dir>] [-web <dir>] <agent_path> [agent_args...]
```

- `-host`: address to listen on (default `127.0.0.1`: only this machine can connect). In a VM or a container, use `-host 0.0.0.0` so 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 the `SIDEKICK_TOKEN` environment variable: a flag is visible in the process list.
- `-allow-host`: host names (comma-separated) the browser may use to reach sidekick, besides `localhost` and IP addresses — e.g. `-allow-host my-vm.local`. Any other name is refused (protection against DNS rebinding).
- `-port`: HTTP port (default `6767` — 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 editing `web/`: a reload shows the changes without rebuilding).
- `-version`: print the version and exit: the release tag (from `release.env`) for a release build, otherwise the commit id (`-dirty` if the working tree had changes), or `dev` under `go run`.

The agent's logs (banner, warnings, `[acp]` trail) are printed on the server's stderr.

### Copying an answer

Each answer of the agent ends with two buttons: **Copy** puts its text on the clipboard as the Markdown the model wrote, **Copy formatted** as rich text (headings, lists, code — for a document or an e-mail), with the Markdown as its plain-text version. Only what the model wrote is copied, not its thoughts or its tool calls. Code blocks keep their own **Copy** button. Over plain HTTP from another machine (`-host 0.0.0.0`), the browser gives no clipboard API: both buttons then copy the Markdown.

### 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:

```bash
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](https://microsoft.github.io/monaco-editor/) tab; **Ctrl/Cmd+S** or **Save** writes it back;
- Markdown (`.md`), AsciiDoc (`.adoc`, `.asciidoc`, `.asc`) and HTML (`.html`, `.htm`) files have a **Preview** button next to **Save** (**Ctrl/Cmd+Shift+V**): the tab shows the rendered file instead of its source, and **Source** goes back. The preview renders what the editor holds, unsaved changes included, and follows it as it changes (the agent's edits too). Images next to the document are shown, links to other files of the project open them in a tab, anchors scroll. [Mermaid](https://mermaid.js.org) diagrams are drawn: a ` ```mermaid ` block in Markdown; in AsciiDoc a `[source,mermaid]` listing or the `[mermaid]` block of asciidoctor-diagram (listing or literal). A diagram with a syntax error shows Mermaid's message in its place, and the diagrams follow the light/dark theme. Each tab remembers its mode;
- images open as pictures: PNG, JPEG, GIF, WebP, AVIF, BMP and ICO in a tab that shows the file (with its size in pixels), SVG rendered first with **Source** to edit it — the picture follows the edits. [draw.io](https://www.drawio.com) diagrams (`.drawio`, `.dio`) open rendered by the official viewer (pages, layers, zoom), **Source** shows their XML and the diagram follows the edits; `.drawio.svg` and `.drawio.png` exports are shown as the pictures they are;
- **+📄** / **+📁** 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.md` becomes `spec-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 ACP `resource_link`s (`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](https://github.com/material-extensions/vscode-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, Asciidoctor.js, Mermaid, the draw.io viewer) 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.

Previewed files are untrusted too. Markdown and AsciiDoc go through the same filter (their ids are prefixed with `user-content-`, so a heading cannot take the id of one of the page's elements); AsciiDoc is converted in `secure` mode (`include::` reads nothing). An HTML file is shown in a frame sandboxed with every restriction — its scripts do not run, it has no access to sidekick — and under the page's CSP, so it loads nothing from the network: its external styles, scripts and images are missing from the preview. The images of a preview come from `/api/raw`, which only serves image files (by extension) from the working directory, with a sandboxing CSP of their own (an SVG opened directly cannot run a script). An SVG in the editor is shown as an `<img>`, where its scripts never run.

Mermaid runs with `securityLevel: 'strict'`: it sanitises labels itself and disables click handlers, the CSP stops what could get through, and each diagram's styles are scoped to its own id.

The draw.io viewer runs in the page: it sanitises the HTML of labels itself, and the CSP stops what could get through — no inline script, event handler or `eval` runs, nothing loads from another site. Its resources, which would come from viewer.diagrams.net, point into the binary instead: MathJax is not embedded (a formula shows as its source), and the few shape libraries the viewer fetches on demand are missing.

### Examples

**1. Using the default port (6767):**
```bash
go run ./cmd/server mm --config config.yaml
```

**2. Specifying a different port (e.g., 9000):**
```bash
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:**
```bash
go run ./cmd/server -port 9000 mm --config config.yaml
```

**4. If you are pointing to a specific binary path:**
```bash
go run ./cmd/server -port 9000 ./path/to/mm --config ./config.yaml
```

### Building the binary

To compile the server into an executable:

```bash
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>`.