HardKAS / local

Execution-safe development for Kaspa.

HardKAS is a local-first developer environment for Kaspa L1, including the SilverScript and covenant workflows of the Toccata upgrade.

HardKAS has separate execution worlds.
Synthetic simulation and Kaspa simnet are not the same environment.

It gives developers a CLI, a managed localnet (a real rusty-kaspa node in Docker), verifiable artifacts for every transaction step, RPC diagnostics and transaction planning on the upstream Kaspa SDK Generator. It does not pretend to be a production wallet, a consensus client or a trustless bridge.

0.12.0-rc.26 Kaspa Native Toccata-aware Local-first Artifact-first Deterministic tooling
local first run simnet
first run
hardkas localnet start --toccata
hardkas accounts real generate --name miner --unsafe-plaintext --yes
hardkas accounts real generate --name ana --unsafe-plaintext --yes
hardkas localnet fund miner --keep-miner
hardkas tx plan --from miner --to ana --amount 10 --network simnet --out plan.json
hardkas tx sign plan.json --account miner --out signed.json
hardkas tx send signed.json --network simnet --yes
hardkas verify signed.json
localnet accounts tx lifecycle artifacts
Alpha boundary (0.12.0-rc.26). HardKAS is developer infrastructure, not production custody software. It confines artifact IDs and store paths to the workspace, refuses mainnet signing and broadcast, and verifies artifact lineage strictly.

The Problem

The old way

Developing on blockchain traditionally means throwing transactions into the network and hoping they confirm as expected. If they fail, debugging relies on reading node logs.

request → mutation → hope

The HardKAS way

HardKAS turns a transaction into explicit steps. Each step writes a versioned, verifiable artifact linked to the one before it, so you can check afterwards what happened and why.

plan → sign → send → observe → verify

Execution Contract

The Execution Contract makes the intended execution boundary explicit, allowing HardKAS to reject incompatible execution contexts. It is a small object that declares the target explicitly:

type HardkasExecutionTarget (@hardkas/core)
type HardkasExecutionTarget = {
  mode: "simulator" | "localnet" | "rpc";
  domain: "kaspa-l1" | "evm-l2"; // evm-l2 is reserved: no L2 commands are registered
  network: string;               // e.g. "simnet", "testnet-10", "mainnet"
};

Execution Guard

Before supported execution operations proceed, HardKAS validates the execution target and account compatibility.

For example: if a synthetic simulator account is used against a real RPC target, the execution guard refuses it before anything is signed:

EXECUTION_MODE_MISMATCH
Execution mode mismatch. Expected: kaspa, Actual: synthetic
Account kind = synthetic · target mode = rpc
✕ DENIED

Safety checks on real-node planning

When a plan targets a real node (localnet or RPC), the transaction runner adds these checks:

  • Pending-spends protection: skips UTXOs that are already being spent in the connected node's mempool, and fails closed if it cannot check.
  • Maturity policy: enforces DAA score thresholds before a UTXO can be spent.
  • Input re-validation: after planning, re-checks that the selected inputs are still spendable and retries a bounded number of times (SELECTED_UTXO_INVALIDATED if they are not). The virtual-state fingerprints before and after are recorded as evidence.

Artifacts

Transactions are not just API calls: every step is an Artifact. TxPlan and SignedTx, then TxReceipt in the simulator, or TxSubmission and TxObservation on a real node.

Hashes

Canonical hashing gives artifacts stable semantic identity independent of non-semantic representation details.

Evidence DAG (Lineage)

Artifacts cryptographically link their parentArtifactId and rootArtifactId, forming an Evidence DAG.

Provenance

Artifacts preserve the execution and lineage metadata defined by their schema.

Replay

Why did this transaction behave differently?

Instead of guessing, use the HardKAS Replay engine. It reconstructs the recorded execution context and verifies the transition against the original artifacts and invariants. Replay works on simulator transactions only. For real-node sends, tx status and tx wait record what the node reports as observation artifacts.

TxReceiptsourceSignedId, daaScore, preStateHash
ReconstructreconstructStateAtDaa(receiptDaa - 1)
Replay Transition
Verify Invariantslineage OK, determinism OK, contamination OK
PASS

Execution Environments

HardKAS exposes three execution environments with increasing proximity to real network behavior.

SimulatorFast feedback
LocalnetReal-node local validation
RPCExternal network

increasing execution fidelity

Simulator (synthetic)

Fast feedback without a Kaspa node. Transactions are planned by the same upstream Kaspa SDK Generator used on a real node (with simnet parameters), and every result is labelled SYNTHETIC_SIMULATOR. It needs the kaspa-wasm toolchain that hardkas init installs.

  • What it validates: transaction structure, Generator-computed mass and fees, standard (v0) transaction planning, lightweight DAG behavior.
  • What it does NOT claim: Kaspa VM equivalence, native script execution, native signing, full consensus validation, exact mass parity.

Localnet (Real-node)

Localnet runs the workflow against a real rusty-kaspa node over RPC. Planning is done by the upstream Kaspa SDK Generator (kaspa-wasm), and each submission and observation is recorded as an artifact.

  • Start it: hardkas localnet start --toccata (profile toccata-v2) runs rusty-kaspad v2.1.0 in Docker.

Capability Honesty

HardKAS states what it claims and what it does not. Its release claims are generated from the code that enforces them (claims.generated.md) and use these values:

StatusMeaning
🟢 READYCertified for local development by the release checks.
🟢 REAL_NODE_EVIDENCEProven end to end against a real rusty-kaspa node (local simnet), with recorded evidence.
🟡 PARTIALWorks for some cases; the limits are stated next to it.
🟡 EXPERIMENTALAvailable, but the command or API may change.
🔴 BLOCKED_BY_POLICYDeliberately not enabled yet (testnet and mainnet readiness).
⚪ NOT_CLAIMEDExplicitly not supported or guaranteed by HardKAS.

SilverScript & covenants (Toccata)

What works today on the Toccata upgrade, and what does not.

Toccata is the Kaspa hard fork, active on mainnet since 30 June 2026, that added transaction v1, covenants and SilverScript. HardKAS drives the official tools (silverc v1.0.0, rusty-kaspa, kaspa-wasm) instead of imitating them. The statuses follow the generated release claims; the proofs run against a local simnet node.

FeatureStatusCommand
SilverScript compile with the official silverc v1.0.0, reproducible byte for byte🟢 REAL_NODE_EVIDENCEsilver compile · silver verify
P2SH contract: deploy and spend🟢 REAL_NODE_EVIDENCEsilver deploy · silver spend
Relative timelock spend🟢 REAL_NODE_EVIDENCEsilver spend --sequence
1:1 covenant: genesis and auth-bound transitions (transaction v1)🟢 REAL_NODE_EVIDENCEsilver covenant genesis · silver covenant transition
General covenant support⚪ NOT_CLAIMED—
Contract tests on the official SilverScript runner (script engine only, not transaction validity)🟡 EXPERIMENTALsilver test
Transaction v1🟡 PARTIAL: built only by the covenant commands; tx plan builds v0—
Compute budget🟡 PARTIAL: set by hand with an explicit fee; no estimator exists--compute-budget · --fee
Fee estimation🟡 PARTIAL: automatic for standard payments (Generator); explicit for v1tx plan
Lane metadata⚪ NOT_CLAIMED: schema field only, planning ignores it—
PSKT (partially signed transactions)🟡 EXPERIMENTAL: no operation available from the CLI by default—
Transaction tracing🟡 PARTIAL: traces are written; the tx trace command is disabled—
ZK corpus🟡 EXPERIMENTAL: inspect surface only; on-chain ZK verification is NOT_CLAIMED—
VM / consensus equivalence⚪ NOT_CLAIMED—

Architecture

HardKAS is organised in dependency levels: a lower level never depends on a higher one. This is a convention; no tooling enforces it yet. Only the main packages are shown (the repository has 35).

Level 0 (Foundations)

core, observability, config. Shared types, errors, the execution guard, workspace locks and configuration.

Level 1 (Transactions and nodes)

tx-builder, kaspa-rpc, artifacts, simulator, localnet, accounts. Planning on the Kaspa SDK Generator, the official RPC client, artifact schemas and hashing, the simulator, the Docker localnet and dev accounts.

Level 2 (Read model)

query-store, query. A SQLite index that can always be rebuilt from the artifacts, and the queries on top of it.

Level 3 (SDK)

sdk. The main programmatic API for Node.js, built on the levels below.

Level 4 (Tools)

cli, testing, dev-server, client.

Quickstart

A first run in the simulator, with no node and no Docker: create a project, then plan, sign and send a payment and replay it from its artifacts. You need Node.js 22.5 or newer; hardkas init downloads the pinned kaspa-wasm.

execution-safe workflow
# 0. Create the project and install the pinned kaspa-wasm
hardkas init

# 1. Optional: add simulated funds (init already gives each account 1000 KAS)
hardkas simulator fund alice --amount 100

# 2. Create a transaction plan
hardkas tx plan --from alice --to bob --amount 10 --network simulated --out tx-plan.json

# 3. Sign the transaction
hardkas tx sign tx-plan.json --account alice --out tx-signed.json

# 4. Execute the transaction against the simulator
hardkas tx send tx-signed.json --network simulated --yes

# 5. Replay it: use the Artifact ID that tx send printed (the receipt)
hardkas replay verify <receiptArtifactId>
real output (excerpt)
$ hardkas tx send tx-signed.json --network simulated --yes

  ✔ Transaction simulated successfully

  Artifact ID
    5a890cae794c69abfef6361bcc6a85865985bad2298c8a380844a00c260e141b

  Tx ID
    synthetic-c84e82a07128512316cf7e65489d2564fa6f3562a852c8be4ce7ee1b363ead8f

  Consensus Validated
    NO

$ hardkas replay verify 5a890cae794c69abfef6361bcc6a85865985bad2298c8a380844a00c260e141b

  ✔ Replay Verification: 5a890cae794c69abfef6361bcc6a85865985bad2298c8a380844a00c260e141b

  Artifacts Replayed
    3

  Lineage Integrity
    valid

  Deterministic Execution
    verified

  Network Contamination
    clean

  Result
    PASS

Examples & Builder Labs

Real commands with their real output, captured on 0.12.0-rc.26 in a fresh simulator project after the Quickstart.

The repository also has reference apps built with HardKAS (wallet backends, a checkout, a local indexer); they are outside the core product.

Inspect local environment
diagnostics
hardkas doctor
hardkas config networks --json
hardkas config show --json
real output: hardkas doctor, without Docker (excerpt)
HardKAS System Doctor

  ✅ Node.js version: v24.15.0 (>= 18 required)
  ✅ pnpm: v11.1.3
  ✅ .hardkas/ directory: Exists and is active
  ✅ .gitignore protection: Contains .hardkas/
  ⚠️ store.db accessibility: store.db not found
  ✅ Workspace locks: No active or stale locks found
  ✅ Events Ledger Stream: 2 events verified
  ⏭️ Telemetry Stream: Stream not found
  ✅ Keystore permissions: No keystore found (nothing to secure)
  ❌ Docker daemon: Not reachable
  ⚠️ .env file: No .env file found

  Summary: 7 passed, 1 failed, 2 warning, 1 skipped
Index and explain artifacts
query
hardkas query store rebuild --backend sqlite
hardkas query artifacts list --sort createdAt:desc --limit 20
hardkas query lineage chain <receiptArtifactId> --why
real output (excerpt)
$ hardkas query store rebuild --backend sqlite
  ✓ Index rebuilt successfully in 43ms.

  Artifacts: 8/8 indexed (0 corrupted)

$ hardkas query artifacts list --sort createdAt:desc --limit 20
  Artifacts: 8 found (showing 8)

  hardkas.replayReport.v1  simulated  simulator    3051cfa9cbb2...
  hardkas.snapshot.v1      simnet     simulator    00c42e9dcc4c...
  hardkas.txReceipt        simulated  simulator    5a890cae794c... from:kaspa:sim_alice
  hardkas.txTrace          simulated  simulator    62aebf52daaa...
  hardkas.signedTx         simulated  simulator    ef78e48aab33... from:kaspa:sim_alice
  hardkas.txPlan           simulated  simulator    c84e82a07128... from:kaspa:sim_alice
  hardkas.snapshot.v1      simnet     simulator    44ab9ac0c71f...
  hardkas.snapshot.v1      simnet     simulator    bcba6f174c6d...

$ hardkas query lineage chain 5a890cae794c69abfef6361bcc6a85865985bad2298c8a380844a00c260e141b --why
  ═══ Lineage Chain (ancestors) ═══

  Anchor: 5a890cae794c69abfef6361bcc6a85865985bad2298c8a380844a00c260e141b
  Complete: ✓ yes
  Nodes: 3

  ├─ hardkas.txPlan [c84e82a07128...] simulated/simulator
  ├─ hardkas.signedTx [ef78e48aab33...] simulated/simulator
  └─ hardkas.txReceipt [5a890cae794c...] simulated/simulator

  Q: Why transition hardkas.txPlan → hardkas.signedTx?
  A: Causal chain is consistent with HardKAS state transition rules.
    1. Transition "hardkas.txPlan" → "hardkas.signedTx" is allowed
    2. Execution context (network, mode) is consistent
Verify artifacts
verify
hardkas verify tx-plan.json
hardkas verify tx-signed.json
real output: hardkas verify tx-signed.json
  ═══ Artifact Verification: tx-signed.json ═══
  ✔ VERIFICATION SUCCESSFUL
  Type:    hardkas.signedTx
  Version: 1.0.0-alpha
  Hash:    ef78e48aab338541f01048a3269b79f4b1326892d95cb31c0ddc6cdfb4adbf41
  Scope:   FULL

Operational Audit (STRICT):
  ✔   ✓ Economic & Lineage invariants verified.

Replay Verification:

  ⚠️  WARNING:
       ⚠ REPLAY UNSUPPORTED (Consensus simulation skipped)

Security Boundaries

Policy Gates

HardKAS refuses to sign and to broadcast mainnet transactions in this release, and the release claims mark testnet and mainnet readiness as BLOCKED_BY_POLICY.

Infrastructure, not Custody

HardKAS is developer infrastructure, not a custody or consensus-security layer.

Main rule. If a feature is not in the generated release claims (claims.generated.md), agents and docs should not imply that it exists.

Advanced / Reference

DAG simulation

The simulator keeps a small local DAG built with an approximate GHOSTDAG model (K = 18 by default). It is research/dev tooling to see how the simulated sink moves; it is not rusty-kaspa consensus and proves nothing about the real network.

hardkas dag statusShow the simulator DAG: sink, block count, selected path, accepted and displaced transactions.
hardkas dag simulate-reorg --depth 1Add one synthetic side block --depth blocks back on the selected path and move the simulated sink to it.

The query dag views (conflicts, sink-path, displaced, history) are not listed: they currently read a state file that nothing writes, so they return nothing. They come back once that is fixed.

Query store

The query store is a SQLite index over the artifacts and their lineage. It is disposable: rebuild it from the artifacts at any time. The default filesystem backend reads the files directly and indexes nothing, so build the SQLite store first.

hardkas query store rebuild --backend sqliteBuild the SQLite index from all the artifacts in the workspace.
hardkas query store sync --jsonAdd new artifacts to an existing SQLite index.
hardkas query artifacts list --sort createdAt:desc --limit 20List artifacts with deterministic filters and sorting.
hardkas query lineage chain <artifactId> --whyWalk an artifact's lineage back to its plan (or forward with --direction descendants); --why explains each link.

Not listed because of known issues: query events reads the event ledger from the wrong path and finds nothing; query store doctor fails once replay verify has run; query tx and query artifacts inspect report incomplete or contradictory results. They come back once fixed.

Operator commands

Operator commands exist so developers do not repair runtime state by hand. The goal is to fail loudly and recover explicitly.

hardkas doctor

Workspace diagnostic: Node and pnpm, the .hardkas/ folder and its .gitignore, the query store, locks, the event and telemetry streams, keystore permissions and Docker. Known issues: it exits 0 even when a check fails, and its lock check looks in the wrong folder (use hardkas lock doctor).

hardkas repair

Detects an unterminated JSONL tail and a corrupt query store. Without --force it only reports; with it, it truncates the tail and removes the store. Known issue: it also writes .hardkas/version.json, which then makes hardkas rebuild --from-artifacts fail. For locks, use hardkas lock doctor and hardkas lock clear <name> --if-dead.

hardkas inspect

Report the size of the event and telemetry streams and list the archived telemetry segments.

hardkas rebuild --from-artifacts

Wipe and rebuild the SQLite query store from the canonical artifacts. The flag is required; the localnet state is not rebuilt.

hardkas rotate

Archive the telemetry stream once it reaches 10 MiB (--force archives it now). The event ledger is never rotated: it is append-only by contract.

hardkas verify

Verify artifact integrity (hashes, schema) and lineage continuity across the workspace. Cross-subsystem checks live in hardkas verify-semantics (alpha).

No silent recovery (goal). Every automatic repair should emit an anomaly or a visible operator message. Quiet corruption handling is treated as a runtime bug.

Event ledger and telemetry

HardKAS separates two operational streams with different retention semantics:

Event ledger (events.jsonl)

Append-only operational evidence. Never rotated. Each event carries eventId, domain and kind, and optionally a causationId. Protected by AppendCoordinator with exclusive locks and fsync.

Telemetry (telemetry.jsonl)

Rotatable observability stream. 8 anomaly types: LOCK_CONTENTION, STALE_LOCK_RECOVERY, FS_RETRY, NORMALIZATION_COLLISION, REPLAY_RECONCILIATION, EXTERNAL_MUTATION, PATH_TRAVERSAL_ATTEMPT, ORPHAN_PROJECTION_RECOVERY. Scoped via AsyncLocalStorage.

AppendCoordinator. JSONL persistence uses exclusive file locks (openSync("wx")), spin-wait acquisition, automatic tail repair for corrupted JSON, and fsync after every write.

Chaos engine EXPERIMENTAL

hardkas chaos runs destructive campaigns against an isolated workspace to stress-test the runtime. Each run's seed is derived from the campaign seed (seed + 13 × run number) and picks the actor, so a campaign always performs the same actions. The runs share one workspace, so each run sees the state left by the ones before it.

LockHell

Writes a stale or zero-byte workspace lock, then runs a rebuild.

RotBot

Appends a truncated JSON line or garbage to the event or telemetry stream, then runs doctor.

DriftHunter

Deletes the SQLite store (store.db), then runs doctor.

HumanChaos

Runs an unknown command and checks that no raw stack trace leaks.

chaos campaigns
hardkas chaos --runs 300 --seed 1337 --profile smoke
hardkas chaos --actor LockHell --runs 500 --seed 404
hardkas chaos replay --run-seed 42

Every run is checked for raw stack traces and unexpected exit codes. The smoke, targeted and full profiles currently use the same actor weights. chaos replay re-runs a single run seed in a fresh workspace and picks the actor from that seed, so runs from an --actor campaign are not reproduced exactly.

Exit code Meaning
0 No findings.
2 Findings: at least one run leaked a raw stack trace or exited with an unexpected code.
3 Unsafe configuration refused.
4 Internal chaos engine failure.
Isolation. Chaos runs in an isolated workspace by default and refuses unsafe current-directory destruction without explicit opt-in.

Kaspa L1 vs Igra L2

System Role HardKAS treatment
Kaspa L1 Proof-of-work blockDAG, sequencing, data availability, state anchoring and finality via GHOSTDAG / future DAGKnight model. HardKAS talks to the node over RPC, runs a local node, manages dev accounts and simulates workflows. It does not validate consensus.
Igra L2 EVM-compatible L2 execution environment in the based-rollup architectural class. Not part of the current HardKAS CLI: the L2 transaction, RPC and bridge commands are not registered. Moving this code to Labs is planned.
Bridge phases Pre-ZK → MPC/committee-style assumptions → ZK exit phase. Modelled in the unregistered l2 package, where trustlessExit stays false until the ZK phase. No bridge workflow ships in the CLI.
No EVM on Kaspa L1. HardKAS documentation and examples must preserve this boundary. EVM execution happens on L2 (for example Igra); Kaspa L1 runs Kaspa script, including SilverScript contracts and covenants.

Bridge assumptions

The bridge-local commands are not registered in the current HardKAS CLI; moving this code to Labs is planned. The assumption model below is kept as architectural context, not as a CLI surface.

Field Expected meaning
trustlessExit false in pre-ZK phase.
l2BridgeCorrectness A replay-report field, currently always "unimplemented".
bridgePhase Used to distinguish current assumption model from future ZK exit.

RPC diagnostics

HardKAS includes Kaspa L1 RPC diagnostics so tools and agents can inspect runtime readiness instead of guessing.

hardkas rpc healthCheck that the local node at ws://127.0.0.1:18210 answers and is ready; it exits non-zero when it is not. It has no --url option.
--wait Keep checking until the node is ready
--timeout <ms> Only with --wait (default 60000)
--json Machine-readable output
hardkas rpc infoShow the node's network, server version, sync state, UTXO index and virtual DAA score.
--url <url> Node wRPC endpoint (default ws://127.0.0.1:18210; http(s):// and host:port are converted)
--json Machine-readable output
hardkas rpc doctor --endpoints <url> <url>Diagnose one or more endpoints: TCP reach, wRPC connection, server and DAG info. It always exits 0, even when an endpoint fails (known issue).
--endpoints <urls...> One or more URLs separated by spaces (commas are not split); a URL without a port is probed on 18210. Default: the default network's rpcUrl in the config
hardkas rpc dagShow the node's DAG info: network, virtual DAA score, sink and tips.
--url <url> Node wRPC endpoint (default ws://127.0.0.1:18210)
--json Machine-readable output
hardkas rpc mempool [txId]Look up one transaction in the node's mempool, or summarise the whole mempool.
[txId] Transaction ID (64 hex characters); omit it for the whole mempool
--url <url> Node wRPC endpoint (default ws://127.0.0.1:18210)
hardkas rpc utxos <address>List the UTXOs of an address with their amounts and DAA scores.
<address> Kaspa address for the node's network (account names are not resolved)
--url <url> Node wRPC endpoint (default ws://127.0.0.1:18210)

CLI reference

The most used commands, with what each argument accepts. Every card was checked against the code of 0.12.0-rc.26. Add --help to any command to list all its options. The complete reference, generated from the command tree, is docs/reference/cli.md.

Core and diagnostics
hardkas init [name]Create a project: package.json, vitest.config.ts, hardkas.config.ts, a sample test and .gitignore, plus 5 simulated accounts (alice…erin, 1000 KAS each). It also installs the pinned kaspa-wasm 2.1.0.
[name] Folder to create, relative or absolute (default: the current folder)
--install Run npm install afterwards (default: off)
--force Overwrite an existing hardkas.config.ts
--network <name> simulated (default) creates the simulator state; any other value skips it. The project's default target is always the simulator
--skip-toolchain Do not install kaspa-wasm (planning and signing need it)
--toolchain-from-file <asset> Install kaspa-wasm from a downloaded kaspa-wasm32-sdk-v2.1.0.zip; its SHA-256 must match the pin
--template · --accounts Accepted but ignored in this release
hardkas doctor [module]Check the machine and the workspace: Node, pnpm, the .hardkas/ folder, the query store, locks, the event and telemetry streams, keystore permissions and Docker.
[module] Omit it for the full check; signer checks the kaspa-wasm signing backend; node checks the Docker node and its RPC (ws://127.0.0.1:18210)
--consistency Also open and check the SQLite query store
--json Machine-readable output
--strict Meant to fail on any failed check; it currently still exits 0 (known issue)
hardkas config showShow the resolved configuration: file path, default network, networks and accounts.
--config <path> Config file to load (.ts, .mts, .js or .mjs); default: the nearest hardkas.config.* from the current folder up
--json Machine-readable output
hardkas config networksList the networks: the built-in simulated, simnet, devnet, testnet-10, testnet-11 and mainnet, merged with the ones in hardkas.config.
--json Machine-readable output
Development runtime
hardkas test [files...]Run the project's tests with Vitest and the HardKAS test helpers. Each run writes .hardkas/runs/<runId>/test-results.json.
[files...] Test files or globs (default: test/**/*.test.ts, tests/**/*.test.ts, scenarios/**/*.scenario.ts, scenarios/**/*.test.ts)
--scenario <name> Only tests whose full name matches this regular expression
--evidence Pack the results of scenario() tests as evidence
--keep-runs Keep the scenario run folders (deleted by default)
--watch Passed to Vitest, but the run currently ends after the first pass
--json Machine-readable output
--network · --mass-* Accepted but ignored in this release: tests use the config's default network
hardkas run <script>Run a .ts or .js script with tsx. On a simulated network it injects a global hardkas test harness; on a node network, a small RPC client. It does not inject the SDK.
<script> Path to a .ts, .mts, .js or .mjs file
--network <name> A network from the config (built-in: simulated, simnet, devnet, testnet-10, testnet-11, mainnet); default simnet; an unknown name falls back to simulated
--accounts <n> Harness accounts (default 3); only on a simulated network
--balance <sompi> Whole sompi per harness account (default 1000 KAS); only on a simulated network
--no-harness Inject nothing
hardkas consoleInteractive REPL with an in-memory simulator harness (h) and hash and format helpers. Nothing connects to a network, and the state is lost on exit.
--accounts <n> alice, bob, carol, dave, erin, then account5… (default 3)
--balance <sompi> Whole sompi per account, 1 KAS = 100 000 000 (default 1000 KAS)
--network <name> Only a label for the simulated state (default simnet)
hardkas dev doctor --profile igra --jsonCheck local readiness for an L2 profile (Igra by default): workspace, artifacts, query store, SDK import, dev server and the L2 JSON-RPC. It does not check the Kaspa node.
--profile <name> igra (built-in) or a key of l2.networks in hardkas.config
--rpc-url <url> EVM JSON-RPC URL (default: the profile's, http://127.0.0.1:8545 for igra)
--json Machine-readable output
hardkas local wizard --profile igraGuided Igra L2 (EVM) check: it pings the profile's JSON-RPC and looks for an EVM account and its balance. It is not a Kaspa L1 setup.
--profile <name> igra or a name under l2.networks in hardkas.config
--account <name> EVM account in hardkas.config (default dev_alice); if it is missing, it offers a key for you to add by hand
--non-interactive Report instead of prompting
Accounts
hardkas accounts listList every account HardKAS can see: simulated (alice…erin), dev and real accounts, and those in hardkas.config. Keys are never printed.
--config <path> Config file to read (default: the nearest hardkas.config.*)
--json Machine-readable output
hardkas accounts balance <identifier>Show an account's balance and UTXO count.
<identifier> Account name (from hardkas.config or the real-account store) or Kaspa address; simulator names (alice…) only in simulated mode
--network <name> simulated or local read the simulator; simnet, devnet, testnet-10 or mainnet ask a node on 127.0.0.1 (default simnet, even in a simulator project)
--url <url> Node wRPC endpoint (ws:// or wss://; http(s):// and host:port are converted)
--local Read the simulator state file (.hardkas/localnet.json)
--json Machine-readable output
hardkas accounts real initCreate an empty real-account index (.hardkas/accounts.real.json). Keys are encrypted per account when you generate them.
--force Replace an existing index (keystore files stay on disk)
hardkas accounts real generateGenerate dev accounts with kaspa-wasm. Each key is encrypted in .hardkas/keystore/<name>.json.
--name <name> Letters, digits, _ and -; it must be new (default account0, account1…)
--count <n> How many (default 1); with more than one, the names become <name>1…<name>N
--network <network> simnet (default), testnet-10 or another testnet-*, or mainnet; devnet currently fails
--password-env <env> Name of an environment variable holding the keystore password (at least 8 characters)
--password-stdin Read the password from stdin (default: interactive prompt)
--unsafe-plaintext Store the key unencrypted in .hardkas/accounts.real.json; needs --yes. Local tests only
hardkas accounts real importImport an existing key into the real-account store. Known issue: importing a name that already exists overwrites its keystore file before failing, so always use a new name.
--name <name> Letters, digits, _ and -; it must be new (default: default)
--address <address> kaspa:, kaspatest: or kaspasim: address; required unless --fixture. It is not checked against the key
--private-key-env <env> Name of an environment variable holding the private key
--private-key-stdin Read the key from stdin (--private-key <hex> still works but is deprecated)
--fixture <name> Import a built-in test key: default, alice, bob, carol, dave or erin (stored unencrypted)
hardkas accounts real session-open <name>Check that an account's encrypted keystore opens with its password (alias unlock). Nothing is recorded.
<name> Account with an encrypted keystore in .hardkas/keystore/
--password-env <env> Name of an environment variable holding the password (default: interactive prompt)
hardkas session create <name> --l1 <wallet> --l2 <account>Hidden and experimental: save a named pair of an L1 and an L2 identity in .hardkas/sessions.json.
--l1 <wallet> HardKAS account name or Kaspa address
--l2 <account> Account name, Kaspa address or 0x EVM address (an account name stores its Kaspa address, not an EVM one)
Kaspa L1 and node
hardkas localnet start --toccataStart (or adopt) the Docker rusty-kaspad node with the toccata-v2 simnet profile, and create dev accounts alice…erin in .hardkas/dev-accounts. Needs Docker and kaspa-wasm.
--toccata Shortcut for --profile toccata-v2, the only profile accepted (a plain localnet start fails)
--json Machine-readable output
hardkas localnet statusReport the toccata-v2 node (RPC on ws://127.0.0.1:18210 and its identity check) and its miner container. Works without Docker.
--json Machine-readable output
hardkas localnet fund <identifier> --amount 1000Mine to an account on the local node until its mature balance grows by the amount, then stop the miner.
<identifier> Account name (alice…erin, accounts real generate names, config accounts) or a kaspasim: address
--amount <kas> KAS to wait for, up to 8 decimals (default 1000); 0 waits for any increase
--timeout <ms> Limit for the maturity wait (default 300000, 5 minutes)
--keep-miner Leave the miner running; a missed target is reported as pending instead of failing
hardkas localnet fork --network testnet-10 --at-daa-score <score> --addresses <address>Copy the current UTXOs of some addresses from a node into a simulator state file.
--network <name> A network with an RPC URL: simnet, devnet, testnet-10, testnet-11, mainnet or one from the config
--addresses <addrs...> One or more Kaspa addresses, separated by spaces
--at-daa-score <score> Required, but only stored as a label: the UTXOs are always the node's current ones
--output <path> State file to write (default .hardkas/localnet.json, which is replaced)
hardkas kaspa doctor --rpc-url ws://127.0.0.1:18210Check one node: reachability, sync state, UTXO index, DAG info and mempool size.
--rpc-url <url> The node's JSON wRPC endpoint; the HardKAS localnet is ws://127.0.0.1:18210
--json Machine-readable output; exit 1 when a check fails
Transactions
hardkas tx plan --from <account> --to <address> --amount <kas>Plan a payment with the Kaspa SDK Generator and write a TxPlan artifact (a copy also goes to .hardkas/artifacts).
--from <accountOrAddress> Sender: account name (alice…erin, real or config accounts) or Kaspa address; it must suit the target (default alice)
--to <address> Recipient: Kaspa address or account name (default bob)
--amount <kas> KAS, up to 8 decimals, e.g. 10 or 0.5 (default 1)
--network <name> simulated, simnet, devnet, testnet-10, testnet-12 or mainnet (default: the config's default target, the simulator in a new project); testnet-11 is refused
--fee-rate <sompiPerMass> Whole sompi per gram of mass (default 1 in the simulator, 100 on real networks: the network minimum, not a live estimate)
--change <accountOrAddress> Where the change goes (default: the sender)
--url <url> Node wRPC endpoint (default ws://127.0.0.1:18210 for simnet and devnet)
--out <path> Write the plan artifact to this file
hardkas tx sign <planPath>Sign a plan. Simulator plans get a synthetic authorization; real-node plans are signed with kaspa-wasm using the account's key.
<planPath> Path to a TxPlan JSON (not an artifact ID)
--account <name> The plan's sender account (default: the plan's from); real plans need an account with a key
--out <path> Write the signed artifact to this file
--fixture Sign with the built-in test key (any network except mainnet)
--threshold <n> Above 1, starts a synthetic multisig for tests; no Kaspa multisig script is produced
--allow-mainnet-signing No effect in this release: mainnet signing is always refused
hardkas tx send <signedPath>Send a signed artifact: simulated in the simulator, broadcast to its recorded network otherwise. Mainnet broadcast is always blocked.
<signedPath> Path to a SignedTx JSON (not an artifact ID)
--yes Confirm the broadcast; required except for simulated and simnet artifacts
--url <url> Node wRPC endpoint (default: the network's rpcUrl in the config)
--from/--to/--amount Shortcut: plan, sign and send in one run instead of passing a file
--track <label> After an accepted broadcast, record it as a deployment in .hardkas/deployments/
--json Machine-readable output; outcome is submitted, rejected or not_executed
hardkas tx status <txIdOrPath>Show a transaction's derived state (SUBMITTED, MEMPOOL_ACCEPTED, ACCEPTED, CONFIRMED, FINALIZED, REORGED…) from the workspace evidence plus one new observation of the node. With a plan or signed file, it shows its signature coverage instead.
<txIdOrPath> Transaction ID, or path to a plan or signed artifact
--no-observe Use only the evidence already in the workspace
-n, --network <network> Network whose node observes (default: the one recorded at submission)
--json Machine-readable output
hardkas tx wait <txId>Wait until the transaction is ACCEPTED or CONFIRMED (blue-score depth at least the HardKAS policy), then until the node's UTXO view reflects it.
--until <target> accepted or confirmed (default)
--timeout <seconds> Default 60
--interval <seconds> Seconds between observations (default 2)
-n, --network <network> Network whose node observes (default: the one recorded at submission)
hardkas simulator fund <identifier>Add a UTXO to a simulator account. It works while the project's default network is the simulator, as in a new project.
<identifier> Simulator account (alice…erin, or kaspa:sim_<name>); real addresses are refused
--amount <kas> KAS, up to 8 decimals (default 1000)
SilverScript and covenants
hardkas silver doctorCheck the pinned kaspa-wasm and silverc v1.0.0 toolchains and the canonical localnet node, and list which capabilities are ready.
--json Machine-readable output
hardkas silver compile <source>Compile with the managed silverc v1.0.0 and write a compile record: source hash, compiler digest and the P2SH address of each contract.
<source> Path to a SilverScript source file
--args <file> Constructor arguments: a JSON list of {kind, value}; kinds int, bool, byte, bytes, text, array, object
--out <file> Where to write the record (default: .hardkas/artifacts/silver/)
hardkas silver verify <record>Recompile a compile record with the managed silverc and check that it matches byte for byte.
<record> Path to a compile record
--args <file> The constructor arguments it was compiled with
hardkas silver deploy <record> --from <account> --amount <kas>Fund the contract's P2SH output on the canonical simnet localnet.
<record> Path to a compile record
--from <account> Real dev account with a local key that pays (see accounts real generate)
--amount <kas> KAS locked in the contract, up to 8 decimals (e.g. 10 or 0.5)
--contract <name> Which contract, when the record has several
--network <network> Only simnet (default); mainnet is refused
--wait Wait for confirmation (--timeout, default 120 s)
hardkas silver spend <deploy-record> --entry <name> --to <address>Spend a deployed contract output through one of its entries.
<deploy-record> The record written by silver deploy
--entry <name> Contract entry to call
--to <address> Kaspa address that receives the whole value, minus the fee
--args <file> Entry arguments: a JSON list of {kind, value}; a signature slot is {"kind":"signature","account":"<name>"}
--sequence <n> Input sequence, for relative timelocks
--wait Wait for confirmation
hardkas silver covenant genesis <record> --from <account> --amount <kas> --compute-budget <n>Create a 1:1 covenant: a new output bound to the covenant id that the Kaspa SDK derives (transaction v1).
<record> Compile record of the covenant contract
--from <account> Funding account with a local key
--amount <kas> KAS locked in the covenant
--compute-budget <n> Compute budget of the funding input; set it explicitly, no estimator exists
--fee <sompi> Explicit fee in sompi; required when the compute budget is above 0
--wait Wait for confirmation and the node's covenant id
hardkas silver covenant transition <covenant-record> --policy <name> --constructor-args <file> --state-map <json> --next-state <file> --compute-budget <n>Advance a 1:1 auth-bound covenant: silverc compiles the successor state and the covenant id stays the same.
<covenant-record> Record written by the genesis or by the previous transition
--policy <name> Covenant declaration (policy function) to call
--constructor-args <file> Constructor arguments of the current state, checked against the record
--state-map <json> State field to constructor parameter index, e.g. {"value":0}
--next-state <file> Successor state: a JSON object with a {kind, value} per field
--compute-budget <n> Compute budget of the covenant input; explicit
--fee <sompi> Explicit fee; required when the compute budget is above 0
--emit-args <file> Write the successor's constructor arguments here, for the next transition
hardkas silver test <record> --tests <file>Experimental: run a compiled contract's tests on the official SilverScript runner (script engine on scenario transactions, not transaction validity).
<record> Path to a compile record
--tests <file> Runner test file (.test.json); a signature argument may be {"signature":"<account>"}
--runner <path> SilverScript runner (cli-debugger) binary; default $HARDKAS_SILVER_RUNNER
Artifacts, query and replay
hardkas verify [path]Verify integrity, schema and lineage of every artifact under .hardkas/artifacts, or of the given file or folder. Exits 1 on any failure.
[path] File or folder inside the workspace (default .hardkas/artifacts); not an artifact ID
--json Machine-readable output
hardkas artifact verify <path>Verify one artifact file, or a folder with --recursive: hash, schema and semantics. Artifacts older than 30 days fail as stale.
<path> Path to an artifact .json (not an ID), or a folder with --recursive
--recursive Verify every .json below the folder
--strict Also require hash version 5, complete lineage and resolvable references
--json Machine-readable output
hardkas replay verify <receiptArtifactId>Replay a simulator transaction from its receipt and check lineage, determinism and contamination. Real-node receipts are not supported.
<artifact> The receipt's 64-hex artifact ID (tx send prints it as Artifact ID), or a path inside the workspace starting with ./
--workspace <path> Workspace folder (default: the current one)
--json Machine-readable output
hardkas query store rebuild --backend sqliteBuild the SQLite index (.hardkas/store.db) from all the artifacts.
--backend <type> sqlite builds the index; filesystem (the default) indexes nothing
hardkas query store sync --jsonAdd new artifacts to an existing SQLite index; without .hardkas/store.db it indexes nothing.
--strict Stop at the first corrupted artifact (SQLite only)
--json Machine-readable output
hardkas query artifacts listList artifacts, newest first, with exact-match filters.
--schema <schema> Without the hardkas. prefix: txPlan, signedTx, txReceipt, txTrace, snapshot.v1, replayReport.v1…
--network <network> Exact network ID, e.g. simulated, simnet, testnet-10
--mode <mode> simulator, localnet or rpc
--sort <field:dir> createdAt, schema, networkId, mode, contentHash, amountSompi or status, then :asc or :desc (default createdAt:desc)
--limit <n> Default 100
hardkas query lineage chain <artifactId> --whyWalk an artifact's lineage: back to its plan by default, or forward.
<artifactId> contentHash, artifact ID, plan/signed/tx ID, or a path to the artifact JSON
--direction <dir> ancestors (default) or descendants
--why Explain each link
hardkas deploy track <label> --network <name>Record a deployment in .hardkas/deployments/<network>/<label>.json. Purely local: nothing is checked on a node.
<label> Free text; it becomes the file name
--network <name> Free-text network label (required)
--tx-id <txId> Stored as given
--plan <artifactId> Stored as given, not resolved (same for --receipt)
--status <status> planned, sent (default), confirmed, failed or unknown
--notes <text> Free text
Check and rebuild a workspace
recovery
hardkas doctor
hardkas lock doctor
hardkas rebuild --from-artifacts
hardkas replay verify <receiptArtifactId> --json
real output (excerpt)
$ hardkas lock doctor
  ═══ Lock Doctor Analysis ═══
  ✓ No locks found. Workspace is clean.

$ hardkas rebuild --from-artifacts
  ℹ Rebuilding projections from canonical artifacts...
  ✔ Rebuild complete. Indexed 7 artifacts.

$ hardkas replay verify 5a890cae794c69abfef6361bcc6a85865985bad2298c8a380844a00c260e141b --json
{
  "schemaVersion": "hardkas.replayVerify.v1",
  "workspace": "5a890cae794c69abfef6361bcc6a85865985bad2298c8a380844a00c260e141b",
  "artifacts": 3,
  "lineage": "valid",
  "determinism": "verified",
  "contamination": "clean",
  "result": "passed",
  "targetTxId": "synthetic-c84e82a07128512316cf7e65489d2564fa6f3562a852c8be4ce7ee1b363ead8f",
  "deterministic": true
}

Not listed: capabilities (hidden; it prints a fixed list that contradicts the release claims), kaspa wallet create (it prints a private key and saves nothing; use accounts real generate), kaspa wallet send (it cannot reach a node with the default config; use tx plan, tx sign and tx send) and query artifacts inspect (it reports contradictory results).

Package map

The main packages (the repository has 35):

Package / area Purpose
@hardkas/cli The hardkas command line.
@hardkas/sdk The main programmatic API, for Node.js.
@hardkas/testing Test harness, fixtures, matchers and scenarios for project tests.
@hardkas/core Shared types, errors, the execution guard and workspace locks.
@hardkas/config Defines, loads and resolves hardkas.config.ts and its networks.
@hardkas/artifacts Canonical artifact schemas, hashing and verification.
@hardkas/tx-builder Transaction planning on the Kaspa SDK Generator (kaspa-wasm): mass, fees and pending-spend checks.
@hardkas/accounts Dev accounts: simulated accounts, the local keystore and kaspa-wasm signers.
@hardkas/kaspa-rpc RPC client for rusty-kaspa nodes, on the official kaspa-wasm RpcClient.
@hardkas/localnet Local chain state: funding, snapshots, forks, receipts and replay.
@hardkas/simulator Approximate GHOSTDAG model, mass profiling and scenarios for the simulator.
@hardkas/query-store SQLite index and query read model.
@hardkas/query Query engine over artifacts and lineage, with explanations.
@hardkas/dev-server Local Hono server, health endpoints and SSE invalidation.
@hardkas/client · @hardkas/react HTTP client for the local dev server, and React hooks and provider for local dashboards.
@hardkas/wallet-adapter Wallet adapter boundary and local wallet connection helpers.
@hardkas/sessions · @hardkas/l2 · @hardkas/bridge-local Experimental or unregistered surfaces (sessions, Igra L2, bridge). Moving the L2 and bridge code to Labs is planned.

Rules for AI agents

HardKAS is designed to be readable by AI coding agents without letting them invent unsupported behavior.

Rule Reason
Read the release claims first (claims.generated.md). Prevents agents from assuming features that are not implemented.
Run hardkas doctor --json before runtime work. Captures local environment readiness.
Prefer --json for automation. Keeps machine workflows stable.
Default to localnet/local profiles. Avoids accidental mainnet mutation.
Do not invent txids, balances, finality or trustlessness. Preserves protocol honesty.
Respect trust boundaries. HardKAS is local developer tooling, not production protocol validation.

FAQ

Does HardKAS execute EVM on Kaspa L1?

No. Kaspa L1 does not execute EVM smart contracts. EVM execution belongs to Igra/Kasplex L2 architecture. HardKAS preserves this distinction.

Is the bridge trustless today?

No. No bridge workflow ships in the CLI, and the bridge model keeps trustless exit false until a ZK phase exists and is explicitly implemented.

Is the DAG simulator consensus-equivalent?

No. It is research/dev tooling for local scenarios. It is not differential validation against rusty-kaspa and not a consensus proof.

Can agents use HardKAS safely?

As developer tooling, yes, if they follow the rules above: read the release claims and the doctor output first, use JSON outputs, and never assume unsupported capabilities.

Where is the full CLI reference?

In the repository: docs/reference/cli.md, generated from the command tree. This page shows the most used commands.

HardKAS Documentation · 0.12.0-rc.26 · CLI · SDK · Examples · Security · GitHub · MIT License
HardKAS is local developer infrastructure in active alpha. It is provided without warranty and is not production custody software.