npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@labelbox/recursion-cli

v0.2.0

Published

Command-line client for the Recursion platform

Readme

@labelbox/recursion-cli

Preview command-line client for the Recursion platform. It projects every CLI-compatible deployed enterprise public preview operation from apps/managed-agents/api/src/openapi/recursion-public-openapi.preview.generated.json as one finite recursion managed-agents <command> route. It has no Horizon import, live manifest, hidden generic route, or Labelbox credential fallback. Three handwritten commands, validate, plan, and apply, reconcile a checked-in agent folder through those same public operations. A fourth, agent-skills, reads an agent's skills as the model is shown them. Two top-level commands, run-automation and wait-automation-run, run an automation and wait for its result. The documentation commands and skills need no API key.

Versions remain below 1.0.0 while the platform API and CLI are changing and may include breaking changes. For launch workloads, use the Recursion web app or MCP unless you explicitly accept the preview client lifecycle.

See the client preview upgrade notes before updating an integration.

npm install --global @labelbox/[email protected]

The exact version above selects the published enterprise client during the latest takeover. The enterprise CLI publishes to npm latest starting with the qualified 0.2.0 release. Use an unqualified install only after that publication is verified. See the upgrade notes for publication status and migration from the Horizon-era 0.0.x CLI. Pin an exact version when an integration needs reproducible installs, or run the CLI from a repository checkout.

With RECURSION_API_KEY already present in the environment:

recursion managed-agents list-agents-v2
recursion managed-agents get-agent-v2 --input-file request.json

Use the -v2 catalog commands for new integrations. The matching v1 commands remain available for compatibility while their endpoints are deprecated.

The production origin defaults to https://api.recursion.labelbox.com. --organization-id and --tenant-id are global client selectors and cannot be overridden inside operation JSON. Operation input is an exact SDK envelope: path, query, and declared header fields are top-level properties and a JSON request body is under body. Read it from --input-file <path> or standard input with --input-stdin; request data is never accepted in process arguments. The API key is read only from RECURSION_API_KEY; no API-key CLI option exists.

Custom API origins must use HTTPS. Plain HTTP is accepted only for exact local development hosts: localhost, 127.0.0.1, and [::1].

Automation contract

Operation stdout and stderr are newline-delimited JSON; --help, --version, and the documentation and skills commands without --json are the plaintext stdout exceptions. Success is { "ok": true, "data": ... }; failure is { "ok": false, "error": ... }. Response payload object keys are normalized deterministically, binary responses use the explicit $recursionBinary base64 envelope, and structured API status, code, details, and retry metadata are preserved. Input errors exit 2, request errors exit 1, and a closed stdout pipe terminates without printing a misleading request failure.

The two canonical session streams emit one success line per SSE record and honor stdout backpressure. Operations with declared ETag caching retain the response ETag and represent a valid 304 explicitly rather than treating it as a failure.

Documentation

recursion recipes
recursion recipes run-an-agent-session [--format cli|curl]
recursion explain [<concept>]
recursion tutorials [<id>]
recursion resources [<id>]
recursion managed-agents create-agent --help

These commands read the docs catalog: the recipes, each proven against production on a schedule, with their steps and runnable CLI or cURL code; the API operations grouped by resource; and the concept and tutorial guides. recursion --help groups them apart from the commands that act.

The catalog comes from GET <origin>/docs-catalog.json (the --base-url or RECURSION_API_URL origin, public, no API key) with a 5-second timeout. It is cached per host in $XDG_CACHE_HOME/recursion/ (default ~/.cache/recursion/), used unchecked for the response's max-age, then revalidated by ETag. When the API cannot be reached or answers with something unreadable, the cache answers, and without one the copy bundled with the CLI does.

Output is text; --json prints { "ok": true, "data": ... } with the catalog entry or list. A recipe's Related links print as the recursion recipes, recursion explain, and recursion tutorials commands that open them. An unknown id exits 2 and names near matches.

recursion managed-agents <command> --help reads only the bundled copy, so help never waits on the network: the command's input fields (top-level path, query, and header fields, then body fields, with type, whether required, allowed values, and description) and a minimal example input, both derived from its JSON schema, then the recipes that use it.

src/generated/docs-catalog.generated.ts is ignored and materialized by yarn generate prerequisites. yarn generate recursion:docs-catalog regenerates all catalog copies; its --check flag checks the tracked API and web copies. Do not edit the generated copies.

Agent skill

recursion skills install [--agent claude|codex|all] [--force]
recursion skills check [--agent claude|codex|all]

install writes the catalog's recursion skill to ~/.claude/skills/recursion/SKILL.md and ~/.codex/skills/recursion/SKILL.md (both by default), with a skill-version: <version> line added to its frontmatter. Run again, it replaces a copy of an older version it installed and leaves a copy edited by hand alone unless --force. check reports each copy as installed-current, installed-stale, installed-modified, or missing. Both read the catalog as the documentation commands do, so a newer skill the API serves updates stale copies, and both exit 3 when a copy does not end current.

Agent folders

recursion managed-agents validate agents/field-agent
recursion managed-agents plan agents/field-agent --target canary
recursion managed-agents apply agents/field-agent --target canary
recursion managed-agents export "Field Agent" agents/field-agent-copy

An agent folder declares one managed agent as files: an agent.yaml manifest, the Markdown and shell files it references, and optional targets/<name>.yaml overlays. The three commands use the same global options and RECURSION_API_KEY as every other command, so the organization is chosen by the caller and never written in the folder. agents/ at the repository root holds the checked-in folders.

| Command | Network | Result | | --- | --- | --- | | validate <folder> | None. Needs no API key and builds no client. | Checks the manifest, every referenced file, and every target, or only --target. | | plan <folder> --target <name> | Reads only. | Reports each resource, its action, and the names of the fields that differ. | | apply <folder> --target <name> | Reads, then writes. | Makes the organization match. A second apply writes nothing. | | export <agent> <folder> | Reads only. | Writes a live agent version as a new agent folder that apply can recreate in another organization. |

--target is required for plan and apply whenever the folder has a targets/ directory.

Exporting an agent

export takes an agent id or exact name and a folder that does not exist yet or is empty. --agent-version <number> picks a version (default: the latest), --environment <name> declares that environment in the folder, and --key <key> sets the manifest key (default: derived from the agent name).

The folder references vaults and credentials by name only and carries no organization or resource id, secret, or ownership marker. Each selected credential becomes an exact expectation (its name or secret name, type and permission), so apply refuses a target where it matches none or several. Skills are expanded the way a session loads them. MCP servers keep their tool allowlist; their headers are dropped, since a header may carry a secret. Without --environment, the folder declares a new Runs environment named after the key.

What a folder cannot declare is listed instead of written: integrations, model settings, the template, file history, the concurrent session limit, the default project and evaluator, metadata, memory settings, team members that are other agents, skills with bundled files, and vaults with no nameable selected credential. Each item is one not_exported output line and is repeated as a comment at the top of agent.yaml. The folder is validated before it is moved into place, so a failure leaves nothing behind. Apply it into a fresh organization: an omitted field such as the rubric leaves an existing agent's live value alone.

Output and exit codes

Output is the newline-delimited JSON of the automation contract. plan and apply print one target line naming the manifest, the target, and the organization the API resolved; one resource line per resource with its kind, name, action, and changed fields; and one summary line with changes, inSync, and writes. Lines carry names and field names only, never a prompt, a script, an id, or any other field value.

Actions are create, update, adopt, unchanged, no_longer_managed, and, for the resources a manifest only references, verified, missing, and ambiguous.

| Exit code | Meaning | | --- | --- | | 0 | validate passed, plan found the organization in sync, or apply converged. | | 1 | A request failed, a required reference is missing or ambiguous, or setup verification did not pass. | | 2 | The arguments or the folder are invalid. | | 3 | plan found differences. |

Manifest reference

agent.yaml is strict YAML: an unknown field, a duplicate key, an anchor, or an alias is an error. Every path is relative to the folder and must stay inside it, symlinks included. A referenced file is UTF-8 and at most 512 KiB; a YAML file is at most 64 KiB. Any value or line shaped like a credential is refused.

| Field | Meaning | | --- | --- | | version | 1. | | key | Lowercase manifest key. It is the first part of every ownership marker, so changing it disowns the existing resources. | | agent.name, agent.model, agent.webSearch | Required. The model must be one the organization lists. | | agent.description | Optional. Omitted leaves the live description alone. | | agent.systemPromptFile | The system prompt. Trailing whitespace is not sent and is never a difference. | | agent.rubricFile | Optional. A Markdown rubric of at most 256 KiB with at least one list item; each list item is one criterion. Every session of the agent that starts with a message is graded against it by default. Omitted leaves the live rubric alone, and an empty file clears it. Trailing whitespace is never a difference. | | agent.multiagent | Optional complete portable roster: type: coordinator, agents containing self entries (optional name), optional team, limits, and slack_reply_review: {model}. Omitted preserves the live roster; declared owns the whole value. All declared models are checked before writes. Catalog agent references remain console-managed because folder declarations contain no resource IDs. | | agent.oversight | Optional complete oversight block: advisor and supervisor (each optional mode and model) and interventionist (optional mode). A mode is off, shadow or active; omitted, it is the deployment's default. A peer without model runs on the agent's model. Omitted preserves the live block; declared owns the whole value. Peers that run on another agent remain console-managed, and export refuses an agent whose block names one (oversight.<implementation>.agent). | | agent.mcpServers | name and HTTPS url pairs, compared in any order. Optional headers (static, non-secret header names to values sent on every request to the server; names the platform sets, such as Authorization, are refused at apply) and optional allowedTools (at least one tool name; a session is offered only those tools of the server), and optional approval (tools: 1 to 64 distinct tool names, each also in allowedTools when that is set, or ['*']; approvers.slackUserIds: 1 to 25 distinct Slack user ids who must approve each exact call before a gated tool runs). A secret belongs in a vault credential bound to the same URL. A header, allowlist or approval change alone publishes a new agent version. | | agent.disabledIntegrationMcpProviders | Integration providers whose MCP tools sessions do not receive. | | agent.skills | name and optional displayTitle, in the order the agent lists them: a reorder alone publishes a new agent version. Each is exactly skills/<name>/SKILL.md, whose frontmatter name must equal the directory; bundled skill files are not supported. | | agent.defaultVaults | Names from vaults. The agent defaults to these vaults, narrowed to the credentials the manifest expects. | | environment.name, environment.provider | Required. provider is runs or docker. | | environment.setup | scriptFile and timeoutSeconds (10 to 3600, default 600). Omitted leaves setup alone. | | environment.onCreate | networkPolicy and privileged, sent only when the environment is created. | | environment.image | Optional expectation. The platform assigns the image; a difference is noted on the resource line and never written. | | vaults | Required vaults by name, each with expected credentials: a type plus any of name, namePrefix, nameContains (one of these, case-insensitive for nameContains), permission, provider (an env_var credential's proxied service, such as github_packages_npm; a credential whose secret would reach the sandbox does not match), and secretName. | | automation.name, automation.promptFile | The automation's display name and literal opening prompt. | | automation.vaults | Names from vaults granted to every run, limited to the credentials their expectations matched, as agent.defaultVaults is; apply replaces a console credential selection. Omitted leaves the grant to the agent's defaults and the operator. | | automation.triggers | Slack and schedule triggers, each with a stable UUID id. A Slack trigger has type: slack, events, channels, botEvents, and optional ignoreThreadReplies, fromUserIds (Slack user or bot IDs), fromUserGroupIds and notFromUserGroupIds (Slack user-group IDs), textMatches (case-insensitive RE2 pattern), classifier (an AI filter: question, answers of value and description, and a rule of when (wake or skip) and conditions, each an answer and an atLeastPercent (5 to 95); any condition holding does when, none holding does the opposite. Optional mode of preview or on (default preview) and send of text_and_images or text; null removes a console-set one), allowSharedChannels, continuation (new_session or resume_thread), firstResponse (none or platform), and enabled; every Slack trigger must agree on continuation and firstResponse. With platform, a message trigger's automatic root that mentions nobody gets its acknowledgement, reaction and native status at the agent's first tool call rather than at dispatch, so an informational post the agent leaves alone shows nothing; mentions are acknowledged at dispatch. A schedule trigger has type: schedule, a five-field cron, an IANA timezone, and optional overlapPolicy (default skip), jitterSeconds (default 10), catchupWindowSeconds (default 900), and enabled. |

targets/<name>.yaml holds the values that differ between rollouts of the same resources:

| Field | Meaning | | --- | --- | | slackEventSource | Display name of the Slack event source the Slack triggers listen on. Required when the manifest has Slack triggers. | | channels | Named lists of Slack channel ids. A trigger's channels names one; an empty list accepts every channel, or, when several organizations share the Slack workspace, every channel no other organization lists (runbook). Every list must be used. |

Targets are overlays, not identities: two targets applied to one organization reconcile the same agent, environment, skills, and automation.

Ownership and adoption

Every resource a manifest owns carries the metadata key recursion_managed:

| Resource | Marker value | | --- | --- | | Agent | <key>:agent | | Environment | <key>:environment | | Automation | <key>:automation | | Skill | <key>:skill:<skill name> |

Ids are derived from the marker on every run by listing the organization, every page of it. Nothing is stored in the folder and there is no state file.

  • Exactly one resource carrying the marker is the resource, whatever it is named now.
  • With none, exactly one unmarked resource of the declared name is adopted: it is stamped with the marker and updated in place.
  • With none of either, the resource is created.
  • Two or more candidates stop the run before any write.

Vaults, credentials, the Slack event source, and the model are references, not owned resources. They are resolved by name and verified before the first write and are never created, changed, or marked. A missing or ambiguous one fails plan and apply with exit code 1. Credential values are never read.

Nothing is ever deleted. A skill or automation that still carries the marker after the manifest stopped declaring it is reported as no_longer_managed.

What apply writes, and what stays the operator's

After every reference and ownership lookup has resolved, apply writes in dependency order:

  1. Environment. Created or patched, then verified: a new or changed setup starts a setup run and waits for its verdict, and a failed verdict stops the run before the agent is written.
  2. Skills. A new skill version only when the SHA-256 of SKILL.md, the display title, or the marker differs.
  3. Agent. A new agent version only when a declared field differs, written as a compare-and-swap on the version that was read. A lost race is answered by reading and diffing again, once.
  4. Automation. Created paused. An existing one is replaced under its ETag with If-Match, with one re-read on a stale validator, and its agentVersionId moves to the agent's latest version.

An apply that fails partway is repaired by running it again: each step diffs live state before writing.

These are read and carried through unchanged, or never sent:

  • The environment's network policy and Docker privilege after creation.
  • The agent's built_in_integrations, nativeIntegrations, model_config, multiagent and oversight when undeclared, template, fileHistoryEnabled, and max_concurrent_sessions, defaultProjectId, defaultEvaluatorAgentId, and any extra keys on a declared MCP server.
  • Every metadata key other than recursion_managed.
  • The automation's paused or active status, and its run defaults other than vaultIds.
  • On each Slack trigger, matched by its id: the textContains and textExcludes filters and the workspaceIds routing restriction. The folder owns fromUserIds, fromUserGroupIds, notFromUserGroupIds, textMatches and classifier when it declares them; otherwise their live values are carried through an apply. Declaring classifier: null removes a console-set AI filter.
  • Every trigger of a type the folder cannot declare, such as a webhook or GitHub trigger added in the console. Member-DM Slack triggers are also carried whole: agent folders cannot declare them, and a declared trigger with the same id is rejected before writes. When one is present, declared Slack triggers must use continuation: resume_thread and firstResponse: none; a conflicting folder is rejected before writes. Manage these bindings through the automation API.
  • On each schedule trigger, matched by its id: its startAt and endAt.

Ordinary Slack and schedule triggers themselves belong to the manifest: one added in the console that the folder does not declare is removed by the next apply.

Agent skills

recursion managed-agents get-agent-skill-disclosure --input-file request.json
recursion managed-agents agent-skills --input-file request.json

A session lists skills to the model in the agent's saved order, with each group expanded in place. When the list is longer than the budget the model's context window allows, descriptions are dropped from the end, and the model is shown those skills by name only.

Two commands report that list for a saved agent. Both take get-agent's input, { "agentId": "<agent id>" }, and write nothing.

  • get-agent-skill-disclosure is the generated command for the API's own read, and returns the service's answer in one call: budget_chars, used_chars, entries in the order the model reads them, and warnings. It answers for the agent's latest version against the budget of the agent's own model, whichever model that is, and it lists and counts the platform skill that a session of an agent with built-in integrations lists first. Each entry of an attached skill carries attachmentIndex, the zero-based position of its attachment in the agent's skills, and a catalog skill's entry carries skillId.
  • agent-skills is handwritten. It composes three reads, of the agent, the model catalog, and the skill disclosure preview, into one line, and adds a position for every skill and nameOnlyFromPosition.

Use get-agent-skill-disclosure when the answer has to be the service's own: for an agent on a model the catalog no longer lists, for an agent with built-in integrations, or to learn which attachment to move. Use agent-skills for a line that already says where descriptions stop, next to the agent's model, version, and saved attachments. It prints what the console's Skills section shows, and differs from the service's answer in the two cases described below its output.

agent-skills writes one success line of the automation contract:

| Field | Meaning | | --- | --- | | agentId, agentVersionId, model | The agent, its latest version, and its model, as read. | | contextWindowTokens | The model's context window from the model catalog, or null when the catalog lists none. | | budgetChars, usedChars | The characters the skill list may spend in the prompt, and the characters it spends. | | skills | The agent's skills in the order the model reads them: position, counted from 1, name, and descriptionIncluded. | | nameOnlyFromPosition | The position of the first skill shown by name only; every skill after it is name only too. null when every description fits. | | attachments | The agent's saved skills array, in saved order. A group is one attachment and several skills. The line does not say which attachment a skill came from; attachmentIndex in get-agent-skill-disclosure does. | | warnings | The preview's warnings, unchanged, after one of this command's own when the budget is only a lower bound. |

The model catalog lists the models offered to new agents. An agent on a model it no longer lists still runs, on a context window agent-skills cannot read. Its line is then measured against the smallest budget any model gets, and the first warning says so: a session of that agent may keep more descriptions. get-agent-skill-disclosure measures against that model's own budget.

A session of an agent that uses built-in integrations also lists one skill of the platform's own first, which skills and usedChars do not include. get-agent-skill-disclosure lists it first and counts it.

Invalid input exits 2 and a failed request exits 1. get-agent-skill-disclosure fails with not_found for an agent that does not exist, and with invalid_request on model for an agent whose model can no longer start sessions.

To move a skill above nameOnlyFromPosition, reorder agent.skills in an agent folder and run apply, or call create-agent-version with the agent's full definition and the reordered skills array. A group's skills keep their creation order and move together with the group's entry.

Run an automation and wait

recursion run-automation "$AUTOMATION_ID" --payload-file payload.json --timeout 1800
recursion wait-automation-run 33333333-3333-4333-8333-333333333333 --require-grade
recursion run-automation "$AUTOMATION_ID" --require-output --summary-file summary.md
recursion run-automation "$AUTOMATION_ID" --no-wait

These commands require @labelbox/recursion-cli 0.2.0 or later; 0.1.0 does not include them.

AUTOMATION_ID is the automation's UUID, from managed-agents list-automations or the console; automations are not addressed by name.

run-automation starts a run of a canonical automation and waits for its result; wait-automation-run attaches to a run started elsewhere, such as by a webhook. Both use the SDK's runAutomationAndWait and waitForAutomationRun, which long-poll the run's result endpoint (GET /managed-agents/v1/automation-runs/{automationRunId}/result, the generated managed-agents get-automation-run-result) until the server reports the run finished: the server waits and decides the verdict. The retries and timeout cancel are the ones the SDK README describes. The commands are top-level because managed-agents run-automation is the generated API call, which only starts the run; --no-wait does the same and prints the run.

The payload is any JSON value, read from --payload-file or --payload-stdin (never from an argument); without one the run starts with {}. --idempotency-key sets the start request's replay key (default: a random UUID). --timeout is in seconds (default 1800, at most 86400); when it passes the session is cancelled unless --no-cancel-on-timeout.

Progress goes to stderr, one {"progress": {...}} line per state change or retry, each with a human message. The result is one {"ok": true, "data": ...} line on stdout: the server's result (state, verdict, reason, reasonMessage, run, session, outcome, output, finalMessage, artifacts, ...) plus timedOut, sessionCancelled, and elapsedMs. On a timeout verdict is absent and timedOut is true. An API error the helper cannot retry is a request failure on stderr, with the run and session ids known so far. A timeout before the start is acknowledged, or before the result could be read once, has no result: it exits 4 with a timeout failure on stderr and writes neither file. When the start had already named the session, that session is still cancelled unless --no-cancel-on-timeout, and the failure says whether the cancel worked. After an unacknowledged start that failure carries idempotencyKey; the run may have been admitted, so rerun with --idempotency-key <key> to replay it rather than start a second one.

--require-grade fails an ungraded completed. --require-output fails a run that would otherwise exit 0 but has no valid structured output: neither a valid file at the automation's declared runDefaults.output.path nor, without one, JSON in the final message. A missing or invalid declared file already makes the server's verdict error.

Standard output holds the whole result, including what the agent wrote, so in a CI job send it to a file (> result.json). The job log then shows nothing from the agent: standard error carries only ids, states and request errors.

--summary-file <path> appends a Markdown summary: the verdict, reason code, run and session ids, cost and artifact count. It holds text the agent wrote only with --summary-details, and a job summary can be public in a public repository. --summary-details adds the explanation, session status, the outcome and its per-criterion verdicts and rationales, the output JSON in a code block, the final message in a collapsed block, and a table of artifacts (path, size, file id). Every value from the run is untrusted, so table cells are escaped and the code blocks use fences no backtick run in them can close; the output and final message blocks are cut at 64K characters. --outputs-file <path> appends verdict (timeout on a timeout), automation-run-id, session-id, reason, final-message, output-json (the valid output as compact JSON, else empty), artifacts-json, and result-json in GitHub's multiline-safe name<<delimiter form; a value over 900 KiB is written empty, since GitHub limits an output to 1 MB. Point them at $GITHUB_STEP_SUMMARY and $GITHUB_OUTPUT.

To fetch an artifact, pass its fileId to get-file-content, which prints the bytes in the $recursionBinary base64 envelope:

echo '{"fileId": "'"$FILE_ID"'"}' \
  | recursion managed-agents get-file-content --input-stdin \
  | jq -r '.data["$recursionBinary"].base64' | base64 --decode > result.json

| Exit code | Meaning | | --- | --- | | 0 | passed, or completed without a grade unless --require-grade; with --require-output, only when the output is valid. | | 1 | A request failed. | | 2 | The arguments or the payload are invalid. | | 3 | Not passed: failed, needs_attention, cancelled, error, ungraded under --require-grade, or no valid output under --require-output. | | 4 | Timeout, or the timeout passed before the run was started or its result read. |

Generated authority

src/generated/operation-registry.generated.ts is ignored. The shared typed Recursion client projector derives command identity, request schemas, media types, and conditional-response metadata from the tracked canonical public OpenAPI for both the SDK and CLI. Repository setup, build/check prerequisites, package archives and docs-catalog generation materialize the registry before consuming it. Canonical public-contract freshness and production release qualification remain required.

Regenerate only this projection with:

yarn generate recursion-cli
yarn generate recursion-cli --check  # verify an already materialized copy

The bundled docs catalog is also ignored. yarn generate prerequisites materializes both CLI projections without updating the tracked API or web catalog. For the raw CLI workspace build, check, test or type-check scripts, run yarn dx setup:repo first: these also consume compiled SDK/library outputs. Repeat preparation after removing ignored outputs or changing their inputs.

Do not edit the generated registry. Change the canonical contract or the shared projector instead. Dual-media operations use their JSON SDK envelope. An operation whose only request body is multipart remains available in the SDK but is omitted from the CLI instead of receiving a misleading JSON command.

Release contract

The publishing job uses the main-only recursion-cli-npm GitHub environment. The CLI is still beta, so publishing does not require a human approval today; the team plans to add that gate when the package reaches 1.0. Generation, builds, qualification, and post-publication verification run outside the publish job.

The manual Release / CLI workflow builds exact SDK and CLI archives, proves the source contract against production, and publishes the qualified CLI bytes through npm Trusted Publishing under the latest dist-tag. The SDK remains on preview, and the CLI archive pins its exact SDK dependency. After publication, an artifact-only verifier downloads the public npm tarball, checks its SHA-256 and SHA-512 against the qualified archive, and gates source tag creation on a match. The workflow retains the qualification receipt and registry-observed digests as private run evidence for 30 days; the candidate archive itself remains a 14-day handoff. Source manifests retain placeholder version 0.0.0; the workflow stamps and tags the reviewed preview version.

Run from a repository checkout

node tools/scripts/install.ts
yarn dx setup:repo
yarn workspace @labelbox/recursion-cli check
yarn workspace @labelbox/recursion-cli test
yarn workspace @labelbox/recursion-cli build
node packages/recursion-cli/dist/bin.js --help

Slack automation triggers in an agent folder can set dmEnabled: true to offer the automation in the Recursion Slack app's DM picker. Set it to false to remove DM access; omitting it preserves the live setting during reconciliation. Only active automations with enabled triggers appear. fromUserIds restricts DM callers; without it, workspace users can invoke the configured automation.