npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tandemir

v0.0.58

Published

Companion daemon for builders working with AI sidekicks. Tandemir watches files in a project, runs lightweight agents in sandboxes on each save, and surfaces each agent's output — plus a chat with an orchestrator — in a built-in browser UI.

Readme

tandemir

Companion daemon for builders working with AI sidekicks. Tandemir watches files in a project, runs lightweight agents in sandboxes on each save, and surfaces each agent's output — plus a chat with an orchestrator — in a built-in browser UI.

Status: Slice 3. Web UI, WebSocket protocol, orchestrator chat, a model-picker dropdown, an agent settings panel, @-tuning, and specialist Apply/Reject proposals are in. The heavy (opencode) runtime lands in a later slice.

What it does

  1. You point tandemir at a project directory containing .tandemir/agents/<name>.json configurations.
  2. Each agent declares the files it watches, the folder it owns, and the artifact path it produces.
  3. When watched files change, the agent runs in a sandboxed copy of the project, calls an LLM with file tools (write_file, read_file, list_files), and writes its output.
  4. Files written under the agent's ownedFolder are auto-synced back to the workspace.
  5. The daemon serves a SolidJS UI:
    • Chat — talk to the orchestrator; it can spawn agents and propose file writes you Apply or Reject. Tune any agent inline with @AgentName <note>.
    • One tab per agent — live artifact preview, recent run logs, and a ⚙ settings panel (model dropdown, prompt, watches, owned folder, debounce, tunings).
    • + — configure and start a new agent.
  6. A per-agent static HTTP route under a random prefix serves the artifact iframe; the UI listens for artifact_changed events on the WebSocket to refresh.

Prerequisites

Quick start

bun install
(cd web && bun install)
bun run build
export OPENROUTER_API_KEY=sk-or-...
bun run start example

bun run start boots the daemon, serves the built UI, and auto-opens your browser. Use --no-open to skip the browser, --port N to bind a different port (default 7777).

Edit example/spec.md, save, and watch the agent's artifact tab refresh.

Editing agents (Slice 3)

  • Click the ⚙ on an agent tab to open its settings — change model (dropdown), prompt, watches, owned folder, or debounce, then Save.
  • Tune an agent inline from chat: @AgentName <note> adds a sticky tuning and reruns the agent. Remove tunings from the settings tab.
  • When an agent writes files outside its owned folder, those writes appear in chat as Apply/Reject proposals (capped at 5 per run).

Split-host layout

The UI supports a multi-pane layout with up to 4 hosts. Each host has its own tab strip and renders its active tab independently.

  • Layout dropdown (top toolbar) — choose between: Single, 2 Columns, 2 Rows, 1+2 Columns, 1+2 Rows, or Grid (2×2).
  • Drag and drop — reorder tabs within a host or drag them between hosts. An insert indicator shows the drop position.
  • Focus — click a host pane to focus it. New tabs open in the focused host. The focused host shows an accent-colored top border.
  • Persistence — layout and tab assignments are saved to localStorage and restored on page reload.

Development

Two-terminal workflow with the Vite dev server in front of the daemon:

# Terminal A — daemon (no browser auto-open; UI comes from Vite below)
OPENROUTER_API_KEY=sk-or-... bun run src/cli.ts start example --no-open

# Terminal B — Vite dev server with HMR
cd web && bun run dev

Then open http://127.0.0.1:5173/. Vite proxies /ws (the WebSocket) and the per-agent static routes (/<12-hex>/...) to the daemon on :7777, so HMR works for the UI while the backend stays live.

bun test            # run the suite
bun run typecheck   # tsc --noEmit

Project layout

src/
  cli.ts                CLI entry; wires bus, manager, orchestrator, server, ws
  config.ts             Loads .tandemir/config.json + agents/*.json; enforces invariants
  paths.ts              safeJoin and path helpers
  manager.ts            Watcher → debounce → run lifecycle per agent
  runner.ts             One agent run: sandbox → LLM tool loop → diff → sync
  watcher.ts            Debounced chokidar wrapper
  sandbox.ts            Per-run temp dirs under .tandemir/sandboxes/
  tools.ts              Sandbox-bounded file tools (write/read/list)
  llm.ts                OpenRouter SDK + specialist tool loop driver
  diff.ts               Classifies sandbox-vs-workspace changes
  sync.ts               Applies owned-folder changes back to the workspace
  server.ts             Hono server: WS upgrade, static SPA, per-agent prefixes
  protocol.ts           Wire types shared with the web UI (events + commands)
  bus.ts                Typed publish/subscribe event bus
  chatlog.ts            Persistent chat history under .tandemir/chat.log
  proposals.ts          Persistent proposal store (used in later slices)
  artifact-watcher.ts   Watches each agent's artifactPath; emits artifact_changed
  orchestrator.ts       Orchestrator agent (chat + spawn/close tools)
  orchestrator-client.ts  OpenRouter client tuned for the orchestrator
  ws.ts                 WebSocket handler: routes commands, mirrors bus events
  types.ts              Shared types
web/
  src/
    main.tsx            SolidJS entry; layout toolbar + host grid
    store.ts            App store (agents, chat, configure tabs, toasts)
    layout-store.ts     Multi-host layout state, tab assignment, persistence
    ws.ts               Client WebSocket; mirrors server protocol
    protocol.ts         Mirror of src/protocol.ts for the browser
    components/
      LayoutToolbar.tsx   Layout preset dropdown + connection status
      HostGrid.tsx        CSS grid container rendering N host panes
      HostPane.tsx        One host: tab strip + routed content area
      HostTabStrip.tsx    Per-host tab strip with drag-and-drop
      ChatTab.tsx, AgentTab.tsx, ConfigureTab.tsx, SettingsTab.tsx, etc.
  tests/
    layout-store.test.ts  Unit tests for layout state logic
  vite.config.ts        Dev server + /ws and /<prefix>/ proxies to :7777
tests/                  Unit tests + e2e
docs/superpowers/
  specs/   2026-05-19-tandemir-design.md
  plans/   2026-05-19-tandemir-slice-1-artifact-pipeline.md
           2026-05-19-tandemir-slice-2-ui-orchestrator.md
example/                Minimal demo project

Configuration

Environment variables

| Variable | Required | Default | Description | |---|---|---|---| | OPENROUTER_API_KEY | Yes | — | Your OpenRouter API key. | | OPENROUTER_BASE_URL | No | https://openrouter.ai/api/v1 | Base URL for the OpenRouter-compatible API. Override to use a proxy, self-hosted endpoint, or alternative provider. | | TANDEMIR_PORT | No | 7777 | Default port when --port is not specified on the CLI. | | TANDEMIR_ORCHESTRATOR_MODEL | No | anthropic/claude-haiku-4-5 | Default orchestrator model when not set in .tandemir/config.json. Per-project config takes precedence. | | OPENCODE_BIN | No | ~/.opencode/bin/opencode | Path to the opencode binary for heavy agents. Falls back to $PATH lookup if not set and the default path doesn't exist. |

Project config

.tandemir/config.json (optional — defaults shown):

{
  "defaultDebounceMs": 1000,
  "defaultModel": "anthropic/claude-sonnet-4-6",
  "orchestrator": {
    "enabled": true,
    "model": "anthropic/claude-haiku-4-5",
    "prompt": "You are the orchestrator. Help the user manage their agents."
  }
}

orchestrator is optional. If omitted or enabled: false, the Chat tab still loads but no orchestrator responds.

The orchestrator.model field takes precedence over TANDEMIR_ORCHESTRATOR_MODEL.

.tandemir/agents/<name>.json:

{
  "name": "Mike",
  "description": "Builds a small hello-world HTML based on spec.md.",
  "prompt": "You write a single-page HTML file that reflects the user's spec.",
  "runtime": "light",
  "model": "anthropic/claude-haiku-4-5",
  "watches": ["spec.md"],
  "ownedFolder": "prototype",
  "artifactPath": "prototype/index.html",
  "debounceMs": 1000,
  "inflightStrategy": "queue",
  "tunings": []
}

Invariants enforced at load:

  • No two agents share an ownedFolder (single writer per folder).
  • No two agents share a name.
  • artifactPath must be inside ownedFolder.
  • No watches glob may match the ownedFolder.
  • runtime must be "light" for now ("opencode" lands in Slice 4).
  • inflightStrategy must be "queue" for now ("cancel-restart" lands in Slice 4).

Design and roadmap

The full design lives in docs/superpowers/specs/2026-05-19-tandemir-design.md.

Slice plans:

Upcoming slices:

  • Slice 4opencode subprocess integration (heavy agents), CLI lifecycle (tandemir stop), polish.

CLI

usage: tandemir start <project-dir> [--port N] [--no-open]
       tandemir stop <project-dir>
       tandemir --help

Flags:
  --port N        Port to bind (default: TANDEMIR_PORT or 7777).
  --no-open       Do not auto-open the browser.

See Environment variables above for all supported env vars.