Architecture and contributor reference for the runx OSS repo: the CLI surface, the trusted Rust local runtime, generated contracts, extension protocols, SDKs, harness, local receipts, registry, official skills, and packaging. For the overview and quickstart, start at the README.
The npm CLI package is @runxhq/cli and exposes the runx binary.
Start with the checked-in hello-world skill:
cargo build --manifest-path crates/Cargo.toml -p runx-cli
export RUNX_RECEIPT_DIR="$(mktemp -d)"
crates/target/debug/runx skill examples/hello-world \
--message "hello from docs" \
--non-interactive \
--jsonOn macOS 26, complete the Developer Tools permission prerequisite if the initial build stalls.
When no production signer environment is configured, local runx skill and
inline runx harness runs seal local-development receipts. Publishing and
hosted verification require real authority.
Then inspect the emitted receipt. The full walkthrough is in getting-started.md, and the next step is skill-to-graph.md. For governed code changes, see issue-to-pr.md.
Run the local payment dogfood lane without a funded wallet, hosted account, or provider keys:
pnpm x402:dogfood:localThis proves runx payment authority, refusal, receipt signing, offline receipt
verification, and the documented x402 upstream/x402-rs/CDP/Stripe SPT preflight
shape. It does not claim real x402 settlement or a real Stripe charge; live
conformance lanes require dedicated funded testnet wallets or provider test
credentials. No-secret preflight reports use can_run: false and missing_env
to name live blockers without printing secret values. See
docs/demos.md for the full split between
local dogfood and live protocol conformance.
Native CLI:
- Rust 1.97+
- The native Rust CLI path must stay useful without Node, pnpm, tsx, or TypeScript packages installed.
Workspace and npm wrapper:
- Node.js 20+
- pnpm 10+
pnpm install
pnpm build
pnpm test
pnpm typecheck
pnpm verify:fast
pnpm rust:checkContributor setup, test selection, and commit sign-off rules are in CONTRIBUTING.md.
For a live creator workflow, link the global runx binary to this checkout once:
pnpm cli:link-globalThen invoke the linked runx binary from anywhere. Use explicit paths outside
a runx workspace; bare skill names resolve from the current workspace's
skills/ directory.
runx --help
runx skill /path/to/runx/oss/fixtures/skills/echo --message hello --json
cd /path/to/runx/oss
runx skill ./skills/skill-lab design --objective "build sourcey docs skill" --jsonRecommended flows:
runx init
runx init -g --prefetch official
runx new docs-demo --objective "Create a bounded documentation decision skill"
runx list skills
runx registry search sourcey --json
runx skill sourcey/sourcey@1.0.0 --registry https://runx.example.test --project . --json
runx add sourcey/sourcey@1.0.0 --registry https://runx.example.test --to ./skills --json
runx skill issue-to-pr --fixture /path/to/repo --task-id task-123
runx resume <run-id> answers.json
runx history <receipt-id> --json
runx history
runx mcp serve ./fixtures/skills/echo
runx skill ./skills/skill-lab design --objective "build github review skill"
runx harness ./fixtures/harness/echo-skill.yaml
runx config set agent.provider openai
runx config set agent.model gpt-5.1
printf '%s' "$OPENAI_API_KEY" | runx config set agent.api_key --from-stdinThe resume file keeps agent work and human authorization distinct:
{
"answers": {
"agent_task.example.output": {
"result": {}
}
},
"approvals": {
"provider-effect:example": {
"approved": true,
"reason": "I authorize this exact provider action."
}
}
}Only entries under approvals carry host-attested human approval provenance.
The local CLI cannot authenticate a person from JSON: by placing a decision
there, the host asserts that a human approved the exact pending gate. An agent
must never author or promote that entry; it returns the pending approval to its
human or to an integrated host that authenticates the decision. Never place a
consequential decision under answers; that section records agent or
caller-supplied work and cannot resolve an approval gate. Runx rejects an agent
response presented to an approval request. The pending run's answers_template
contains the exact request ids to resolve.
Hosted and replay drivers may bind runx skill or runx resume with
--package-digest and --execution-closure-digest. Runx recomputes both at the
native execution boundary, persists them in pause checkpoints, and rejects a
resume whose supplied bindings disagree with that checkpoint. These flags bind
execution; they are never skill inputs. The closure digest includes the
immutable Runx release identity, so a pending continuation cannot silently
cross a runtime upgrade. Runx-generated run ids and durable graph state bind
the same package and execution-closure digests, so changing a skill, transitive
child package, or runtime closure cannot merge incompatible checkpoint history.
Execution ceilings remain owned by the capability they constrain rather than being flattened into one misleading global number: an MCP call timeout, an outbox timeout, a native command argument budget, and a file-bundle budget are different contracts. Their constants use capability-qualified names. Limits that are selectable per invocation or materially shape a sealed execution are typed at the invocation boundary; deterministic-module limits and any limit hit are copied into signed receipt metadata.
Credential redaction and untrusted-data admission are also distinct. Exact values delivered by Runx enter the run-scoped taint set and are scrubbed at every output boundary. External configuration and provider output can contain raw material Runx never delivered, so those narrow boundaries additionally reject exact secret-field names before the data can enter receipts. That check is not a general text heuristic and never removes URLs or unrelated operator diagnostics.
With agent.provider, agent.model, and agent.api_key configured, the CLI
can now resolve managed agent work directly. Deterministic tools, approvals,
and required human inputs keep their existing local behavior.
Prepared context never asks for performative approval: it binds the selected skill, inputs, execution closure, and drift guards into the receipt. A consequential action stops once at its owning boundary—an effect-owned gate for native provider mutation, or an explicit graph approval when no native effect owns the decision. There is no persistent or environment-based auto-approval override; development configuration must not silently acquire live authority.
Provider-backed skills declare requirements in X.yaml; configure them with
runx credential or an ignored workspace .env. See
Credential Resolution for the exact precedence and storage
contract.
Ctrl-C (or the terminal's configured interrupt shortcut) interrupts the whole active Runx context, including supervised tool, JavaScript, adapter, and MCP child process groups. Runx allows a two-second cleanup window, exits with status 130, and treats a second interrupt as an immediate exit. On macOS, Cmd-C is normally copy; Ctrl-C is the interrupt.
runx skill ... --json and runx resume ... --json return the canonical
runx.skill_run.v1 envelope. A sealed run has one caller-facing result, a compact
trace for graph runs, the terminal closure, and the receipt_id needed for
independent inspection:
{
"schema": "runx.skill_run.v1",
"status": "sealed",
"skill_name": "example",
"run_id": "run_example_123",
"receipt_id": "sha256:...",
"closure": { "disposition": "closed" },
"result": {},
"trace": {
"graph": "example-read",
"status": "succeeded",
"steps": [
{
"step_id": "read",
"skill": "provider.read",
"status": "success",
"receipt_id": "sha256:..."
}
]
}
}result is the selected runner's normalized output or the declared contract of
a graph's terminal successful producer. trace deliberately carries
references rather than step payloads. Intermediate graph state, child receipts,
and the full signed receipt are written to the local Runx state and receipt
stores; process output identity is committed by the receipt. Inspect proof
through runx history and runx verify instead of paying to copy it through
every agent response. Paused runs keep their exact requests and resume
instructions.
Use per-key --input and --input-json flags for small interactive calls. For
generated or reusable input, pass the complete runner input object through one
workspace-contained JSON document:
runx skill ./skills/research research --inputs request.json --json
cat request.json | runx skill ./skills/research research --inputs - --json--inputs is exclusive with every per-key input form. A file path is resolved
relative to the invocation workspace and must identify one contained, regular,
UTF-8 file. File and stdin input are capped at 64 MiB, must decode to exactly
one JSON object, and then enter the same selected-runner defaulting and type
validation as inline inputs. Runx does not echo a rejected document in its
diagnostic.
This is a control-document transport, not a high-volume execution profile. Put large immutable content behind the digest-bound artifact/page boundary and put durable histories behind data cursors rather than carrying either through graph context.
The global link points at packages/cli in this checkout. Rebuild with
pnpm build; do not reinstall.
Rust owns the trusted local runtime path. The Rust crate graph is the enforced boundary map:
runx-contracts: domain-neutral Rust contract types plus shared schema emission and reconciliation; domain crates contribute the contracts they own.runx-core: pure state-machine and policy decisions.runx-parser: pure skill, graph, runner, and tool manifest parsing.runx-receipts: canonical receipt model, hashing, signatures, and tree verification.runx-runtime: impure local runtime, adapters, exact process invocation and supervision, harness replay, journals, registry clients, payment gates, MCP, and execution.runx-cli: nativerunxbinary over the runtime.runx-sdk: blocking CLI-backed SDK over stable contracts.
The TypeScript package graph is the client, protocol-extension, wrapper, and generated-contract layer:
@runxhq/contracts: generated validators and TypeScript types over the Rust-owned schema artifacts.@runxhq/cli: npm distribution wrapper and client presentation around the native CLI.@runxhq/contracts,@runxhq/extension-sdk,@runxhq/host-adapters, and@runxhq/langchain: generated contracts plus narrow process/protocol, host-presentation, and bridge packages over language-neutral contracts.
For the generated package export index, see docs/api-surface.md.
runx-runtime is the canonical local runtime. It owns local skill, graph,
harness, receipt, history, policy, authority, payment, typed
execution-boundary evidence, MCP, built-in adapter execution, and external
execution-adapter supervision for the native CLI path.
TypeScript remains for generated contracts, CLI/client wrappers,
cloud/product integrations, host adapters, and protocol helper SDKs over
language-neutral protocols. Host adapters can shape host responses over
the runx host protocol; they do not own local execution. External execution
adapter authors target manifests and wire protocols, so they do not need Rust,
runx-core, runx-runtime, or a fork of the core repository. Source-event
ingress, hosted runtime binding, catalog/read-model access, and thread/outbox
provider adapters are separate protocol lanes, not reasons to broaden the
execution-adapter protocol into a second runtime.
Command-surface ownership:
| Surface | Canonical owner | TypeScript role |
|---|---|---|
runx skill local execution |
runx-runtime::execution via runx-cli |
npm launcher/client wrapper |
runx harness <fixture.yaml> |
Rust harness replay | tests and wrapper views |
| receipts and history | Rust receipt store and journal | display/client views |
| policy, authority, payment, x402 | Rust core/runtime policy | published type mirrors and product UX |
| governed data operations | typed native operations plus external provider adapters | generated types, helper SDKs, provider glue |
| external execution-adapter protocol | runx-runtime supervisor |
generated types, helper SDKs, host/client wrappers |
| non-execution extension protocols | lane-specific Rust/cloud owners | generated types, helper SDKs, provider glue |
skill authoring and runx new |
runx-runtime authoring service plus skill-lab |
npm launcher only |
| marketplace and docs projection | Rust-owned catalog/contracts | generated docs and client views |
Stateful product work should use the governed data-plane shape in docs/governed-data-plane.md: domain skills own meaning, while provider adapters execute bounded reads, append-only event writes, and projection reads.
Graphs call exact native operations: data.append_event, data.read_events,
data.read_projection, and data.list_stream_heads. Runx resolves each
operation's data_source_ref through RUNX_DATA_SOURCES or
.runx/data-sources.json. Unbound local://... refs use native durable SQLite;
a binding may route the same operation to a conforming external provider such
as data.redis. Binding metadata is runtime-owned and is not part of the
native operation's public input schema.
Legacy native SQLite stores migrate only through the offline runtime service:
runx data migrate \
--database .runx/data/events.sqlite \
--source local://events \
--jsonThe command requires exclusive access, accepts only workspace-relative paths,
creates a SQLite-consistent backup before changing a recognized legacy schema,
rebuilds stream heads and digests, and independently verifies counts and
readback. A current store returns an idempotent current proof without another
backup. An unknown or partial schema is left byte-identical and fails with
recovery guidance.
Large local inputs use artifact.admit and artifact.read. Admission snapshots
one contained regular file, binds its media type, byte count, and whole-file
digest to an opaque invocation-scoped reference, and never exposes the host
path. The current total admission ceiling is 512 MiB. Reads return exact
offsets, range and whole-file digests, next_offset, and eof in pages of at
most 4 MiB using base64, character-safe UTF-8, or JSON-array record framing;
the default page is 1 MiB. The 4 MiB limit is a page ceiling, not a total-file
ceiling. fs.read and fs.read_bundle share the same containment and hashing
owner for bounded text; they are not alternate large-file transports.
cli-tool, MCP, and external-adapter process sources are trusted host code.
Their exact non-secret configuration is declared through
environment.required and environment.optional; credentials use the
separate credential contract. Runx controls exact argv, cwd, delivered
environment, stdin, timeouts, bounded output, process groups or Job Objects,
kill-tree behavior, and cleanup.
Receipts record trusted_host_process. That is an honest observation, not a
filesystem, network, or syscall-confinement claim. Capability and provider
scopes still govern the native or hosted operations Runx performs on the
skill's behalf; a local subprocess cannot turn those strings into OS
permissions.
JavaScript modules use a different boundary. Their worker receives no ambient OS environment, credentials, workspace path, network API, process API, clock, or randomness; only the validated in-memory module closure, JSON input, exact declared non-secret environment, and fixed limits cross the worker protocol.
Runx is the generic execution engine. Product workflows stay outside the runx CLI and ship as local skills, runners, and tools in the consuming repo.
The intended extension model is:
runxowns generic runtime, thread, outbox, receipt, and handoff machinery- service repos own their product workflows as local capability packs
- operators execute those workflows through normal skill invocation
- CLI, API, and GitHub-comment triggers all normalize into the same capability execution envelope, while the thread stays the review/control object
Sourcey is the reference shape for this model: from inside the Sourcey repo,
runx skill ./skills/outreach status --issue ... resolves the local
skills/outreach capability pack. outreach is not a privileged engine
command, and there is no privileged runx docs ... path inside the engine.
issue-to-pr follows the same boundary. runx owns the generic source-thread to
scafld to PR machinery; service repos own Slack, Sentry, owner assignment, and
publish policy. See docs/issue-to-pr.md.
runx new <name> --objective <outcome> is a thin client of the canonical Skill
Lab build lane. It inspects the target and catalog, requests a closed
architecture decision and change draft, binds both to the inspected package
digest in native code, stages and harnesses the exact candidate, then applies
the same bytes transactionally. The command owns no templates and never adds a
placeholder JavaScript module:
runx new docs-demo --objective "Create a bounded documentation decision skill"Without --managed-agent, the command stops at needs_agent, prints an answers
template and exact runx resume command, and leaves the target untouched. Add
--managed-agent only when this run should use the configured in-process model
loop. To cold-start without installing Runx first, invoke the same command
through npx @runxhq/cli.
Community skills should be authored and published as standalone packages
through this lane. The main runx repo is the first-party lane for official
skills and runtime code, not the community package catalog.
Prefer declarative graphs composed from native tools and existing skills. When
irreducible deterministic domain computation needs JavaScript, declare
type: javascript; the module receives resolved inputs and returns JSON while
Runx owns the process protocol. A frozen second argument carries exact
manifest-declared non-secret environment values when needed. Use cli-tool
only for a real executable or protocol boundary. See
Skill Author Runtime Contract.
Registry search and install now normalize public trust into three tiers:
first_party, verified, and community. Richer provenance and attestation
metadata still travels with the registry row, but the user-facing install/search
surface stays readable.
runx registry package <SKILL.md|skill-dir> --json projects the exact
parser-owned publish artifact without writing a registry row. Hosted and
third-party publishers should consume that output instead of implementing
their own package-file discovery.
Use skill-catalog.md for the maintained category list, catalog search flow, and duplicate-check standard before proposing a new first-party skill.
Executable skills split authored skill content from execution profiles. X.yaml
is the runx execution profile file; the short name is public compatibility for
existing skill packages, but docs and code should describe it as the execution
profile:
skills/sourcey/
SKILL.md
X.yaml
Direct execution accepts the package directory or SKILL.md inside it. Flat
foo.md skill files are no longer a supported execution surface.
In a workspace that owns a skills/ catalog, a root SKILL.md is the
workspace operator manual exported to agents; it is not an executable package
boundary around the repository. Executable package discovery starts at
skills/*/SKILL.md. A standalone workspace root remains a package, and a root
X.yaml explicitly opts a catalog workspace root into package ownership.
Execution profiles use a strict YAML subset: no anchors, aliases, merge keys, custom tags, multi-document markers, duplicate mapping keys, or unknown profile fields. Keep capability and receipt mappings explicit in the runner that uses them.
Every graph runner declares its intentional public result producers:
graph:
name: publish-and-readback
result_from: [readback]
steps:
- id: approve
run:
type: approval
- id: publish
tool: provider.mutate
- id: readback
tool: provider.readresult_from is not a list of graph leaves. It returns each selected successful
step's complete declared contract, including packet envelopes. Approvals and
intermediate evidence remain in the separate operator context and signed
receipts. Multiple names are for mutually exclusive result branches or
deliberately combined, non-overlapping contracts; two successful producers may
not emit the same key. Preparation resolves every result producer through its
exact runner, tool manifest, or nested skill and rejects a missing semantic
output contract before any step executes. Declare run.outputs,
artifacts.wrap_as, or artifacts.named_emits; transport output is never an
implicit graph result.
Public catalog packages must keep examples in standalone fixtures, not inline
manifest harness blocks. The package should contain only the files the skill
uses at execution time: SKILL.md, X.yaml, deterministic runner files,
schemas, fixtures, and narrowly scoped context/ or references/. Do not add
README/changelog/setup docs, generated state, logs, screenshots, private
provider config, or broad project plans inside a public skill. The public docs
for the package belong in SKILL.md; external guides belong under docs/.
See ../docs/skill-profile-model.md for resolution rules, publication modes, trust tiers, MCP export, and composite skill behavior.
Use work-plan for bounded change planning, skill-lab for skill-package
design and improvement, and the named downstream execution lane for mutation.
Reusable Runx mechanics and security boundaries belong in the native Rust tool
catalog. Skills should compose those native tools instead of shipping request,
filesystem, Git, hashing, packet, approval, credential, or receipt wrappers.
Use runx tool inspect <name> --json to inspect the contract that both graphs
and managed agents execute.
The repository-level tool package shape remains for a genuinely separate executable or protocol boundary that should be callable as a tool:
tools/<namespace>/<tool>/
src/index.mjs
fixtures/*.yaml
manifest.json
run.mjs
manifest.json is the execution contract and sole owner of the tool name,
source, inputs, defaults, artifact projection, scopes, and governance metadata.
Process code contains only the domain behavior the native catalog cannot
express.
defineTool() from @runxhq/extension-sdk may transport the already
materialized input object and structured failures over the local process
protocol; it does not declare or regenerate the manifest.
runx tool build --all --json
runx dev --lane deterministic --json
runx dev --lane repo-integration --jsonWhen a run.mjs entrypoint is needed, it is a thin process shim and owns no
contract metadata. runx tool build is read-only: it validates the source
manifest and reports hashes derived from the manifest and its declared source
files without rewriting either. Do not create one of these packages merely to
wrap a capability already owned by the native catalog. The declared entrypoint
must run directly on the supported Node runtime; do not probe for build output
or import uncompiled TypeScript.
The official catalog is explicit about why each package is public:
- canonical governed skills:
charge,dispute-respond,skill-lab,review-skill,least-privilege,overlay,policy-author,audit-receipt,refund,ops-desk,send-as,spend,weather-forecast - branded provider skills:
nitrosend,nws-weather-forecast,stripe-pay,x402-pay - context skills:
brand-voice,taste-profile
Other bundled packages stay in the same SKILL.md + X.yaml shape, but are
internal by default. Internal packages must declare why they remain bundled:
graph-stage, runtime-path, harness-fixture, or context. Owned graph
stages live below their public skill at skills/<skill>/graph/<stage>/X.yaml,
not as root catalog packages.
For first-party skill proposal work, the core builder bar is explicit: proposal packets should name the real pain being solved, explain fit against the current runx catalog, surface maintainer decisions cleanly, and avoid builder residue or placeholder targets.
See docs/operator-console.md for the manager-dashboard model that lets agents
operate projects, workspaces, products, or accounts through the same governed
lanes as the UI.
Each ships as a portable SKILL.md plus a colocated execution profile at
skills/<skill>/X.yaml when it exposes deterministic runners or inline harness
coverage. Upstream skills that runx does not own keep their execution profiles
under bindings/<owner>/<skill>/X.yaml with adjacent binding.json
governance metadata. Bare skill names resolve only to local workspace skills or
locked first-party official shorthand. Third-party registry execution uses the
explicit owner/name@version form, optionally with --registry and
--digest, and only trusted signed registry packages are materialized into the
runnable cache. Official skills are registry-backed and cached locally on first
acquisition. The npm CLI package no longer needs to ship the official runtime
skill bodies for normal execution.
Agent graphs can also demand-load skills as context instead of executing them.
Put reusable judgement, operating procedure, or capability skills in the local
registry, then reference them from an agent-task step with context_skills:
context_skills:
- ../taste-profile
- registry:runx/taste-profile@1.0.0The runtime injects each referenced SKILL.md as a generic
runx.skill.context artifact in the agent invocation current_context. Local
path refs resolve relative to the graph; registry refs require
RUNX_REGISTRY_DIR and are read from the local registry, not fetched remotely at
execution time. Explicit local/file registry sources are treated as user-owned
local material: they are digest-checked, but they do not require hosted registry
signatures. Context skills are bounded, digest-labeled, and presented to managed
agents as untrusted advisory data.
Graph steps can execute local-registry skills too:
steps:
- id: build_docs
skill: registry:runx/sourcey
runner: sourceyThis uses the same explicit local-registry rule: set RUNX_REGISTRY_DIR, sync or
publish the skill into that registry first, and treat .runx/registry-step-skills
as generated runtime cache rather than source.
Any runnable skill package can also be exposed locally as an MCP tool with:
runx mcp serve ./skills/sourceyThat MCP surface is a thin facade over the normal runx kernel path, so receipts, policy, approvals, and resolution requests still behave the same way.
Local receipts are append-only JSON files under .runx/receipts unless RUNX_RECEIPT_DIR is set. runx history verifies receipt signatures and surfaces verified, unverified, or invalid status. Once a skill package and runner resolve, a blocked preparation also seals a blocked refusal receipt; the JSON failure returns its receipt_id and prepared-context digest so rejected input or context admission remains visible in history without echoing the rejected value.
Graph receipt lineage is an immutable one-way DAG. The parent commits each
child receipt ID and exact signed-body digest; a reusable child is not re-signed
with one lineage.parent. This keeps receipt identity content-addressed and
allows the same child proof to participate in more than one graph without a
store collision. Runtime tree resolution collapses only identical repeated
child receipts into one DAG node; two different signed bodies under the same
receipt ID remain ambiguous and fail verification.
Publish a local receipt to the hosted notary with:
runx publish ./.runx/receipts/<receipt-id>.jsonrunx publish posts the full sealed receipt to POST /v1/receipts/notarize
with publish: true, then prints the public /r link and content hash returned
by the notary. Configure the hosted API with RUNX_PUBLIC_API_BASE_URL (default
https://api.runx.ai) and authenticate with RUNX_PUBLIC_API_TOKEN or --token
(or run runx login). Runx requires HTTPS for non-loopback API origins so the
bearer token cannot be sent to a public plaintext endpoint.
For local hosted dogfood only, point at a loopback API and opt into the private network escape explicitly:
runx publish ./.runx/receipts/<receipt-id>.json \
--api-base-url http://127.0.0.1:47882 \
--token dev-token \
--allow-local-apiProjects can opt into stricter local cli-tool admission with
.runx/config.json:
{
"policy": {
"strict_cli_tool_inline_code": true
}
}When enabled, local execution rejects known inline interpreter and shell eval
forms such as node -e, python -c, and bash -lc. Move the program into a
checked-in script file and invoke that file instead.
Trainable export is currently a TypeScript-maintained projection command. It can project verified receipt lineage into newline-delimited training rows without mutating the original receipts, but it is not yet part of the native Rust CLI surface:
runx export-receipts --trainable
runx export-receipts --trainable --receipt-dir ./.runx/receipts --status complete --source cli-toolRows are emitted as JSONL and follow the public training contract published at:
https://runx.ai/spec/training/trainable-receipt-row.schema.json
The export keeps receipt identity, verified outcome resolution, ledger artifacts, and runner provenance together so downstream training and eval systems can consume governed lineage instead of raw prompt logs.
Run a whole skill package to execute its inline X.yaml cases and every
conventional fixtures/*.yaml case through the native runtime:
runx harness ./skills/business-ops --jsonPass a fixture YAML path instead when intentionally replaying one standalone case:
runx harness ./fixtures/harness/echo-skill.yaml --jsonFixtures can assert the terminal status, receipt identity and lineage, exact or subset output, ordered graph steps, and exact or subset output for named graph steps. Prefer semantic subsets over complete snapshots:
expect:
status: sealed
receipt:
schema: runx.receipt.v1
child_receipt_count: 2
steps:
- classify
- act
step_outputs:
act:
subset:
action_packet:
data:
status: awaiting_approvalA receipt-dependent fixture may seed a bounded set of existing receipts from its own package:
setup:
receipts:
- fixtures/receipt-store/sha256-example.jsonEach path must be a normalized package-relative .json path. Runx parses and
verifies every seeded receipt under the fixture's configured signature policy
before placing it in that case's isolated store. Seed data is evidence for the
case, not proof of a provider action; the fixture must still assert only what
the verified receipts and runner output establish.
Supplied caller.answers are semantic oracles, not inert model stubs. Native
replay fails unless every supplied answer is observable in the root or step
output. For stateful work, use one graph fixture to prove the transition and
durable readback; do not depend on fixture filename order.
Package replay uses a disposable project-owned workspace below .runx/harness
and a separate receipt store for every case, then cleans that scratch state.
Cases therefore cannot satisfy each other through filename order or ambient
receipt history. Receipts produced by each case are verified and copied to the
durable .runx/receipts store, or to the directory selected by
--receipt-dir. An explicit RUNX_CWD identifies the owning project but does
not disable harness isolation.
For the core first-party skill lane, run:
pnpm dogfood:core-skillsThis remains a TypeScript wrapper lane. The native Rust proof for local orchestration is the Rust CLI/runtime test and fixture suite; wrapper dogfood is useful only after the same behavior is proven without Node, pnpm, or tsx.
For the default structural verification lane during refactors, run:
pnpm verify:fastThat lane keeps the cheap workspace checks together: OSS typecheck plus the fast package test surface with the current structural budget and boundary coverage.
pnpm build
pnpm test tests/cli-package.test.ts
cd packages/cli
npm pack --dry-run --jsonThe package must include dist/index.js and dist/index.d.ts, and dist/index.js must be executable.
oss/(this repository) must not import fromcloud/(the private companion workspace, not part of this checkout).- State-machine and policy packages remain pure.
- Rust owns trusted local runtime/execution, including exact process supervision, receipts, policy, authority, payment, harness, built-in adapters, and external execution-adapter supervision.
- TypeScript runtime-local and adapters packages must not be fallback executors for trusted local behavior.
- External execution adapters own their side effects behind language-neutral protocols and manifests; non-execution extension lanes have their own protocol contracts.
- External extension authors must not need Rust, a
runx-coreorrunx-runtimedependency, or a core repository fork. - CLI, SDK, IDE plugin, host adapter, and MCP entrypoints delegate to runner contracts or external protocols instead of duplicating the engine.