Skip to main content
@hue-run/sdk includes the hue command. It stores a key you create in Hue, configures your coding agent for the Hue MCP server, forwards simulated Slack events to a local bot, runs evaluations, and imports traces. Install it in the project where your agent lives:
After installation, run the commands from that project with npx hue …. Every command accepts --help. To run the latest CLI without installing the SDK in your project, use npx -y @hue-run/sdk@latest …. npx caches the package without adding a project dependency. Use npx hue only in a project with @hue-run/sdk installed; otherwise npm can resolve an unrelated package called hue. To select an exact CLI version, commit an SDK dependency and lockfile or replace @latest with that version. The CI workflow installs the latest stable runner by default and accepts an exact version for debugging.

Store your key

Create a Read and write key in Settings → API keys for the project you want to use, then run:
hue login prints the key settings page and opens it in your browser when a terminal is attached. It reads the key without echoing it, checks it against Hue, and stores it once as both HUE_API_KEY (for evaluations) and HUE_MCP_KEY (for your coding agent) in ./.env.hue, together with HUE_BASE_URL and HUE_MCP_URL. --gitignore adds that file to .gitignore. Key values are never printed. A Read key or a legacy tracing key is refused before anything is stored, because it cannot run evaluations. See Project keys for what each preset can do. --env-file PATH is also accepted for a file that already exists. Node.js 22 and 24 read --env-file from the whole command line, so when the file does not exist yet they exit with node: <path>: not found before hue runs; use --env-path to create a new file. To revoke evaluation and agent access separately, run --keys evaluations and --keys coding-agent with two different keys.

Connect your coding agent

hue mcp install writes a server named hue at https://mcp.hue.run/mcp for your client. Supported clients are claude-code, codex, conductor, cursor, vscode, windsurf and gemini. For windsurf it only prints the snippet; merge it into the configuration opened by Cascade’s … (Actions) → MCPs → Open MCP config file. See the Cascade MCP guide for that client’s configuration. Add --dry-run to see the change first, or --print for the snippet only. Without --auth, claude-code, codex, conductor and cursor sign in with Hue, and the other clients use a key. --read-only, or read_only=true or 1 in --url, selects a key instead. claude-code, codex and cursor also keep the choice of the server’s existing entry, in ./.mcp.json, ./.cursor/mcp.json or as codex mcp get reports it, so a rerun keeps a key and its read_only; for a new entry they use a key when HUE_MCP_KEY is set. For codex, when codex is on PATH but codex mcp get fails for a reason other than having no such server, the command asks you to pass --auth rather than guess. The command names its choice on stderr; pass --auth to replace an entry as given. Outside a terminal, such as in CI or a coding agent’s shell tool, a default sign-in for codex or conductor prints the codex mcp add command instead of running it, because that command signs in at once and waits up to 5 minutes for the browser. A Codex configuration sets supports_parallel_tool_calls = true, so Codex runs Hue’s calls in parallel; codex mcp add cannot set it, so after registering with Codex the command names the line to add to ~/.codex/config.toml. A printed sign-in TOML block keeps its URL bare and sends project and toolset selections as X-Hue-MCP-Project and X-Hue-MCP-Toolsets headers. MCP arguments and results use the product object’s name: for example, evaluation tools use eval_set_id, eval_set_version_id, eval_set_case_id, evaluator_version_id, run_id, scoring_run_id and scoring_item_id. Their list results are eval_sets, evaluators, runs, scoring_runs and cases; a row’s own identifier remains id. With a key, export HUE_MCP_KEY in the shell that starts your client; an app started from the Dock or a launcher does not see that shell’s variables. Then ask the agent to call list_projects and get_project_context to confirm which project it reached. The MCP guide covers connection settings, verification and what the server can do.

Receive Slack events locally

hue listen forwards a World instance’s Slack requests to your bot’s HTTP receiver. Run it beside the bot as a separate process. You do not need to import Hue into the bot, instrument each agent, or enable tracing to receive events. Tracing setup is separate if you want to record the bot’s internal model and tool calls. Use SDK 0.27.0 or later for slash commands and buttons. Run the CLI with Node.js 22.12 or later in your test environment. The same command forwards requests to a Python, TypeScript, or other HTTP bot. The CLI comes from the npm package; installing hue-run from PyPI does not install it. The bot needs an HTTP receiver, such as a Slack Bolt request handler. Socket Mode is not supported by this listener. You do not need a public callback URL for a receiver on the listener’s machine. Check the runtime and installed command before registering a subscription:
Have a runnable test copy of your bot ready. It must let you configure its Slack API URL, bot token and signing secret. Configure any business-system clients against your own test backend before sending an input that could write data.

Register the subscription

  1. Start a Slack World instance. Copy its world token and Slack Web API URL from Connect or get_instance_connections over MCP.
  2. Create a Read and write project key in Settings → API keys for registration. Load it into HUE_API_KEY in your setup shell. The project key creates and inspects the subscription; the listener uses the world token instead.
  3. Create a listen subscription. Replace the instance ID below. Keep the response file out of Git because it contains the signing secret.
The response includes the subscription id and signingSecret. Registration sends no request to the bot. One active Slack subscription is allowed per instance; reuse it or revoke it before creating another. Choose the event names your bot handles:

Configure the bot and start the listener

Put these values in your test configuration, such as an ignored .env.hue-slack file:
Wire the bot’s Slack client to HUE_SIM_SLACK_WEB_API_URL and use HUE_WORLD_TOKEN as its bot token. JavaScript Bolt uses clientOptions.slackApiUrl; JavaScript Slack WebClient uses slackApiUrl. Python Slack WebClient uses base_url. Setting an environment variable alone does not change the client: your bot must read it into that setting. Configure the HTTP receiver with SLACK_SIGNING_SECRET. Keep normal Slack signature verification enabled. The listener preserves the signed body and headers, including form-encoded commands and button payloads. Your handler must answer url_verification with HTTP 200 and the echoed challenge; Slack frameworks usually handle this. Start the bot with these values using its normal startup command. Wait until its HTTP receiver is listening, then run the listener in another terminal:
Replace the port and path with your bot’s receiver. --env-path loads values for the listener only; it does not start the bot or configure its process. The listener forwards every subscribed request to this one URL. If your bot uses separate command or interaction paths, route those requests from this receiver to the corresponding handler. localhost refers to the listener’s network namespace. For a containerized bot, run the listener in the same namespace or expose the bot’s port on the listener’s host. An off-machine receiver needs an HTTPS URL and --allow-remote-forward. The first delivery verifies the subscription. Check that GET /api/v1/event-subscriptions/<subscription ID>, authorized with the setup project key, reports verification.state: "verified". Do not call the subscription’s /verify route for listen delivery; the listener performs the handshake.

Try a message and inspect the result

Keep both processes running. Use send_instance_input over MCP to send a message as a user in the World. For commands and buttons, use a compatible listener version and the IDs of messages and buttons that actually exist in the instance. Read the reply with get_instance_state and inspect the bot’s calls with list_instance_requests. Your receiver must acknowledge within three seconds. A successful command or interaction can return an immediate reply body of at most 64 KiB; URL verification bodies are capped at 4 KiB. These responses must finish within the deadline, even when the body exceeds the capture limit. An interrupted response reports connection_failed without sending its partial body to Hue. Larger bodies are truncated, which can change the displayed reply. Ordinary event response bodies and unsuccessful response bodies stay on the listener’s machine. Return immediate replies without HTTP compression; the listener does not decode compressed receiver responses. Keep successful replies suitable for storage as test evidence. A response_url in a request authorizes later replies, so keep it out of application logs and shared output. The listener remembers recent delivery results in memory. A restart loses that memory, and the listener does not guarantee exactly-once execution. Make financial writes and other business effects safe to retry in your application.

Stop and clean up

Press Ctrl+C to stop the listener after deliveries in flight finish, then stop your test bot. Stop the World instance when the test is over; its world token expires with it. Remove the ignored .env.hue-slack and .hue-slack-subscription.json files when you no longer need their credentials. For a fresh instance, repeat the connection and subscription setup with its own values. This wiring receives Slack inputs and redirects Slack API calls. Configure any other app clients separately through Connect your agent.

Run an evaluation

hue eval runs your agent locally against a published case or a saved eval set and prints Hue’s verdicts. Your agent, prompts and model credentials stay on your machine. It reads HUE_API_KEY from the environment, or from ./.env.hue, the file hue login writes, when the environment has none; --env-file <path> names another file. Start the agent’s own command with --command, after the one-time change in Connect your agent:
See Run your agent for one-shot runs, --check, recovery, and the shared CI configuration and reports. hue eval needs Node.js 22 or 24, even for a Python agent. --command starts the command once per case with {"inputs","config"} as JSON on stdin and reads the answer from stdout. For a case with a simulated world, the command receives the world’s variables; the eval-ready guide lists them under Run it and shows the one committed helper that reads them, so the agent reaches each app through Hue’s mirror with its own production client and never receives Hue-native tools. Only the current case’s world sets those variables: a value inherited from your environment never reaches the command. A direct case has no simulated world: it sets HUE_EXECUTION_ID and case variables without a world token, app mirrors or MCP connection. Skip optional app initialization and fail closed if the agent needs a missing app connection. HUE_CASE_INPUTS names the inputs file, the case’s input files are under files/<role>/, and every file the command writes to HUE_CASE_OUTPUT_DIR is uploaded as a generated file for grading. A one-shot direct case starts in that private case directory, so use an absolute entry-point path; a command worker keeps the directory where you started the CLI for both direct and world cases. The command inherits your environment except Hue’s own credentials: HUE_API_KEY, HUE_MCP_KEY and any other variable holding a Hue key are removed unless you pass --allow-hue-credentials, so your model keys and settings still reach the agent but the project key does not. --worker registers your agent so runs started from Hue, from the Run button or the launch_run MCP tool, execute on your machine with the same handoff. Command workers register both direct:v1 and environment:v1, so one worker can run answer-only cases, world cases or an eval set containing both. Use a new --revision when upgrading an existing worker: a registered revision’s capabilities cannot change. One-shot exit codes: 0 every case passed; 1 a case failed, errored, is inconclusive or is incomplete; 2 usage error; 130 interrupted. hue eval --help lists every flag. One-shot runs store case outputs, target error messages and explanations by default, as workers already do. Trace content capture is on by default; --no-content opts out. Use --no-output to omit result content and skip hosted model judges in a one-shot run, or --no-output --no-content to omit both results and telemetry content. Resume an older metadata-only run with --no-content and its original output policy. A command’s stdout becomes its stored answer, with credentials handed to it by hue eval redacted; keep credentials and debug logs out of stdout. Generated files are uploaded regardless of --no-output and are not fully redacted, so never write credentials into them. CI also accepts captureContent and persistResultContent in its configuration. Both default to true; CLI flags override them. See CI content settings for recovery and generated-file limits. These runner settings do not configure your agent’s own instrumentation. An evaluator that does not apply to a case shows n/a and neither passes nor fails it. A case with no applicable pinned evaluator is an error. A TypeScript adapter file (./hue-agent.ts exporting runMyAgent(inputs, context)) is the in-process alternative. It runs inside hue eval’s own process, where HUE_WORLD_TOKEN and HUE_EXECUTION_ID are not set, so pass the execution context to the helper. A world-only adapter throws when context.world is missing, then passes context.world.env as the helper’s environment argument or spawns the agent with agentEnvironment(context.world). A direct adapter receives context.mode: "direct" and context.executionId; pass { HUE_EXECUTION_ID: context.executionId } to the helper and skip app connections. Adapter-file workers register world support by default; opt into direct cases with --capability direct:v1 only after handling that context. Never set process.env yourself: with --concurrency above 1 it leaks one case’s world into another. See the World handoff reference for what the adapter receives and the TypeScript reference for the underlying local-run APIs.

Hosted verifiers

See Hosted verifiers to run approved private code on Hue, and Hosted judges to grade outputs with a model. Those guides cover setup, concurrency, results, and Hue-funded allowances.

Import traces from Langfuse

hue import langfuse copies a Langfuse project’s traces, and optionally its media, into Hue. It runs on your machine: it reads Langfuse’s public API with the Langfuse project’s own keys, which go only to Langfuse, and sends the spans with your Hue project key. It runs with npx whatever language your application uses; the Python SDK has no counterpart. Put the Langfuse keys in an env file kept out of version control, count what would be imported, then import:
The secret key is read only from LANGFUSE_SECRET_KEY in the environment or the env file, never from the command line, where shell history and other processes can read it. The Langfuse host is --langfuse-host, then LANGFUSE_BASE_URL, then LANGFUSE_HOST, then https://cloud.langfuse.com; use your region’s host or your self-hosted URL. HUE_API_KEY comes from the environment, the env file or ./.env.hue; the Read and write key hue login stores works. The command checks it against Hue before it reads Langfuse. The command reads Langfuse Cloud and self-hosted Langfuse v4 through the Observations API v2, and self-hosted v3 through the v1 traces and observations API. Each observation becomes the completed span a Langfuse OpenTelemetry SDK records, with the langfuse.observation.* and langfuse.trace.* attributes Hue reads, the user, session, release and environment, and the model and token counts as GenAI attributes; see Use with Langfuse. A span whose observation records an environment also carries it, as recorded, in hue.import.source_environment. The environment label does not affect World capture. Content is sent by default. Inline files and values over the 1 MiB inline limit are placed as the SDK places them, but stored before their span is sent. Without --media, Langfuse media references stay as recorded, and Hue shows them as files held in Langfuse. With --media, each referenced file up to 25 MiB is downloaded from Langfuse, uploaded under its trace and placed in the digest form the SDK writes. The download link and each of up to five redirects must use HTTPS without credentials and reach a public address or the Langfuse host; a link to this machine, a private network or a link-local address fails the file. When the Langfuse host is on this machine, any address is accepted, as is plain HTTP to this machine. A reference Langfuse holds no bytes for stays as recorded. Langfuse ids are kept as OpenTelemetry ids where they already are one, and other ids are derived from them, so running the same command again resumes an interrupted import without duplicating what Hue already holds. Keep --media, --no-content, --service-name and the SDK version the same when you resume, and leave traces that already reached Hue through OpenTelemetry out of the window. A file or value that cannot be stored holds its span back for the next run. Langfuse 429 answers are waited out for as long as Retry-After asks. The summary reports the traces imported, the spans sent and accepted, and the media files uploaded and left in Langfuse, and names each trace not fully imported with the reason. Exit codes: 0 every selected trace was imported, 1 a trace, span or file was not (or a key was refused), 2 usage error, 130 stopped; run the same command again to resume.

Import exported traces

hue traces import brings a bundle of trace exports you already hold into a Hue project, in the formats Bulk import existing traces lists. Your coding agent runs the two commands as part of that workflow; the Hue MCP server authorizes the upload, so no project key is involved.
prepare reads the file, directory or ZIP archive at <path> on your machine, writes the prepared import to the directory and prints its report, with the manifest digest and totals the agent passes to prepare_trace_import. It sends nothing. upload sends the prepared traces to Hue with the authorization the agent saved to the file, two requests at a time, and checks every receipt. Run it again after an interruption to resume. Unlike hue import langfuse, which reads a live Langfuse project through its API, traces import takes files you already hold. Exit codes: 0 prepared or completed, 1 not completed (the report says what to do next), 2 usage error, 130 stopped; run the same command again to resume.