New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@mattstack/rt-client

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mattstack/rt-client

Typed client for the rt daemon: repos, worktrees, ports, tokens, and the event relay

Source
npmnpm
Version
0.26.0
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created
Source

@mattstack/rt-client

Typed client for the rt daemon.

rt keeps the per-repo state a dev environment needs: worktrees, assigned ports, tokens, dev servers, and a live event relay. This package is how other programs read and drive that state without shelling out to the CLI and parsing text.

bun add @mattstack/rt-client
import { rtCommand, readProjectMRs } from '@mattstack/rt-client';

const repos = await rtCommand(['repos', 'list']);
const mrs = await readProjectMRs('group/repo');

Requires a running rt daemon. Install rt from the latest GitHub Release (./rt --post-install), then rt verify.

Bun-only: the settings exec path (src/settings/exec.ts) shells out via Bun.spawn, so this package does not run under Node.

@mattstack/glance is a peer dependency: rt-client returns glance's forge types so merge request shapes stay identical across rt, gitq, and mr-board.

Repo identity

Every per-repo key in the rt estate is a stable serialized identity, not a repo name. Whatever you store per-repo, send to the daemon, or put in a REST path is keyed by the wire form this package emits. The one exception: settings-store sections (repos.<identity>) key on the RAW host/path form (RepoIdentity.id for a remote-kind identity) — the settings resolver never sees the wire form, and a serialized key there misses silently.

remote:gitlab.com%2Facme%2Facme-dev     path:%2FUsers%2Fdev%2Fscratch
└─┬──┘ └──────────┬─────────────┘
 kind    the id, encodeURIComponent'd — slash-free, fits one URL segment

kind is remote (the repo has an origin: id is normalized host/path) or path (no usable remote: id is the main worktree's realpath). The : is a literal delimiter.

import {
  deriveRepoIdentity,   // (repoPath: string) => Promise<RepoIdentity> — never null
  serializeIdentity,    // (id: RepoIdentity) => string — the wire form above
  parseIdentity,        // (wire: string) => RepoIdentity | null — THE validity check
  identityFromRemote,   // (remoteUrl: string) => RepoIdentity | null — sync
  type RepoIdentity,    // { kind: "remote" | "path"; id: string }
} from '@mattstack/rt-client';

const identity = serializeIdentity(await deriveRepoIdentity(repoPath));

await rtCommand(['worktree', 'list', '--repo', identity]);        // daemon key
const url = `/api/runs/${encodeURIComponent(identity)}/${runId}`; // URL segment
DoDon't
Get identities from these functions, once, at the boundaryRe-derive with your own git calls (git remote get-url diverges under insteadOf)
Key stores and daemon payloads on the serialized formKey anything on a folder basename or a remote's last segment
Key settings sections (repos.<identity>) on the raw host/path idPut the serialized form in a settings lookup, or the raw form in a daemon payload
encodeURIComponent(identity) in URL path segmentsShip the wire form raw in a URL — its % signs decode into slashes
Decode for display: parseIdentity(wire), then the id's last path segment (remote) or basename (path) — the returned id is already decodeddecodeURIComponent the id again, show the wire form to a human, or build a chat handle from it
Treat the repo field from runs:list as an opaque key, passed back verbatimValidate or re-derive runs:* repo keys — pre-cutover runs keep their original keys

Repo-keyed daemon verbs accept serialized identities only; a bare repo name doesn't error, it resolves empty. parseIdentity is strict — only strings serializeIdentity emitted parse — so validate payloads with it, and never hand-assemble or string-split a wire.

Chat

The rt chat surface the chat viewer (~/Documents/GitHub/chat) is built on. Every call degrades to { ok: false, error } instead of throwing, and a daemon that is down and a daemon that refused look the same to the caller; branch on ok, not on exceptions.

import { chatRooms, chatMessages, chatPost, createRelay, daemonHealth } from '@mattstack/rt-client';

const rooms = await chatRooms({ handle: 'matt' });            // { ok, data: { rooms } }
const page = await chatMessages({ room: 'build', limit: 50 }); // newest page; `before: <id>` pages older
await chatPost({ handle: 'matt', room: 'build', body: 'on it' });

const health = await daemonHealth();                           // { reachable, error? }, never throws
const stop = createRelay({                                     // one daemon subscription, republished
  match: t => t.startsWith('chat/'),                            // `chat/<room>/msg`
  topic: 'chat',
  publish: (topic, data) => server.publish(topic, data),
});
FunctionDaemon verb
chatSignIn / chatSignOut / chatAway / chatBackpresence: the buddy-list row and its session heartbeat
chatBuddies / chatWho / chatRoomsthe roster, one room's members, a handle's rooms
chatJoin / chatLeave / chatArchivemembership (wakeOn: mention | all | none); archive parks a room for everyone until a post revives it
chatPost / chatDm / chatDmOpen / chatRead / chatMessages / chatMarkmessages: post, DM, open a DM room without posting, read-and-advance, page, advance the cursor
paneList / panePeek / paneSpawn / paneAccounts / paneDirectoriesherdr panes: list with presence joined, peek a screen, start claude in a tab, cswap accounts, directory suggestions
chatInvitetype /chat:join <room> into a pane; accepted, queued or refused
paneSendtype a line into a pane; accepted, queued or refused, plus an optional continuation the daemon types once the pane's turn has ended
createRelay / subscribethe event stream; daemonHealth the reachability probe

Pass { sockPath } as the trailing options to reach a non-default daemon socket. The verbs and their payloads are specified in repo-tools docs/superpowers/specs/2026-08-28-rt-chat-delivery-v2-design.md; the agent-facing rules are skills/rt-chat/SKILL.md.

Runs

RunStageRow.status is one of running | done | failed | redirected; rt runs stage-redirect writes the fourth when the work engine leaves a stage for another one, so a reader that maps statuses to icons or filters must handle all four.

License

MIT

FAQs

Package last updated on 16 Sep 2026

Related posts