Choose a worker within your rules. stooart checks a task against the workers you configure and recommends a worker with reasons. You decide whether to hand off the work.
Get started · Set up Jev · Routing rules · Choose a strategy · Learn from outcomes · Contribute
Install from npm for the CLI, or use JSR to call it from Deno. Supported executable targets are macOS arm64 and Linux x64.
Use Node.js 24.10 or newer. npm installs the launcher and downloads only the executable for your platform:
npm install --global @compootor/stooart
stooart --versionThe JSR package is a Deno launcher and API. Install a native stooart executable first. The npm package above is one way to add it to PATH.
deno add jsr:@compootor/stooart
deno run --allow-run=stooart jsr:@compootor/stooart/cli --versionThe JSR launcher defaults to stooart on PATH. Its API also accepts an explicit executable path.
To try routing, save the example request as task.json, then run:
stooart route task.jsonWith JSR, use deno run --allow-run=stooart jsr:@compootor/stooart/cli route task.json. The command prints a JSON recommendation. The example uses fictional workers, so replace them with workers you can use. Routing needs no API key and never launches a worker.
Starting with v0.1.1, stooart uses scriptc instead of a bundled Bun runtime. The npm launcher requires Node.js; the standalone executable runs without an installed JavaScript runtime.
| Artifact | Measured size on macOS arm64 |
|---|---|
| Standalone executable | 1.83 MB |
| Compressed platform package | About 907 KB |
| Root npm package with launcher, docs, and skills | About 72 KB |
These are local v0.1.1 candidate measurements, using decimal units. Release archives can differ slightly as documentation changes. The published v0.1.0 assets retain their original contents.
Runtime and performance · what scriptc compiles
Vite+ bundles the Effect application. scriptc's C backend builds a standalone executable that embeds QuickJS and runs that bundle in dynamic mode. It does not translate the entire Effect application into static C.
In a local macOS arm64 check, routing the same fixture averaged about 26 ms with the scriptc executable and 41 ms with the bundle under Node.js. Each result covers 30 process launches after three warmups. It includes startup and routing, makes no Jev network call, and uses a timer with 10 ms resolution. It is a local comparison, not a latency guarantee.
The native CLI suite covers routing, persistent credentials, journals, and verification commands. Terminal checks also cover hidden key entry and cancellation. Release CI builds and tests both supported targets before packaging.
| I want to | Read |
|---|---|
| Configure workers | Complete request example |
| Let Jev choose between eligible workers | Set up Jev, then try the two-worker check |
| Record checks and reuse procedures | Evidence workflow and runnable example |
| Prepare or verify a package | Release procedure |
The repository includes two optional skills. Release packages carry the same files under skills/.
| Skill | When to use it |
|---|---|
delegate |
Route a task among workers you configure, then decide how to act on the recommendation |
learn |
Record a decision, run an explicit check, link the outcome, and inspect reusable procedures |
To use them with Codex from this checkout, copy the skill directories into your skill folder:
mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills"
cp -R skills/delegate skills/learn "${CODEX_HOME:-$HOME/.codex}/skills/"For another agent, use its documented skill folder. The skills call the stooart executable, so install the CLI or provide its path to the agent. Neither skill grants worker access or runs a worker on its own.
You can use stooart without Jev. Default priority routing needs no account or API key. Set up Jev when you want an online model to choose between eligible workers.
stooart connects directly to TypeSafe, the service that runs Jev. Its client software is included. You do not need a separate jev command or login.
Install stooart first. The commands below work in Bash and zsh on macOS or Linux. Save the two-worker connection request as jev-setup.json in your working folder before the connection check.
-
Create a TypeSafe account and API key.
-
Run
stooart jev setup. Paste the key at the hidden prompt and press Enter. From this checkout, usepnpm dev jev setup. The key does not appear in shell history or command output.This saves the key under
~/.config/stooart/credentialswith private file permissions. IfXDG_CONFIG_HOMEis set, stooart uses$XDG_CONFIG_HOME/stooart/credentialsinstead. -
Run the connection check from a terminal. This uses TypeSafe API quota but does not run a worker.
stooart route jev-setup.json --jev
From the checkout, use
pnpm dev route examples/jev-setup.json --jevwithout copying the file.
The connection-check example contains two fictional, eligible workers. You do not need to install them. The check confirms that Jev can return a routing decision.
Important
Use the two-worker example for this check. examples/task.json has only one worker, so it skips Jev even with --jev. A preferred worker, an ineligible shortlist, or a task kept local can also skip the API.
stooart returns a JSON object with named fields. For the unchanged connection-check example:
| What you see | What it means | Next step |
|---|---|---|
workerId is ci-test-runner or review-and-test-runner, reason mentions the classifier, and no failureKind |
Jev returned a choice that passed validation | Replace the fictional profiles with workers you can actually use |
executor: "local", failureKind: "low_confidence" |
Jev responded but was too uncertain to choose | Keep this task with the caller |
Another failureKind, or a command error |
Setup or the response needs attention | Open the troubleshooting table below |
Exit code 0 alone does not prove Jev worked. local is a valid routing result, including when a key is missing. Do not repeat calls until Jev picks the worker you prefer.
Fix a setup problem · find your result and next action
| Result or symptom | What to check |
|---|---|
authentication |
Enter a current TypeSafe key in the same terminal and check the account's API access. A key for another model provider will not work. |
quota |
Check usage and available quota in the TypeSafe account. Repeating the request will not restore quota. |
rate_limit |
Wait before trying again; reduce concurrent requests if it repeats. |
transport or timeout |
Check internet access and whether the configured API address is reachable. The request timeout is 10 seconds. |
provider |
Check the service or trusted gateway, then retry later. stooart will not switch providers for you. |
malformed_response |
The response could not be used. Check any gateway's compatibility; a response alone does not prove setup is healthy. |
local with no failureKind, or a priority-based reason |
Policy may have skipped Jev. Use the unchanged two-worker example and include --jev. |
| Works in a terminal, fails inside an agent | The agent process may not have the same environment. See the agent handoff below. |
command failed with a nonzero exit code |
Check the working folder, request filename, JSON, flags, and API configuration. Invalid configuration can fail before there is a failureKind. |
You can continue without Jev by omitting --jev. stooart then uses configured priority.
Keep the connection available · sessions, native builds, and custom endpoints
The saved key is available to stooart across terminal sessions and processes. To delete it, run stooart jev remove, or pnpm dev jev remove from the checkout. Keep the key out of repositories and chat.
If TYPESAFE_API_KEY is set in the process environment, stooart uses that value instead of the saved key. This is useful for managed agent hosts that inject secrets. If the variable is set to an empty value, stooart treats the key as unavailable and does not fall back to the saved key.
The native executable reads the process environment and the saved credential file. It does not load .env files or another CLI's saved login. Development uses the same environment rules. For a built CLI, use the same request with the host binary, such as ./dist/stooart-darwin-arm64 route examples/jev-setup.json --jev.
Leave TYPESAFE_BASE_URL unset for the default service at https://api.typesafe.ai. If an administrator supplied a trusted gateway, use its API root; stooart appends /v1/systemone. Do not add that endpoint path yourself or silently replace an existing gateway. The configured service receives the API key and routing metadata.
A TypeSafe key grants access to Jev, not to the worker providers in your profiles. Configure and confirm those separately.
Connect an agent · setup checklist and result handling
- Choose where the key lives. Run
stooart jev setupon the host that runs stooart, or setTYPESAFE_API_KEYin that host's secret or environment settings. The saved key works across stooart processes for the same user. A terminal export does not update an already-running desktop app. Configure its launching process or restart it from a configured terminal. - Confirm the intended endpoint. Preserve a deliberately configured gateway. Do not dump environment variables or place credentials in tool arguments, prompts, or logs.
- Run the two-worker check when an API request is within the task's scope. Keep the request unchanged and inspect the returned JSON. A single-worker route is insufficient.
- Report
workerId,failureKind, andreason. If the result islocal, keep control and explain why. If it names a worker, confirm that worker has access and fits the task. Routing does not authorize or perform execution.
When neither source is configured, ask the owner to run stooart jev setup or set TYPESAFE_API_KEY for the host process. Do not search unrelated files or copy another application's stored credentials.
pnpm dev route examples/task.json
cat examples/task.json | pnpm dev route -A request has two parts: task describes the work, and workers lists available choices. Keep worker access and availability current.
See the routing flow · request to recommendation
route returns a worker, local to keep the task with the caller, or script for scoped deterministic work. It never launches a worker or grants file access.
Configure the request · task and worker field reference
| Field | Meaning |
|---|---|
id, kind, goal |
Stable identity, phase, and intended behavior |
acceptance, allowedPaths |
Checks and file scope the caller enforces |
requiredTools, unresolved |
Required capabilities and unresolved decisions |
delegationRequested |
Defaults to false; explicitly permits research, review, or diagnosis delegation |
preferredWorkerId |
Exact worker preference; stooart never substitutes another |
allowedProviders |
Provider allowlist; an empty list permits none |
features |
Optional family, scope, context, and proof enums |
projectId, groupId |
Retrieval identity and related-attempt grouping |
Profile id |
Nonempty, unique worker identifier used by preferences and outcomes |
Profile executor |
Caller-defined name starting with a lowercase letter, followed by lowercase letters, digits, ., _, or - |
Profile model, provider |
Nonempty identifiers for the configured model and provider |
Profile available, tools, explicitOnly, priority, effort |
Caller-supplied availability, capabilities, preference rule, ordering, and optional effort |
local and script are reserved routing results. Configure only model and effort pairs your worker supports.
| Policy fact | Result |
|---|---|
| Missing tools, unavailable worker, disallowed provider, duplicate ID, or unmet explicit preference | Reject that worker and include the reason |
| Unresolved or incomplete scope | Return local |
| Research, review, or open diagnosis without explicit delegation | Return local |
| Scoped deterministic operation | Return script |
| Eligible implementation workers | Choose lowest priority, then worker ID |
Track availability · health and cooldowns
stooart does not infer live access from an installed CLI. An optional profile health object contains a failure category plus observedAt and retryAfter ISO timestamps. Active cooldowns, invalid timestamps, and future observations exclude that profile. Expiry removes the cooldown restriction; it does not prove recovery. Scope profiles to the actual account and provider route, and refresh available yourself.
Every recommendation includes rejected workers and reasons. A preferred worker is exact, never a request to substitute another worker. A recommendation grants no permission and runs no command.
Priority routing needs no setup. Use Jev when you have credentials or recipes when you have recorded evidence. --jev and --recipes cannot be combined.
| Strategy | Add to route request.json |
Selection rule |
|---|---|---|
| Priority · default | Nothing | Lowest priority number, then worker ID; no network |
| Jev · optional | --jev |
Ask Jev to choose among up to three eligible workers |
| Recipes · optional | --recipes --journal journal.jsonl |
Reuse recent, matching procedures supported by verified outcomes |
All three respect policy gates. Priorities, Jev confidence, and observed recipe success rates are not calibrated measures of worker quality.
Jev privacy and fallback behavior · request contents and abstentions
Follow Set up Jev to configure credentials. Explicit worker preferences and requests with one eligible worker skip the network call.
| Sent to Jev | Kept out of the request |
|---|---|
| Task kind, required tool labels, optional enum features | Goal, acceptance prose, file paths, project IDs |
| Candidate ID, executor, model, provider, effort | Journal, procedures, source, worker health |
Keep IDs and labels free of private content. Priority orders the shortlist locally; it is not sent as a candidate field.
Malformed, inconsistent, out-of-range, or low-confidence responses return local. Provider failures do too, with no provider substitution. failureKind distinguishes authentication, quota, rate limits, timeout, transport, provider errors, malformed responses, and low confidence. Diagnostics omit provider response bodies. Missing credentials produce an authentication abstention when a network choice is needed.
A reported success becomes reusable evidence only after an explicit check. Record a decision, do the work, verify a chosen artifact, then link the result.
- Route and save the decision with
--journal. - Perform the work through the worker or tool you choose.
- Verify an artifact with a command you explicitly supply.
- Record the outcome, receipt, and optional versioned procedure.
Use recall to inspect matching procedures or --recipes to opt into their recommendations. Only verify executes a check; routing and retrieval never execute procedure text.
Follow the runnable evidence example →
Use the evidence commands · input files and journal
Below, stooart means an installed CLI. From the checkout, use pnpm dev in its place. Create verification.json and linked-outcome.json using the request formats; they are not included fixtures.
stooart route examples/learning-task.json --journal ./journal.jsonl
stooart verify verification.json --journal ./journal.jsonl
stooart record linked-outcome.json --journal ./journal.jsonl
stooart recall examples/learning-task.json --journal ./journal.jsonl
stooart route examples/learning-task.json --recipes --journal ./journal.jsonl
stooart eval --journal ./journal.jsonl --after 2000-01-01T00:00:00.000ZThe cutoff is an example. Choose a past timestamp that separates your recorded training evidence from later decisions.
Understand the evidence · verification, recipe eligibility, and evaluation limits
verify runs the named command with direct argv execution, a timeout from 1 to 120,000 ms, and the current environment. It hashes the selected file or directory before and after the check. A passing receipt proves that this command passed against that artifact. It does not prove that the check is adequate, that descendants were isolated, or that a third party signed the receipt.
record --journal links a decision, attempt, receipt, selected worker, and artifact hash. Only a matching passing receipt supports verified. Keep accepted, failed, environment_error, cancelled, and unknown distinct. Costs are observed values; omitted cost stays unknown.
Recipes require a versioned procedure, at least one verified outcome, matching project/task features and worker configuration, the current policy version, and a receipt younger than 90 days. Retrieval shows verified and failed counts, corrections, checks, and costs. Unknown outcomes stay visible. Routing never runs recipe steps.
Offline eval freezes evidence before the supplied cutoff, excludes related task groups from held-out decisions, and reports priority, recipe, and recorded Jev replays. It makes no model calls. Only outcomes for the worker actually selected are observed, so the report is not a causal worker comparison or savings claim.
Know what is stored · journal integrity and privacy
New journals use mode 0600 and parent directories use 0700. A directory lock serializes writers. Truncated lines, duplicate IDs, mismatched references, changed procedure versions, and invalid chronology fail closed. Preserve a damaged journal before repairing it.
Decision snapshots omit raw goal text, acceptance prose, and allowed paths. Do not put credentials or private source in task descriptions, procedure text, verifier labels, or legacy logs. Legacy record --log files remain separate and never feed recipe routing. The verifier captures stdout and stderr only to hash them; it does not persist raw output.
Read the full request formats and runnable local exercise in docs/learning.md.
Keep a simple outcome log · separate from verified journal evidence
pnpm dev record examples/outcome.json --log ./outcomes.jsonl
pnpm dev history --log ./outcomes.jsonlWithout --log, the path is ~/.local/state/stooart/outcomes.jsonl. New files use mode 0600. These records store caller reports, including any verified label; they do not prove checks ran and never feed recipe routing. Use --journal for linked evidence.
Open an issue before changing the routing contract or package layout. For a focused fix, send a pull request that describes the input, the observed result, and the intended result. Test behavior through the CLI or launcher; keep tests independent of internal helper structure. Never include a live TypeSafe key, worker credential, or private journal.
Run pnpm check before submitting. If you change native runtime or packaging, also build and test the binary on a supported host. Name that host in the pull request.
Use Node.js 24.10 or newer and pnpm 12.3.4:
git clone https://github.com/stoopid-computers/stooart.git
cd stooart
pnpm install --frozen-lockfile
pnpm check
pnpm dev route examples/task.jsonpnpm check runs Vite+ formatting, lint, types, GitHub workflow checks, and CLI/launcher tests. Run pnpm fmt first if you need to format edited files. To build and exercise the standalone executable for macOS arm64 or Linux x64, run:
Install a C toolchain first. On macOS, use xcode-select --install. On Ubuntu, install build-essential.
pnpm build:native
pnpm test:nativeThe standalone executable uses scriptc's C backend with embedded QuickJS to run the bundled Effect application. It needs no installed Node.js or Bun. This is scriptc's dynamic mode, not a static translation of the whole application into C. It reads its environment and the saved Jev credential file; it does not load local .env files. The npm launcher requires Node.js 24 or newer. The JSR launcher does not download or compile the executable.
See docs/releasing.md for package checks, provenance, private local archives, checksum verification, and release requirements. Local preview archives are private and must never be published.
stooart is MIT licensed. Embedded dependencies keep their own licenses in THIRD_PARTY_NOTICES.