Run a private local daemon
Use spawn() when a Node.js, Bun, or Deno application should own a private
local mecated process. Use query() when a script needs one prompt and
automatic cleanup.
Prerequisites
You need Node.js 22, Bun 1.4, or Deno 2.9.3 or later in the Deno 2.x line on
macOS or Linux. Install mecated from Stacklok's Homebrew tap, then verify that
it is available on PATH:
brew install stacklok/tap/mecatl
mecated --version
For release archives and source builds, see Install Mecatl. The
SDK uses the binaryPath option when set. Node.js and Bun then check
MECATED_BIN and PATH; Deno checks PATH. The SDK does not download a
binary.
Start a daemon from Node.js or Bun
This example uses the offline provider so you can verify process ownership without model-provider credentials:
import { spawn } from '@stacklok-oss/mecatl-sdk/node';
await using client = await spawn({ args: ['--mock'] });
const session = await client.sessions.create({});
const result = await (await session.run('List the main packages')).result();
console.log(result.text);
For a live model, omit --mock. The child process inherits the parent
environment and ordinary mecated configuration. Pass env to override an
environment value or args to add mecated serve flags.
spawn() owns the daemon's private Unix socket, readiness file, lifetime pipe,
and shutdown arguments. Application-supplied args cannot replace those values.
Start a daemon from Deno
This example requires a build of the unreleased Deno integration. SDK v0.1.0 does not include it.
Import spawn() from @stacklok-oss/mecatl-sdk/deno. Deno starts the daemon
with Deno.Command and connects through an ephemeral loopback gRPC listener
using the shared ConnectRPC transport. The HTTP listener is disabled.
import { spawn } from '@stacklok-oss/mecatl-sdk/deno';
await Deno.mkdir('.mecatl-runtime', { recursive: true });
await using client = await spawn({
args: ['--mock'],
tempDirectory: '.mecatl-runtime',
});
const session = await client.sessions.create({});
const result = await (await session.run('List the main packages')).result();
console.log(result.text);
Run the application with access to the executable, runtime directory, and loopback listener:
deno run \
--allow-run=mecated \
--allow-read=.mecatl-runtime \
--allow-write=.mecatl-runtime \
--allow-net=127.0.0.1 \
deno-local.ts
The Deno client owns the readiness file and runtime directory. It keeps the
daemon's standard input open as a parent-liveness channel. Closing the client
closes that channel and waits for the daemon to exit. client.daemon.grpcAddress
reports the bound address, and client.daemon.transport is "grpc". Deno clients
do not expose the Node/Bun callback-tool or filesystem media helpers.
Run one prompt with query()
query() composes daemon startup, session creation, one run, session deletion,
and daemon shutdown:
import { query } from '@stacklok-oss/mecatl-sdk/node';
const oneShot = await query('Summarize the current working tree', {
spawn: { args: ['--mock'] },
});
for await (const event of oneShot) {
if (event.kind === 'result') console.log(event.payload.text);
}
For Deno, use the runtime directory covered by the spawn() example's
permission flags:
import { query } from '@stacklok-oss/mecatl-sdk/deno';
await Deno.mkdir('.mecatl-runtime', { recursive: true });
const oneShot = await query('Summarize the current working tree', {
spawn: { args: ['--mock'], tempDirectory: '.mecatl-runtime' },
});
for await (const event of oneShot) {
if (event.kind === 'result') console.log(event.payload.text);
}
Supplying client uses an existing client and leaves it open. The query still
deletes its session unless retainSession is true. A retained session from an
SDK-spawned daemon lasts only for that daemon's lifetime because the default
local store is in memory.
Dispose owned resources
Call client.close() or use await using. Disposal cancels owned runs,
detaches durable watches, closes callback-tool and transport resources, stops
the child process, and removes the private runtime directory. Closing a client
created with connect() never signals an operator-owned daemon.
The SDK reports cleanup faults through the configured diagnostics callback and
continues the remaining cleanup steps.
Next steps
- Register callback tools before creating a session from Node.js or Bun on a private daemon.
- Handle permissions and plans in a long-running application or one-shot query.
Related information
- TypeScript SDK Node.js and Bun API
for all
spawn()andquery()options. - TypeScript SDK Deno API for Deno
spawn()andquery()options.
Troubleshooting
spawn() reports spawn_failed
Run mecated --version from the parent process environment or pass the
executable's absolute path as binaryPath.
spawn() reports readiness_timeout
Inspect the structured diagnostic delivered to your diagnostics callback. The
SDK includes a bounded, credential-redacted tail of the daemon's stderr.
Deno reports a permission error
Grant --allow-run for mecated, read and write access to the configured
runtime directory, and --allow-net=127.0.0.1 for the local gRPC connection.