Single-file React/TSX bespoke web artifacts via the bwa CLI.
  • TypeScript 89.2%
  • JavaScript 10.8%
Find a file
dikkadev 5a2fe1514e feat(check): warn when artifacts never call runtime submit()
The check command now reports a non-fatal warning when an artifact imports the runtime but never calls submit, helping catch runs that would otherwise appear valid yet never return a result.
2026-05-31 22:18:45 +02:00
dist feat(check): warn when artifacts never call runtime submit() 2026-05-31 22:18:45 +02:00
skills/bespoke-web-artifact docs(bespoke-web-artifact): expand design guidance for artifact-specific visuals and feedback 2026-05-31 20:01:00 +02:00
src feat(check): warn when artifacts never call runtime submit() 2026-05-31 22:13:11 +02:00
tests feat(check): warn when artifacts never call runtime submit() 2026-05-31 22:13:11 +02:00
.gitignore chore(dist): track built bwa CLI artifacts 2026-05-30 09:27:22 +02:00
AGENTS.md feat(cli): bootstrap bwa single-file artifact runner 2026-05-30 09:25:19 +02:00
LICENSE feat(cli): bootstrap bwa single-file artifact runner 2026-05-30 09:25:19 +02:00
package.json docs(readme): add Pi install and local development setup guide 2026-05-30 15:40:31 +02:00
pnpm-lock.yaml feat(cli): bootstrap bwa single-file artifact runner 2026-05-30 09:25:19 +02:00
pnpm-workspace.yaml feat(cli): bootstrap bwa single-file artifact runner 2026-05-30 09:25:19 +02:00
README.md docs(readme): clarify install and update workflow for Pi package and CLI 2026-05-31 13:00:03 +02:00
tsconfig.json feat(cli): bootstrap bwa single-file artifact runner 2026-05-30 09:25:19 +02:00
tsup.config.ts feat(check): warn when artifacts never call runtime submit() 2026-05-31 22:18:45 +02:00
vitest.config.ts feat(cli): bootstrap bwa single-file artifact runner 2026-05-30 09:25:19 +02:00

bespoke-web-artifact

bespoke-web-artifact provides bwa, a CLI for writing one-file React/TSX web artifacts without creating a local Vite project beside the artifact.

The artifact stays as one meaningful .tsx file. bwa creates the temporary Vite runtime elsewhere, serves it on a random local port by default, and lets the artifact send a result back to stdout when useful.

CLI overview

bwa add artifact.tsx lucide-react
bwa check artifact.tsx
bwa run artifact.tsx
bwa run artifact.tsx --port 5173
bwa run artifact.tsx --json
bwa run artifact.tsx --bg
bwa bg list [--json]
bwa wait <pid> [--timeout 60]
bwa bg clear [pid...]
bwa completion bash

bwa build is present only as a reserved command. It intentionally fails until export/share/deploy semantics are designed.

Artifact format

A BWA artifact is a single .tsx file with an optional metadata block at the top:

// /// bwa
// title = "Artifact title"
// vibe = "specific visual and interaction direction"
// deps = ["lucide-react"]
// ///

The artifact should default-export a React component:

import { submit, close } from "bespoke-web-artifact/runtime";

export default function Artifact() {
  return (
    <main>
      <button onClick={() => submit({ choice: "yes" })}>Submit</button>
      <button onClick={() => close()}>Close</button>
    </main>
  );
}

submit(data) prints the result to bwa run/bwa wait, shows a small success/error toast in the page, and shuts the server down. The default output is TOON; pass --json to bwa run when a script needs JSON. close() shuts the server down without a submit payload.

Metadata and dependencies

Prefer bwa add for metadata edits:

bwa add artifact.tsx lucide-react recharts

If the file does not exist, bwa add creates a starter artifact. If it exists, the command updates only the deps list in the metadata block and preserves the artifact body.

Declared deps are made available to the temporary Vite runtime. This package currently carries the common artifact dependencies it expects agents to use, including React 19, Vite, lucide-react, and recharts.

Running artifacts

Foreground run:

bwa run artifact.tsx

bwa run prints the artifact title and local URL to stderr, does not open a browser, and keeps running until the page submits, closes, the floating Exit button is clicked, or the process receives Ctrl-C/SIGTERM. By default it asks the OS for a random available port.

Use a specific preferred port only when that exact port matters. Explicit ports are strict; if the port is already in use, BWA fails instead of moving to another port:

bwa run artifact.tsx --port 5173

Use JSON submit output for command chains:

bwa run artifact.tsx --json

Background runs for agent workflows

Use --bg when an agent needs to keep working after starting the artifact server, especially before registering the random port with local-router:

run=$(bwa run artifact.tsx --bg)
pid=${run%%;*}
# the same line includes the ready URL and port, e.g. "12345; url: http://127.0.0.1:43210/ port: 43210"
bwa wait "$pid"

Background contract:

  • bwa run --bg waits until the server is listening, then prints one stdout line: <pid>; url: <url> port: <port>.
  • bwa bg list prints active/completed runs as TOON; bwa bg list --json prints the raw registry JSON for scripts.
  • bwa wait <pid> blocks until the artifact submits, closes, or fails. Submit results are printed in the same format foreground bwa run would use. Closed runs with no submit payload print nothing.
  • bwa wait <pid> --timeout <seconds> fails if the run does not finish before the timeout.
  • bwa bg clear [pid...] closes background runs through the same runtime close path as the floating Exit button and removes them from the registry. With no PIDs, it clears all registered background runs.

Background run state is stored under the BWA cache directory. Set BWA_CACHE_DIR to isolate runs for tests or scripted workflows.

Checking artifacts

bwa check artifact.tsx

bwa check parses the metadata, prepares the temporary Vite entry, and starts Vite in middleware mode far enough to catch obvious loading/configuration breakage. It is intentionally forgiving: if the artifact can run, it should usually pass.

Shell completion

Bash completion can be generated with:

bwa completion bash

Source the output from your shell setup or redirect it into a completion file managed by your environment.

Install and update

There are two pieces to install:

  • the Pi package, which gives Pi the bespoke-web-artifact skill;
  • the CLI executable, which puts the bwa command on your shell PATH.

This package declares its Pi skill in package.json:

"pi": {
  "skills": ["skills"]
}

From the git remote

Install or update the Pi package from the remote repo:

pi install ssh://git@git.dikka.dev:2222/lab/bespoke-web-artifact.git
pi update ssh://git@git.dikka.dev:2222/lab/bespoke-web-artifact.git

For a pinned install, include a tag or commit ref. Move to a newer pinned version by installing the same source with the new ref:

pi install ssh://git@git.dikka.dev:2222/lab/bespoke-web-artifact.git@v0.1.0
pi install ssh://git@git.dikka.dev:2222/lab/bespoke-web-artifact.git@v0.1.1

Pi installs the package checkout under its git package cache. Expose that checkout's built CLI with a symlink:

mkdir -p ~/.local/bin
ln -sf ~/.pi/agent/git/git.dikka.dev/lab/bespoke-web-artifact/dist/cli.js ~/.local/bin/bwa
chmod +x ~/.pi/agent/git/git.dikka.dev/lab/bespoke-web-artifact/dist/cli.js
bwa --help

Make sure ~/.local/bin is in PATH.

After updating the remote Pi package, refresh/check the CLI executable too:

pi update ssh://git@git.dikka.dev:2222/lab/bespoke-web-artifact.git
chmod +x ~/.pi/agent/git/git.dikka.dev/lab/bespoke-web-artifact/dist/cli.js
bwa --help

From a local checkout

From this checkout, install dependencies, build the CLI, and expose the local bwa command:

vp install
vp run build
mkdir -p ~/.local/bin
ln -sf "$(pwd)/dist/cli.js" ~/.local/bin/bwa
chmod +x dist/cli.js
bwa --help

Then install the local package into Pi so Pi can load the skill from this checkout:

pi install "$(pwd)"

A local path Pi install points Pi at this checkout, so skill edits are picked up from the working tree after restarting Pi. After pulling local changes, rebuild the CLI:

vp install
vp run build
chmod +x dist/cli.js
bwa --help

Avoid vp add -g ., vp add -g "$(pwd)", and vp link for this local CLI flow; they are not reliable for this project setup.

Status

Early implementation. bwa build is intentionally not defined yet.