Build Skribbl

KINDAreplaces $8.25/mosaves $99/yrback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A desktop canvas of live terminals where the canvas is the easy part, and the difficult parts are keeping a dozen child processes alive across restarts, learning an agent's state from the agent rather than from its output, and metering spend accurately enough to act on.

estimated effort multi-daythe files for this build are in the project pack

TerminalsA real shell per node through a pseudo-terminal, rendered by a terminal emulatorCanvasA pan and zoom node graph with terminals as nodes and links as recorded relationshipsDurabilityEach node runs inside a terminal multiplexer session named by node idStatusHook and event channels the agent itself exposes, never scraped outputMeteringFour token counters from the agent's own accounting, priced from a dated tableRuntimeA desktop application with native pseudo-terminal bindings

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the desktop application and its build.

    Get it nodejs.org, or nvm install 22. open ↗

    Verify node --version prints v22 or higher

  2. installfree

    Why The pseudo-terminal bindings compile against your desktop runtime's version, and this is the first failure on every fresh machine.

    Get it Your platform's compiler and build tools, then rebuild the bindings for the runtime version you ship.

    Verify A shell spawns in a node after a clean install

  3. installfree

    Why Session survival across crashes and restarts comes entirely from it, and without it every relaunch kills every agent.

    Get it Install it from your package manager and confirm a session survives closing the terminal that started it. open ↗

    Verify A detached session is still there after its terminal closes

  4. the agent's own subscription or per-token billing

    Why Status and usage come from the agent's own channels, and each agent exposes them differently or not at all, which decides what the canvas can honestly show.

    Get it Install the agent, authenticate it, and read its hooks and status line documentation before writing phase three. open ↗

    Verify A hook fires and writes an event on a test prompt

  5. decidefree

    Why The four counters are priced differently and the rates change, so the table needs a checked-on date shown beside every total.

    Get it Copy the current per-token rates for each model you run, including the cache read and cache write multipliers, and record the date.

    Verify The table has four rates per model and a date

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- nodes(id, title, cwd, agent_kind, x, y, w, h, mux_session, created_at)
- links(id, from_node_id, to_node_id, direction, label) · recorded relationships, no message passing
- sessions(node_id, mux_session, attached_at, alive, last_checked_at) · alive is observed, never assumed
- status_events(id, node_id, source, kind, at, payload_json) · source is hook or none; kind is waiting_for_permission, waiting_for_input, working, finished or unknown
- usage(id, node_id, at, input_tokens, cache_write_tokens, cache_read_tokens, output_tokens, model, source)
- price_table(model, input_minor_per_million, cache_write_minor_per_million, cache_read_minor_per_million, output_minor_per_million, checked_on)
- A status event records its source, so the canvas renders unknown honestly where no hook has fired rather than inferring a state from when the terminal last printed something.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
MUX_BINrequiredtmuxThe multiplexer binary. Sessions are named by node id.
HOOK_SOCKET_PATHrequired~/.local/share/canvas/hooks.sockWhere installed hooks write events. The canvas reads, never guesses.
STATUS_FILE_DIRrequired~/.local/share/canvas/statusPer-session usage written by the agent's status line command.
PRICE_TABLE_PATHrequired./config/prices.jsonFour rates per model and a checked-on date, shown beside totals.
LAYOUT_PATHrequired~/.local/share/canvas/layout.jsonNode positions and links, written atomically.
SCROLLBACK_LINESrequired5000Per node. Twelve unbounded buffers is how the canvas dies.
MAX_NODESrequired16Above this the canvas refuses with the reason rather than degrading quietly.
INFER_STATUSrequiredneverPresent as a constant. A guess is worse than showing nothing.

The build, in order

  1. A real shell in a node

    Each node is a real process that resizes, scrolls and dies cleanly.

    1. Full screen programs draw for the size the pty reports, not the size you see.

      Files src/main/pty.ts

    2. An invisible agent is still a billed agent.

      Files src/main/pty.tstests/no-orphans.test.ts

    3. Twelve unbounded buffers is how the canvas dies at four in the afternoon.

      Files src/renderer/terminal.tsx

    done when · tick each as it passes
    watch out
    • Forgetting to tell the pty about a resize means every full screen program draws for the wrong size and the agent's own interface wraps into garbage, and closing a node without killing its process group leaves agents running invisibly and spending money. Resize the pty on every node resize, and kill the group rather than the shell.
  2. Sessions that outlive the window

    A crash or a restart reattaches to running agents rather than killing them.

    1. The session name is the node id, so a relaunch finds it without a lookup table.

      Files src/main/mux.ts

    2. A fresh shell in an old node's place is a lie with a cursor.

      Files src/main/mux.tstests/dead-session.test.ts

    3. A crash during a save should cost nothing.

      Files src/main/layout.ts

    done when · tick each as it passes
    watch out
    • Restoring the layout from a file and spawning fresh shells looks exactly like persistence until you notice the agent that was halfway through a refactor is gone, and you notice an hour later. Attach to the named session, and if it no longer exists say so on the node.
  3. Status from the agent, or unknown

    A node shows waiting, working, finished or unknown, and never a guess.

    1. The agent knows when it is waiting. Nothing else does.

      Files src/main/hooks.tsconfig/hooks.json

    2. Not by which terminal printed last, which is wrong as soon as two are busy.

      Files src/main/status.ts

    3. Unknown is a true statement. Idle is a guess.

      Files src/renderer/status-badge.tsx

    done when · tick each as it passes
    watch out
    • Inferring 'blocked' from a terminal that has been quiet for thirty seconds flags every long test run as needing you and misses a permission prompt that printed once and is waiting, and the second is the expensive one. Read the hook events, map them by identifier, and render unknown where no hook has ever fired for a node.
  4. Counting tokens without lying

    Per node and per canvas spend is four counters from the agent's own accounting, priced from a dated table.

    1. Its own accounting, written to a file the canvas tails.

      Files src/main/usage.tsconfig/statusline.sh

    2. Four rates, one date, and the date shown beside the total.

      Files src/main/pricing.tsconfig/prices.json

    3. A missing model or a missing channel produces a blank, not a zero.

      Files src/renderer/meter.tsxtests/pricing.test.ts

    done when · tick each as it passes
    watch out
    • Summing the four counters into one number and pricing it at the input rate overstates spend when the agent is mostly reading its cache and understates it during long outputs, and either way the figure cannot be acted on before the bill arrives. Keep them apart, price each, and show the date of the price table beside the total.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more dev tools.