reef-vcs
v0.4.2
Published
The TypeScript SDK for Reef: a typed client for the reef daemon's API, with a workspace block that holds a lease and reports presence.
Maintainers
Readme
reef-vcs
The TypeScript client of the Reef daemon. Reef gives each agent its own workspace: a copy-on-write copy of a git or jj repository, leased to one process and snapshotted after every write. Work lands as a jj change; nothing is lost when a workspace is released.
npm install reef-vcsThe package talks to a running daemon and never starts one. Install reef as the
quickstart says; any reef
command starts the daemon, or run reef daemon start. Use the reef-vcs release that matches the
daemon's version: older and newer daemons serve the calls both know, and a mismatch is reported as
IncompatibleError. Node 22.15 or later, on macOS or Linux; ESM, and require() works from
Node 22.12.
Connect
import { connect } from "reef-vcs";
const client = await connect(); // the daemon the reef CLI uses
const named = await connect({ agent: "planner-3" }); // name the agent on every operation it records
const remote = await connect({ remote: "vm" }); // a profile saved by `reef remote add`connect() finds the socket as reef does (REEF_SOCKET, REEF_STATE_DIR, REEF_CONFIG, then
the platform's default), or the remote daemon REEF_REMOTE names. Close the client with
await client.close(), or hold it with await using; a script that forgets still exits.
Status and history
Every RPC is a method on the client, taking an object of the request's fields:
const status = await client.getStatus({ workspace: wsId });
for await (const op of client.listOperationsAll({ repo: repoId })) {
console.log(op.id, op.description); // every page
}Messages, enums and protobuf-es's helpers are importable from reef-vcs/api/v1. 64-bit integers
are bigint: log a message with toJson(Schema, message).
A workspace for a block of code
await client.withWorkspace({ repo: repoId, purpose: "fix the parser" }, async (ws) => {
await writeFile(join(ws.path, "parser.ts"), fixed);
ws.activity("running the tests");
});
// Released with a final snapshot: the edit is in the workspace's change.On Node 24 and later, or with a transpiler, the same block is await using:
await using ws = await client.workspace({ repo: repoId, purpose: "fix the parser" });While it is held, the lease is renewed and a presence entry shows it in reef presence watch and
the web UI, as reef ws run does for a command.
Subscriptions
const stream = client.subscribeOperations({ repos: [repoId] });
for await (const frame of stream) {
for (const op of frame.operations) console.log(op.id);
}Breaking out of the loop, stream.cancel(), or an AbortSignal passed as { signal } ends it.
A remote daemon
const client = await connect({
remote: "https://vm.example:7470",
token, // from `reef remote token create` on that machine
fingerprint: "sha256:...", // from `reef remote show` on that machine
});The daemon's key is checked against the fingerprint in every TLS handshake, before the token is sent.
Errors
Every failure is a ReefError subclass by kind (NotFoundError, ConflictError, ...), with the
daemon's reason, hint (how to fix it) and next (a reef command line that does):
import { NotFoundError } from "reef-vcs";
try {
await client.getWorkspace({ workspace: wsId });
} catch (error) {
if (error instanceof NotFoundError) console.log(error.reason, error.hint, error.next);
}Read more in the TypeScript SDK guide.
Maintainers
Releases publish to npm from the repository's release.yml by trusted publishing, with
provenance; see the R2.07 brief's one-time setup.
