This repository has no description
drawgent docs development.md
9.4 kB
Markdown
at main

drawgent › Documentation

Development #

Building #

npm ci && npm run build      # editor, panel and renderer pages -> dist/ (embedded into the binary)
cargo build --release        # or: cargo install --path .

For release builds, nix develop -c make … provides the toolchain; rustup plus cargo-zigbuild also works.

Command Output
make musl / make dist static Linux x86_64 binary / tarball (MUSL_TARGET=aarch64-unknown-linux-musl for ARM)
make darwin / make dist-darwin macOS universal binary (Intel and Apple Silicon, macOS 13 or later) / tarball. DARWIN_TARGET=aarch64-apple-darwin (or x86_64-apple-darwin) builds one architecture
make licenses regenerate THIRD_PARTY_LICENSES.md. make dist fails while it's out of date
make sign-extension sign the Firefox extension (see below)
  • macOS: the build is cross-compiled from Linux with zig and no Apple SDK; drawgent links only libSystem, libiconv and libcharset. The arm64 slice is ad-hoc signed by the linker but not notarized. It hasn't been tested on a real Mac yet.
  • Small machines: use JOBS=1. One dependency, chromiumoxide_cdp, needs a lot of memory to compile.

Code layout #

src/, in Rust, has one folder per role. Dependencies only point down the list.

Path
main.rs CLI parsing and dispatch
cli/ setup.rs; attach.rs (session discovery, picker); daemon.rs (up -d, status, down); firefox.rs (setup firefox); up.rs (up / serve, --diagram); check.rs; remote.rs
sync/ hub.rs (routing, notes, chat log); server.rs (HTTP, WebSocket, REST); room.rs (Excalidraw room client, peers' laser strokes); rooms.rs (rooms joined at runtime)
agents/ mod.rs (queue, workers); acp.rs (ACP driver: new and forked sessions); opencode.rs, codex.rs (live sessions)
bridge/ ACP bridges built into the binary: claude.rs (Claude Code stream-json), codex.rs (codex app-server)
canvas/ scene.rs (store, edits); boards.rs; diagram.rs (.excalidraw files); build.rs (baselines, semantic diff); lint.rs; autolayout.rs; gesture.rs (gestures, delete impact, poll options); history.rs (undo); el.rs, geometry.rs, fractional.rs. It doesn't depend on the renderer: it asks a Layout
code/ mod.rs (workspace files, search, code links); repomap.rs
render/ mod.rs (Chrome over CDP, implements Layout); chrome.rs (find or install Chrome)
config.rs, mcp.rs, legal.rs config and paths; the MCP server (a REST client); license notices

web/:

  • the editor: main.jsx, chat.jsx, boards.jsx, code.jsx, cards.jsx, build.jsx, gestures.jsx, laser.js, laserpoint.jsx;
  • the panel-only view: panel.jsx;
  • the renderer page: render.jsx.

extension/: the Firefox extension, in plain JS with no build step. It only uses drawgent's REST API and panel view.

Tests #

cargo test

The end-to-end suites are in scripts/. Most use fake agents: fake Claude, Codex and ACP CLIs. They also use a fake excalidraw-room server, so they run offline:

Script Covers
smoke.mjs [url], e2e-browser.mjs [url] a chat turn and an AGENT: note against a running drawgent, in a real browser
claude-bridge-e2e.mjs, codex-bridge-e2e.mjs the built-in bridges: streaming, permission prompts, Stop, usage
efficiency-e2e.mjs check_layout, add_graph, cropped screenshots, incremental get_scene, token usage
gestures-e2e.mjs gestures, the poll, make_space, delete with reconnect, undo
boards-e2e.mjs move, copy, split, folder mode, switching boards
diagram-e2e.mjs --diagram files: clean output, changes from git flow back
code-e2e.mjs, pointing-e2e.mjs code links, the Code tab, drawgent check --fix; tree, Ctrl+P, laser on code, basket, code cards, repo map
room-e2e.mjs a fresh excalidraw.com room, both directions (needs the network)
remote-room-e2e.mjs self-hosted rooms: token, peers storage, leaving when alone
extension-e2e.mjs the extension's sidebar: joining at runtime, panel view, laser from the document, WebSocket origin check
daemon-e2e.mjs up -d, status, down, canvas only
firefox-setup-e2e.mjs setup firefox with a fake Firefox: signed package, --from-source, --xpi
laser-e2e.mjs, build-e2e.mjs with a real agent (needs setup claude): a laser zone edited by the agent; Build what I drew

CI and releases #

CI runs on Tangled's spindle. The workflows are in .tangled/workflows/: microvm engine, NixOS image, our own flake.nix dev shell. Both call scripts you can run locally:

Workflow Trigger Runs
ci.yml push to main, pull requests to main, manual scripts/ci.sh: cargo test, then the offline e2e suites, each with a throwaway HOME
release-<os>-<arch>.yml a v* tag one per target, in parallel (Linux x86_64 and arm64, macOS arm64 and x86_64): scripts/release.sh build <tag> <target>, then publish. The tarball and its .sha256 are attached to the tag
nix develop -c scripts/ci.sh                  # what CI runs (needs Chrome or Chromium)
nix develop -c scripts/ci.sh gestures-e2e     # some suites only

Cutting a release:

  1. Bump version in Cargo.toml and package.json.
  2. Commit.
  3. Run git tag -a v0.2.1 -m v0.2.1. The tag must be annotated: Tangled attaches artifacts to tag objects.
  4. Run git push origin main v0.2.1.

The release workflows then build and attach the files. A single job must fit the spindle's time limit, which is why each target gets its own workflow. It checks that the tag matches Cargo.toml and that each file is under Tangled's 50 MiB artifact limit. Re-running it skips files that are already attached.

Publishing needs the repo secret ATP_APP_PASSWORD: an app password of the repo owner's account, added under Settings → Secrets. The script finds the account's PDS from its DID and logs in there.

The browser extension #

Most of what the sidebar shows is drawgent's panel page, not the extension. You can work on it without signing or reinstalling anything:

  • The chat panel (web/panel.jsx, web/chat.jsx, web/chat.css) is served at /?view=panel&board=<board>. Open it in any tab at sidebar size, e.g. with Firefox's Responsive Design Mode (Ctrl+Shift+M). After a change, run npm run build, restart drawgent and reload the tab.
  • node scripts/panel-preview.mjs sets it all up. It starts a drawgent with a fake agent and a fake room whose "user" chats and draws with the laser. It then takes screenshots of the panel at 320, 400 and 560 px (chat, gesture card, poll) and prints the height of each part. --keep leaves it running and prints the URL.
  • The sidebar itself (sidebar.*, drawgent.js, background.js): go to about:debugging#/runtime/this-firefox → Load Temporary Add-on… → extension/manifest.json. Reload picks up edits, Inspect opens its devtools. Alternatives:
    • npx web-ext run --source-dir extension reloads on save in a fresh profile;
    • drawgent setup firefox --from-source installs the current sources.

Releasing a version #

  1. Bump version in extension/manifest.json. Mozilla signs each version only once.
  2. Run make sign-extension with the addons.mozilla.org API keys in AMO_JWT_ISSUER and AMO_JWT_SECRET. It signs the extension as unlisted and writes extension/signed/drawgent-firefox-<version>.xpi. It also records the package, with its SHA-256, in extension/updates.json.
  3. Commit and push both. Installed extensions update from updates.json, and the next drawgent build embeds the package for setup firefox.

The extension ID is drawgent-ext@2kmail.net. It never changes.

Regenerating the docs images #

The images in docs/img/ come from a real session. The script runs drawgent with your configured agent on a throwaway clone of this repository. It drives the UI in headless Chrome, records the screen, and makes 3×-speed GIFs with ffmpeg:

npm run build && cargo build --release
node scripts/docs-capture.mjs                               # every scene (uses real tokens)
node scripts/docs-capture.mjs --only laser,code --scene saved-scene.json

The scenes are architecture, note, laser, gestures, code, repomap and panel. --scene starts from a saved scene, so later scenes can be redone without the long architecture run. It needs Chrome, ffmpeg and a set-up agent.

License #

drawgent is GPL-3.0-or-later. The third-party work it bundles is under GPL-compatible licenses, listed in full in THIRD_PARTY_LICENSES.md:

  • Rust crates and npm packages: MIT, Apache-2.0, ISC, BSD, Zlib, Unicode-3.0, CDLA-Permissive-2.0, MPL-2.0 OR Apache-2.0, CC0, Unlicense and 0BSD;
  • Excalidraw's fonts: OFL 1.1 and MIT. Liberation Sans is left out: its license is GPLv2 with a font exception;
  • the drawing guide, adapted from excalidraw-mcp (MIT).

After changing dependencies, run make licenses. The agents and Chrome aren't part of drawgent: they run as separate programs from your own install.