@nexart/cli
v0.7.0
Published
NexArt CLI — Code Mode and AI execution certification
Downloads
460
Maintainers
Readme
@nexart/cli v0.7.0
Command-line interface for NexArt — run, replay, and verify deterministic generative art, plus AI execution certification commands.
Installation
# Global install (recommended)
npm install -g @nexart/cli
# After global install, use the `nexart` command directly:
nexart run sketch.js --seed 12345Quickstart: Run an Example
The SDK includes example sketches in the examples/ folder:
# 1. Set up authentication
export NEXART_RENDERER_ENDPOINT=https://nexart-canonical-renderer-production.up.railway.app
export NEXART_API_KEY=nx_live_your_key_here
# 2. Run the main example sketch (outputs to current directory)
npx @nexart/cli run ./examples/sketch.js --seed 12345 --include-code --out ./out.png
# Creates: ./out.png and ./out.snapshot.json
# 3. Verify the output is deterministic
npx @nexart/cli verify ./out.snapshot.json
# Output: [nexart] Result: PASSOutput Files
When you run with --out ./out.png, the CLI creates:
./out.png— The rendered PNG image./out.snapshot.json— Snapshot for replay/verify
Example Sketches
| File | Description |
|------|-------------|
| examples/sketch.js | Main example — VAR controls + random palette, protocol-safe |
| examples/sketch-minimal.js | Simple shapes, no randomness — identical output every run |
| examples/sketch-vars.js | Uses VAR + random() — demonstrates determinism with same seed |
Canonical Size
The canonical renderer enforces a fixed canvas size:
| Property | Value | |----------|-------| | Width | 1950 | | Height | 2400 |
Important: Do not pass custom --width or --height to the canonical renderer endpoint. The canonical size is enforced server-side for consistent, verifiable output.
# Correct: use default canonical size
nexart run sketch.js --seed 12345
# Avoid: custom sizes may be rejected by canonical renderer
# nexart run sketch.js --width 800 --height 600 # NOT recommendedQuick Start (npx)
Run without installing globally:
# Using npx (no install required)
npx @nexart/cli run sketch.js --seed 12345
npx @nexart/cli verify out.snapshot.json
npx @nexart/cli replay out.snapshot.json --out replay.pngOverview
The CLI has two command groups:
Code Mode commands — render generative art sketches, create verifiable snapshots, replay and verify them.
AI certification commands — create, certify, and verify tamper-evident Canonical Execution Records (CERs) for AI operations via the NexArt node API. Also includes local verification of project bundles (cer.project.bundle.v1) with nexart ai project-verify.
Authentication
Remote rendering requires an API key for metered access.
Setup
# Set environment variables
export NEXART_RENDERER_ENDPOINT=https://nexart-canonical-renderer-production.up.railway.app
export NEXART_API_KEY=nx_live_your_key_here
# Run with authentication
npx @nexart/cli run sketch.js --seed 12345 --include-code --out out.pngAPI Key Options
# Via environment variable (recommended)
export NEXART_API_KEY=nx_live_...
nexart run sketch.js --seed 12345
# Via CLI flag
nexart run sketch.js --seed 12345 --api-key nx_live_...Error Messages
If authentication fails:
[nexart] Error: Missing API key for remote rendering.
[nexart] Set NEXART_API_KEY environment variable or pass --api-key.
[nexart] Get your API key at: https://nexart.art/dashboard/apiCommands
run
Execute a sketch and create a snapshot:
# With remote renderer (default, requires API key for remote endpoints)
nexart run sketch.js --seed 12345 --out render.png
# With code embedded for standalone verify/replay
nexart run sketch.js --seed 12345 --include-code
# Local mode (placeholder PNG, no auth required)
nexart run sketch.js --renderer localOptions:
| Flag | Default | Description |
|------|---------|-------------|
| --out, -o | out.png | Output PNG path |
| --seed, -s | random | PRNG seed |
| --vars, -v | 0,0,0,0,0,0,0,0,0,0 | VAR values (comma-separated) |
| --width, -w | 1950 | Canvas width (use default for canonical) |
| --height | 2400 | Canvas height (use default for canonical) |
| --renderer | remote | remote or local |
| --endpoint | env/localhost:5000 | Remote renderer URL |
| --api-key | env | API key for authentication |
| --include-code | false | Embed code in snapshot |
| --runtime-hash | auto | Override runtime hash |
Outputs:
render.png— The rendered imagerender.snapshot.json— Snapshot for replay/verify
verify
Check that a snapshot produces the expected output:
nexart verify render.snapshot.json
# With external code file
nexart verify render.snapshot.json --code sketch.jsExit codes:
0— PASS (hashes match)1— FAIL (hashes differ or error)
replay
Re-execute from a snapshot:
nexart replay render.snapshot.json --out replay.png
# With external code file
nexart replay render.snapshot.json --code sketch.js --out replay.pngAI Certification Commands (nexart ai)
These commands interact with the NexArt node API to manage Canonical Execution Records (CERs) for AI operations. CERs are tamper-evident bundles that cryptographically certify an AI execution (input, output, model, parameters).
Environment Variables
| Variable | Description |
|----------|-------------|
| NEXART_NODE_ENDPOINT | NexArt node API URL (default: https://node.nexart.art) |
| NEXART_API_KEY | Shared API key for authenticated requests |
nexart ai create
Create a CER bundle from an AI execution record.
# From file
nexart ai create execution.json
# From stdin
cat execution.json | nexart ai create
# With explicit endpoint and API key
nexart ai create execution.json \
--endpoint https://node.nexart.art \
--api-key nx_live_...
# Save to file
nexart ai create execution.json --out cer.jsonInput format (JSON file or stdin):
{
"executionId": "exec-001",
"provider": "openai",
"model": "gpt-4o",
"input": "What is 2+2?",
"output": "4",
"parameters": { "temperature": 0 }
}Output: CER bundle JSON printed to stdout (or saved via --out).
Options:
| Flag | Default | Description |
|------|---------|-------------|
| --endpoint | env/https://node.nexart.art | NexArt node URL |
| --api-key | env | API key |
| --out | stdout | Save bundle to file |
| --signals-file | (none) | Path to a JSON array of context signals to attach |
Exit codes:
0— Success1— API error or missing input
nexart ai certify
Certify an AI execution and receive an attested CER bundle. The node API signs the bundle and attaches an attestation.
# From file
nexart ai certify execution.json
# From stdin
cat execution.json | nexart ai certify
# JSON output (machine-readable)
nexart ai certify execution.json --json
# Save output
nexart ai certify execution.json --out certified.jsonDefault output:
[nexart] CER certified successfully
bundleType : cer.ai.execution.v1
hash : sha256:a1b2c3...
attestation: presentJSON output (--json):
{
"ok": true,
"bundleType": "cer.ai.execution.v1",
"certificateHash": "sha256:a1b2c3...",
"hasAttestation": true,
"bundle": { ... }
}Options:
| Flag | Default | Description |
|------|---------|-------------|
| --endpoint | env/https://node.nexart.art | NexArt node URL |
| --api-key | env | API key |
| --out | stdout | Save bundle to file |
| --json | false | Machine-readable JSON output |
| --signals-file | (none) | Path to a JSON array of context signals to attach |
Exit codes:
0— Certified successfully1— API error (e.g. 401 Unauthorized), missing input, or invalid response
nexart ai verify
Verify a CER bundle or CER package locally. No network call — computes and compares the certificateHash against the bundle contents. Fully compatible with v0.11.0+ CERs that include context.signals, and v0.6.0+ CER packages.
# Verify a raw CER bundle from file
nexart ai verify cer.json
# Verify a CER package (inner bundle verified; envelope fields are not verified)
nexart ai verify cer-package.json
# From stdin
cat cer.json | nexart ai verify
# JSON output
nexart ai verify cer.json --jsonDefault output (PASS — raw bundle):
Verification result: VERIFIED
bundleIntegrity: PASS
nodeSignature: SKIPPED
receiptConsistency: SKIPPEDDefault output (PASS — CER package):
Input type: CER package
Verification result: VERIFIED
bundleIntegrity: PASS
nodeSignature: SKIPPED
receiptConsistency: SKIPPED
Note: Verified inner CER bundle only. Package-level receipt/signature/envelope not verified by this command.Default output (FAIL):
Verification result: FAILED
bundleIntegrity: FAIL
[nexart] Expected hash: sha256:a1b2c3...
[nexart] Computed hash: sha256:d4e5f6...JSON output (--json) — raw bundle:
{
"status": "VERIFIED",
"checks": {
"bundleIntegrity": "PASS",
"nodeSignature": "SKIPPED",
"receiptConsistency": "SKIPPED"
},
"reasonCodes": [],
"certificateHash": "sha256:a1b2c3...",
"bundleType": "cer.ai.execution.v1",
"inputType": "bundle",
"verifiedAt": "2026-03-25T12:00:00.000Z",
"verifier": "@nexart/cli"
}JSON output (--json) — CER package:
{
"status": "VERIFIED",
"checks": {
"bundleIntegrity": "PASS",
"nodeSignature": "SKIPPED",
"receiptConsistency": "SKIPPED"
},
"reasonCodes": [],
"certificateHash": "sha256:a1b2c3...",
"bundleType": "cer.ai.execution.v1",
"inputType": "package",
"verifiedAt": "2026-03-25T12:00:00.000Z",
"verifier": "@nexart/cli",
"verifiedInnerCer": true,
"packageTrustLayersVerified": false
}Options:
| Flag | Default | Description |
|------|---------|-------------|
| --json | false | Machine-readable JSON output |
Exit codes:
0— PASS (inner bundle hash matches)1— FAIL (hash mismatch, invalid bundle, or unsupported format)
nexart ai project-verify (v0.7.0+)
Verify a project bundle (cer.project.bundle.v1) locally. No network required. Delegates all verification logic to verifyProjectBundle() from @nexart/ai-execution — the canonical source of truth for project bundle semantics. The CLI provides the command surface and output formatting.
# From file
nexart ai project-verify project-bundle.json
# From stdin
cat project-bundle.json | nexart ai project-verify
# Machine-readable JSON output
nexart ai project-verify project-bundle.json --jsonChecks performed (in order, via @nexart/ai-execution):
bundleTypediscriminant: must becer.project.bundle.v1- Required fields:
version,protocolVersion,projectBundleId,projectTitle,startedAt,completedAt,integrityblock shape stepRegistryis a non-empty arrayembeddedBundlesis a plain object keyed bystepIdtotalStepsmust equalstepRegistry.length- Per-step: embedded bundle exists;
executionIdandcertificateHashmatch the registry entry; inner CERcertificateHashis independently valid integrity.projectHashis recomputed from all material project metadata and compared to the declared value
Default output (PASS):
Verification result: VERIFIED
bundleType: cer.project.bundle.v1
projectBundleId: proj-abc123
projectTitle: My Project
totalSteps: 3
passedSteps: 3
failedSteps: 0
projectHashIntegrity: PASS
stepIntegrity: PASSDefault output (FAIL):
Verification result: FAILED
bundleType: cer.project.bundle.v1
projectBundleId: proj-abc123
projectTitle: My Project
totalSteps: 3
passedSteps: 2
failedSteps: 1
projectHashIntegrity: FAIL
stepIntegrity: FAIL
[nexart] Error: integrity.projectHash mismatch: expected sha256:..., got sha256:...JSON output (--json):
{
"status": "VERIFIED",
"bundleType": "cer.project.bundle.v1",
"projectBundleId": "proj-abc123",
"projectTitle": "My Project",
"totalSteps": 3,
"passedSteps": 3,
"failedSteps": 0,
"projectHashValid": true,
"checks": {
"structuralValid": true,
"projectHashIntegrity": "PASS",
"stepIntegrity": "PASS"
},
"steps": [
{
"stepId": "step-001",
"sequence": 0,
"executionId": "exec-abc",
"certificateHash": "sha256:...",
"ok": true,
"errors": []
}
],
"errors": [],
"verifiedAt": "2026-04-06T12:00:00.000Z",
"verifier": "@nexart/cli"
}Options:
| Flag | Default | Description |
|------|---------|-------------|
| --json | false | Machine-readable JSON output |
Exit codes:
0— VERIFIED (all checks pass)1— FAILED (any structural, step, or hash error)
Context Signals (v0.5.0+)
Context signals attach upstream evidence — CI approvals, webhook events, human-review records — to a CER. They are included in the context.signals array and are tamper-evident: the certificateHash covers the full context block, so any post-creation modification to signals is detected by nexart ai verify.
Preparing a signals file
A signals file is a plain JSON array of signal objects:
[
{
"type": "approval",
"source": "github-actions",
"step": 0,
"timestamp": "2026-03-15T12:00:00.000Z",
"actor": "alice",
"status": "ok",
"payload": { "pr": 42 }
}
]Attaching signals when creating / certifying
# Create CER with signals
nexart ai create execution.json --signals-file signals.json --out cer.json
# Certify with signals
nexart ai certify execution.json --signals-file signals.jsonThe CLI reads the JSON array from --signals-file, merges it into the request body as { signals: [...] }, and sends it to the node API. The node then embeds the signals in the CER under context.signals and includes them in the certificateHash.
Verifying a signals-containing CER
No extra flags are needed — nexart ai verify handles both plain CERs and CERs with context.signals:
nexart ai verify cer.json
# Verification result: VERIFIED
# bundleIntegrity: PASSIf any signal field is altered after creation, the hash will mismatch and verification fails:
# (tampered context.signals)
nexart ai verify tampered-cer.json
# Verification result: FAILED
# bundleIntegrity: FAILCER Packages (v0.6.0+)
A CER package is an envelope object that wraps a raw CER bundle with optional metadata layers — receipt, signature, and custom envelope fields:
{
"cer": {
"bundleType": "cer.ai.execution.v1",
"certificateHash": "sha256:...",
"version": "1.0.0",
"createdAt": "...",
"snapshot": { ... }
},
"receipt": { ... },
"signature": "base64url-sig=="
}nexart ai verify automatically detects the format:
- Raw bundle — input has
bundleType === 'cer.ai.execution.v1'at the top level. Behavior is identical to pre-v0.6.0. - CER package — input has a
cerfield whose innerbundleType === 'cer.ai.execution.v1'. The CLI verifies only the inner bundle; receipt, signature, and other envelope fields are not verified.
Detection is transparent — no flags are needed. Both formats use the same nexart ai verify command.
What IS verified (inner bundle)
certificateHashis recomputed from the protected set (bundleType,version,createdAt,snapshot) and the optionalcontextblock (signals). A mismatch reportsBUNDLE_HASH_MISMATCH.
What is NOT verified (package envelope)
receiptfields (attestationId, nodeRuntimeHash, etc.)signature(cryptographic envelope signature)- Custom envelope fields
Full package trust verification (receipt + envelope signature) is planned for a future release.
Remote Renderer
The CLI calls a canonical Node.js renderer endpoint for real PNG generation.
Endpoint Configuration
# Via environment variable
export NEXART_RENDERER_ENDPOINT=https://nexart-canonical-renderer-production.up.railway.app
export NEXART_API_KEY=nx_live_...
# Via CLI flags
nexart run sketch.js --endpoint https://render.nexart.io --api-key nx_live_...Expected API
POST /api/render
Content-Type: application/json
Authorization: Bearer <api_key>
{
"code": "...",
"seed": 12345,
"VAR": [0,0,0,0,0,0,0,0,0,0],
"width": 1950,
"height": 2400,
"protocolVersion": "1.2.0"
}
Response: image/png (binary)
Headers:
X-Runtime-Hash: <hash>Equivalent curl
curl -X POST https://nexart-canonical-renderer-production.up.railway.app/api/render \
-H "Content-Type: application/json" \
-H "Authorization: Bearer nx_live_..." \
-d '{"code":"createCanvas(1950,2400);\nbackground(0);\n","seed":12345,"VAR":[0,0,0,0,0,0,0,0,0,0],"width":1950,"height":2400,"protocolVersion":"1.2.0"}' \
--output render.pngSnapshot Format (v1)
{
"protocol": "nexart",
"protocolVersion": "1.2.0",
"runtime": "canonical",
"runtimeHash": "<sha256>",
"codeHash": "<sha256>",
"seed": 12345,
"VAR": [0,0,0,0,0,0,0,0,0,0],
"canvas": { "width": 1950, "height": 2400 },
"outputHash": "<sha256>",
"createdAt": "2026-01-25T...",
"code": "..." // optional, if --include-code
}Hash definitions:
outputHash= SHA-256 of PNG bytescodeHash= SHA-256 of normalized coderuntimeHash= From renderer or SHA-256 of SDK version
Renderer Modes
| Mode | Description |
|------|-------------|
| --renderer remote | Default. Calls canonical renderer with auth, produces real PNG output. |
| --renderer local | NOT implemented yet. Outputs a 1x1 placeholder image only. No auth required. |
# Remote (default) — real PNG output, requires API key for remote endpoints
nexart run sketch.js --seed 12345
# Local — NOT implemented, placeholder only, no auth
nexart run sketch.js --renderer localReal local/offline rendering is planned for a future release.
Environment Variables
| Variable | Description |
|----------|-------------|
| NEXART_RENDERER_ENDPOINT | Remote renderer URL (default: http://localhost:5000) |
| NEXART_NODE_ENDPOINT | NexArt node API URL (default: https://node.nexart.art) |
| NEXART_API_KEY | API key for authenticated requests |
License
MIT — Free for all use including commercial.
See Core vs Edges for the NexArt business model.
