Termkit

Quick start

Wire up a provider and render your first terminal.

Termkit has two seams you fill in: where the byte stream lives (connectionUrl) and how to control sessions (transport). Everything else is handled for you.

1. Wrap your app in a provider

Define the config once (outside render, or memoised) and pass it to <TermkitProvider> near your app root.

app.tsx
import { TermkitProvider, type TermkitConfig } from '@mp-lb/termkit';
import { trpc } from './trpc';

const config: TermkitConfig = {
  // Where the WebSocket byte stream lives. `params` is forwarded to the daemon
  // and drives its working-directory resolution.
  connectionUrl: ({ sessionId, params }) =>
    `ws://${location.host}/_terminal?` +
    new URLSearchParams({ session: sessionId, ...params }),

  // The control plane: list live sessions, kill one, clear a bell.
  transport: {
    list: () => trpc.terminal.list.query(),
    kill: (sessionId) => trpc.terminal.kill.mutate({ sessionId }),
    seen: (sessionId) => trpc.terminal.seen.mutate({ sessionId }),
  },
};

export function App() {
  return (
    <TermkitProvider config={config}>
      <Routes />
    </TermkitProvider>
  );
}

The transport here forwards to a tRPC router, but it's just three async functions — wire them to whatever backend you have.

2. Render a terminal

import { Terminal } from '@mp-lb/termkit';

export function TerminalPanel() {
  return (
    <div style={{ height: '100%' }}>
      <Terminal session="global" autoFocus />
    </div>
  );
}

The session id is stable and yours to choose. Render the same id again — even after a reload — and termkit reattaches to the same live shell instead of spawning a new one.

Give the terminal a sized container; it fills 100% of width and height and refits on resize.

3. Run the daemon

The browser connects to a daemon that owns the PTYs. The simplest option:

pnpm add -D @mp-lb/termkit-server
TERMKIT_PORT=5179 pnpm termkit-daemon

Point connectionUrl at it (directly, or through your dev server's proxy). For working-directory resolution, embedding the daemon, and production setups, see Server & daemon.

On this page