effect-herdr
v0.1.0
Published
A typed Effect SDK for herdr, the terminal-native agent multiplexer.
Maintainers
Readme
effect-herdr
A typed Effect SDK for herdr,
the terminal-native agent multiplexer. Script sibling panes, split
workspaces, and react to focus changes — all as composable, typed Effects.
Install
bun add effect-herdr effectQuickstart
Run this from inside a herdr-managed pane (HERDR_ENV=1):
import { BunFileSystem } from "@effect/platform-bun"
import { Effect, Option } from "effect"
import { currentPane, runInPane, splitPane, HerdrSession } from "effect-herdr"
const program = Effect.gen(function* () {
const pane = yield* currentPane
if (Option.isNone(pane)) return yield* Effect.log("not running inside herdr")
const sibling = yield* splitPane(pane.value, { direction: "right" })
yield* runInPane(sibling, "echo hello from effect-herdr")
})
program.pipe(
Effect.provide(HerdrSession.Live),
Effect.provide(BunFileSystem.layer),
Effect.runPromise,
)HerdrSession.Live resolves the socket path the same way the herdr CLI
itself does (env var, then ~/.config/herdr/herdr.sock) and fails loud at
startup if nothing is listening there — no silent no-ops. BunFileSystem
is the one platform layer this quickstart needs; see
Platform runtime below for why.
A full runnable version of this — split, run a command, wait, close — is
examples/parrot.ts:
bun run examples/parrot.ts # run from inside a herdr paneWhat's here
HerdrSession— the ergonomic entry point. OneLayer, sound defaults.- Pane control —
splitPane,focusPane,closePane,runInPane(batch string or streamingStream<string>input),waitForOutput(blocks on a substring/regex match, returned as aStream). - Focus tracking —
activePane/activeTab(per-container, always resolves),focusedPane/focusedTab/focusedWorkspace(global,Option-wrapped),focusedPaneRef(a liveSubscriptionRefthat updates as focus changes anywhere in herdr). - Identity vs. state —
Pane/Tab/Workspaceare stable references you can hold onto;PaneSnapshot/TabSnapshot/WorkspaceSnapshotare point-in-time reads with their owncapturedAt. - Raw protocol escape hatch — every ergonomic combinator is built on
HerdrConnection's typedrpcclient. Drop tosession.rpc["workspace.list"]()whenever the service layer doesn't cover your case; there's no hidden state that makes mixing the two incoherent.
Not every herdr RPC method has an ergonomic wrapper yet — see
TODO.md for the coverage gap and other known limitations
(PTY control-key input, real-time pane-output tailing).
Platform runtime
effect-herdr uses Effect's platform primitives (FileSystem,
ChildProcessSpawner, Crypto, Socket) instead of Node/Bun stdlib calls
directly, so it works the same way under Bun or Node. Provide whichever
platform layer matches your runtime once, at your program's entrypoint —
e.g. @effect/platform-bun's BunServices.layer.
Development
bun install
bun run typecheck
bun run test # unit tests, packages/core only
bun run test:e2e # E2E, spins private herdr servers per test
bun run test:all # both
bun run schema:refresh # re-capture scripts/herdr-schema.json after upgrading herdrThe E2E suite shells out to a real herdr binary to spawn isolated
named-session servers — the SDK-under-test is never in that bootstrap path.
Requires herdr on PATH.
Release
Versioning and publishing go through
Changesets: run
bun run changeset to describe a change, merge it, and CI opens a release
PR that publishes to npm on merge. bun run build produces the published
dist/ output (ESM + .d.ts) via tsdown.
