Skip to content
hachejPublic

About

Build agent-powered apps without reinventing the shell.

Resources

Stars

49 stars

Watchers

1 watching

Forks

Latest commit

 

History

4,559 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Boring UI

Put an AI agent inside your app.

Chat, files, document viewers, approvals and background work for React and Node apps, built on the Pi agent harness. You keep authentication, data, permissions and model keys.

npm CI License: MIT

// Browser: a whole agent app (sessions, chat, artifact viewers) from one registry block.
import { AgentWorkspace, useConversations, useRemoteChat } from '@/components/pi-app/agent-workspace';
import { defaultKinds } from '@/components/pi-app-kinds/pi-app-kinds';

const kinds = defaultKinds(); // the viewers it draws: Markdown, HTML, PDF, images, mock-ups, diagrams…

const conversations = useConversations({ endpoint: '/api/conversations', fetch, activeId, onSelect });
const chat = useRemoteChat({ conversationId: activeId, endpoint: id => `/api/chat?conversation=${id}`, fetch, identity });
<AgentWorkspace artifactKinds={kinds} conversationId={activeId} conversations={conversations} revisionProvider={revisionProvider}
  controller={chat.status === 'ready' ? chat.controller : undefined} />;
// Server: your process opens the Pi Harness and the workspace; the kit adds an agent definition and HTTP handlers.
const agent = defineAgent({ id: 'writer', model: { provider: 'openai', modelId: 'gpt-5-mini' },
  tools: [createPresentTool({ workspace: { files, root, access } })] });
agent.install(registry);
const harness = await Harness.open(storage, { registry, models, env: () => env }, context);
const chatHandler = createChatTransportHandler({ authenticate });  // your auth decides who opens which conversation

Try it in 30 seconds

Node.js 22.19 or later. The scripted model needs no API key.

git clone https://github.com/hachej/boring-ui && cd boring-ui
npm ci && npm run build
STUDIO_MODEL=scripted npm run workspace-app

Open the printed URL and click Draft a plan. The agent writes a fictional picnic plan and opens it in the side panel. Drop STUDIO_MODEL=scripted and set OPENAI_API_KEY to use a real model.

Why Boring UI

  • The agent lives in your app. A side panel, a floating bar, a bottom drawer on phones, or the whole page. You pick the placement.
  • You own the server. Your process opens the Pi Harness. The kit never holds your keys, your users or your policy.
  • One place for files. The agent's read/write/edit, the viewers and the file tree all go through one workspace provider, with revisions and conflict checks.
  • Copy the UI, keep it updatable. Blocks install through the shadcn CLI into your code, use your shadcn theme, and update with one command.
  • Durable by default. Conversations, questions, approvals and schedules survive a restart, because Pi stores them.

Install

npm i @hachej/boring-ui-kit @hachej/boring-agent @hachej/boring-files \
  @earendil-works/pi-durable@~1.4.0 @earendil-works/pi-ai@~1.4.0 @earendil-works/chord@~1.4.0

Then add UI blocks to a React app that has shadcn set up (components.json, Base UI base-nova style). Blocks import the app's shadcn components through its ui alias and use its tokens, so the app installs those components once, first (what the app needs):

npx shadcn@4.23.0 add alert attachment avatar badge bubble button card checkbox collapsible dialog drawer dropdown-menu empty input input-group item label message message-scroller native-select popover progress scroll-area separator sidebar spinner switch table textarea toggle toggle-group tooltip trace
npx boring-ui-blocks add https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.4.8/r/pi-app.json

From the release after 0.4.23, also add .../r/pi-app-kinds.json and pass its defaultKinds() as artifactKinds, as above: pi-app draws only the kinds it is given. Add .../r/theme.json once if your app has no shadcn tokens yet. The full walk-through is the build-agent-app skill.

Features

Chat that knows your app

PiChat is the conversation: queue, steer, stop, attachments, @ file mentions, voice messages, question and approval cards. AmbientChat floats the same chat over an existing site. AppShell puts one agent above any app, as a drawer on phones and a panel on wide screens.

import { AmbientChat } from '@/components/pi-ambient/ambient';

<AmbientChat controller={controller} actions={actions} labels={{ title: 'Console assistant' }} />

See the block list.

Artifacts the agent can show

The agent writes a file and calls present. The page opens it in a viewer: Markdown (editable), HTML, PDF, images, code, mock-ups, diagrams, typed records and boards.

import { createPresentTool } from '@hachej/boring-agent/artifacts';

defineAgent({ id: 'writer', model, tools: [createPresentTool({ workspace: { files, root, access } })] });

See Whole agent app and Artifacts.

A workspace with history

createWorkspaceProvider puts revisions, conditional writes and a change feed over a Pi FileSystem (disk, virtual or SQLite). createFileGuard routes Pi's own file tools through it, so an agent edit never overwrites a save the person just made.

import { createWorkspaceProvider } from '@hachej/boring-files/workspace';
import { createFileGuard } from '@hachej/boring-agent/file-guard';

const files = createWorkspaceProvider({ identity, fs: env, journal: createWorkspaceJournal(db) });
const guard = createFileGuard({ workspace: { files, root, access } });

The browser reaches it through one route, createRevisionHandler: reads, saves, the file list, @ search and uploads (a conditional create with a receipt, binary-safe, up to maxFileBytes) all use the same resolve and access. See @hachej/boring-files and One file tool set.

Approvals, questions and schedules

Gate any tool behind an Approve/Deny card, let the agent ask the person a question, hand work to a sub-agent, or schedule a follow-up. Each one is a native Pi tool or extension.

import { createApprovalExtension } from '@hachej/boring-agent/approval';

const approvals = createApprovalExtension({ tools: { write: true, edit: true } });
defineAgent({ id: 'writer', model, extensions: [fileTools, approvals] });  // Approve/Deny before every write or edit

See Approval gate, Asking the person and Sub-agents and schedules.

Shell, Git and sandboxes

A virtual Bash and Git workspace in memory or SQLite, or a remote shell and file system you already run. The agent's tools see one view of the files either way.

See @hachej/boring-execution.

Feedback from your users

People point at what they see, dictate a note and send it. Works with or without an agent.

See @hachej/boring-feedback.

Packages

Package What it gives you
@hachej/boring-ui-kit Headless controllers, editors and viewers, the shadcn registry (r/) and the boring-ui-blocks command
@hachej/boring-agent Pi agent pieces: defineAgent, chat transport, conversations, present, approvals, questions, schedules, memory
@hachej/boring-files The workspace provider: revisions, conditional writes, history, remote access
@hachej/boring-execution Virtual Bash and Git, remote shell and file system adapters
@hachej/boring-feedback In-app feedback capture and delivery

Two more packages stay private to this repository: boring-browser (the agent in a browser worker) and boring-testing (a scripted keyless model and a headless browser driver).

Examples

Every example uses fictional data. Run it with npm run <name> after npm run build; npm run <name>:journey drives it in a real browser.

Example What it shows
workspace-app The smallest whole agent app: sessions, chat, artifact panel, about 120 lines of server
ambient An agent floating over an existing settings console
app-shell A phone-first app with one agent in a bottom drawer
dock-app Chat and files in resizable docks beside a host page
shared-chat A team conversation with several people and agents
bot One lifelong conversation with memory and a self it can edit
browser-agent A coding agent that runs entirely in one browser tab
hosts The same agent on Cloudflare Durable Objects and AWS
workspace-demo A fictional accounts-payable week with approvals

The studio is a playground over every block (npm run studio).

Use with your coding agent

This repository ships Agent Skills that teach Claude Code, Codex and other coding agents to build with the kit:

npx skills add hachej/boring-ui
Skill Use it to
boring-ui Learn the kit, its rules, and which skill to use next
build-agent-app Scaffold an app with an agent inside, or add one to an existing app
add-blocks Find, install, update and theme registry blocks
agent-capabilities Give the in-app agent tools, files, approvals, questions, sub-agents and schedules

Documentation

Topic Start here
UI blocks and their props Registry guide
Upgrading Migration guide
What is implemented, with tests Feature map
How the kit works with Pi Pi integration and invariants
Files, Git and execution Workspace architecture
An agent beside an existing website Website integration
Agents that change their own tools Self-evolution
Product scope Requirements and roadmap
Releasing npm release guide

Apps built by the Boring Factory start from its app template and ship through the Factory; this repository provides the packages and blocks they consume.

Contributing

Read AGENTS.md and INVARIANTS.md first. Use fictional data only.

npm ci
npm run check        # docs links, package boundaries, registry blocks, design rules
npm run typecheck
npm test
npm run verify       # all of the above plus invariants and design tests
npm run check:pack   # audits the real package tarballs

verify lists deferred proofs; they are backlog, not release blockers. Browser journeys and isolated consumer checks run separately in CI. Keep raw local evidence in .cache/evidence/. A package change adds its note to MIGRATING.md under Unreleased. Merging a PR does not publish packages; see the release guide.

Release qualification is tracked in the implementation checkpoint and VERIFY.json. Passing one test does not qualify every provider or deployment.

License

MIT. Optional dependencies keep their own licenses. Qualify tldraw licensing and assets for your deployment; see the canvas guide.

About

Build agent-powered apps without reinventing the shell.

Resources

Stars

49 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages