The tenor CLI provides 26 subcommands for elaboration, evaluation, analysis, code generation, serving, source wiring, migration, template management, cryptographic signing, testing, and interactive tooling.
Global Flags
Every subcommand accepts these flags:
| Flag | Description |
|---|---|
--output text|json | Output format (default: text) |
--quiet | Suppress non-essential output |
Environment Variables
| Variable | Used By | Description |
|---|---|---|
ANTHROPIC_API_KEY | tenor connect, tenor ambiguity, LlmPolicy | Anthropic API key for Claude |
TENOR_REGISTRY_TOKEN | tenor publish | Auth token for template registry |
TENOR_REGISTRY_URL | tenor publish, tenor deploy | Registry endpoint override |
TENOR_PLATFORM_TOKEN | tenor deploy | Auth token for hosted platform |
RUST_LOG | All crates | Logging level (tracing-subscriber) |
Core Commands
tenor check
Run the full static analysis suite (S1-S8) against one or more .tenor files.
tenor check [files...]Flags:
| Flag | Description |
|---|---|
--analysis s1,s4,s6 | Run only the specified analyses (comma-separated) |
--authority | Print the authority topology (S4) |
--verbose | Print detailed analysis results per property |
--json | Output analysis report as JSON |
Static Analysis Properties:
| Property | Description |
|---|---|
| S1 | Complete state space enumeration |
| S2 | Reachable/dead state detection |
| S3a | Structural admissibility per state |
| S4 | Authority topology derivation |
| S5 | Verdict and outcome space |
| S6 | Flow path enumeration |
| S7 | Evaluation complexity bounds |
| S8 | Verdict uniqueness (pre-verified by elaboration Pass 5) |
Example usage:
# Run all static analyses
tenor check contract.tenor
# Run only authority topology and flow path enumeration
tenor check contract.tenor --analysis s4,s6
# Check multiple files with verbose output
tenor check trade.tenor inspection.tenor --verbose
# Authority topology as JSON
tenor check contract.tenor --authority --jsonExample output:
tenor check escrow.tenor
S1 State Space
EscrowAccount: 4 states (held, released, refunded, disputed)
DeliveryRecord: 3 states (pending, confirmed, failed)
S2 Reachability
EscrowAccount: 4/4 reachable, 0 dead
DeliveryRecord: 3/3 reachable, 0 dead
S3a Admissibility
EscrowAccount.held:
escrow_agent → release_escrow, refund_escrow
buyer, seller → flag_dispute
EscrowAccount.disputed:
compliance_officer → release_escrow_with_compliance
escrow_agent → refund_escrow
S4 Authority Topology
buyer → {flag_dispute}
seller → {confirm_delivery, flag_dispute}
escrow_agent → {release_escrow, refund_escrow, record_delivery_failure, revert_delivery_confirmation}
compliance_officer → {release_escrow_with_compliance}
S5 Verdict Space
6 verdict types: line_items_validated, delivery_confirmed, delivery_failed,
within_threshold, refund_requested, release_approved,
compliance_review_required, refund_approved
S6 Flow Paths
standard_release: 5 paths, max depth 4, all terminal
refund_flow: 1 path, max depth 1, all terminal
S7 Complexity
Max predicate depth: 3
Max quantifier nesting: 1
Max flow depth: 4
S8 Verdict Uniqueness
All verdict types produced by exactly one rule. ✓
✓ All 8 analyses passed.tenor elaborate
Elaborate .tenor source files into the canonical JSON interchange format through the six-pass pipeline.
tenor elaborate [files...]Flags:
| Flag | Description |
|---|---|
--output PATH | Write interchange JSON to a file instead of stdout |
--pretty | Pretty-print the JSON output |
--manifest | Generate a TenorManifest wrapping the interchange bundle with etag |
Example usage:
# Elaborate and write to file
tenor elaborate contract.tenor > contract.json
# Pretty-printed output
tenor elaborate contract.tenor --pretty
# Generate manifest with etag for deployment
tenor elaborate contract.tenor --manifest > manifest.json
# Multiple source files
tenor elaborate trade.tenor types/common.tenorExample JSON output (abbreviated):
{
"constructs": [
{
"id": "buyer",
"kind": "Persona",
"provenance": { "file": "escrow.tenor", "line": 1 },
"tenor": "1.0"
},
{
"id": "escrow_amount",
"kind": "Fact",
"source": {
"path": "accounts.{id}.balance",
"source_id": "escrow_service"
},
"tenor": "1.0",
"type": { "base": "Money", "currency": "USD" }
}
],
"id": "escrow",
"kind": "Bundle",
"tenor": "1.0",
"tenor_version": "1.1.0"
}tenor evaluate
Evaluate rules against a fact set and produce verdicts. Optionally execute a specific flow as a given persona.
tenor evaluate [files...] --facts facts.jsonFlags:
| Flag | Description |
|---|---|
--facts PATH | Path to JSON file containing fact values (required) |
--flow FLOW_ID | Execute a specific flow |
--persona PERSONA | Persona executing the flow (required with --flow) |
--entity-states PATH | JSON file with initial entity state map |
--instance-bindings PATH | JSON file with entity-to-instance bindings |
Example usage:
# Evaluate rules and see verdicts
tenor evaluate contract.tenor --facts facts.json
# Execute a specific flow as a persona
tenor evaluate contract.tenor --facts facts.json \
--flow standard_release --persona escrow_agent
# With entity states and instance bindings
tenor evaluate contract.tenor --facts facts.json \
--flow standard_release --persona escrow_agent \
--entity-states states.json \
--instance-bindings bindings.jsonExample verdict output:
tenor evaluate escrow.tenor --facts facts.json
FactSet assembled: 5 facts
Stratum 0:
✓ line_items_validated (Bool = true)
✓ delivery_confirmed (Bool = true)
✗ delivery_failed (not produced)
✓ within_threshold (Bool = true)
✗ refund_requested (not produced)
Stratum 1:
✓ release_approved (Text = "auto")
✗ compliance_review_required (not produced)
✗ refund_approved (not produced)
ResolvedVerdictSet: 4 verdictstenor simulate
Execute a flow simulation with full provenance tracking. Produces an execution trace showing every step, entity state change, and decision point.
tenor simulate [files...] --flow FLOW_ID --persona PERSONA --facts facts.jsonFlags:
| Flag | Description |
|---|---|
--facts PATH | Path to JSON file containing fact values (required) |
--flow FLOW_ID | Flow to simulate (required) |
--persona PERSONA | Persona initiating the flow (required) |
--entity-states PATH | JSON file with initial entity state map |
--instance-bindings PATH | JSON file with entity-to-instance bindings |
Example output:
tenor simulate escrow.tenor --flow standard_release \
--persona escrow_agent --facts facts.json
Flow: standard_release
Persona: escrow_agent
Snapshot: frozen at initiation (4 verdicts)
Step 1: step_confirm (OperationStep)
Operation: confirm_delivery
Persona: seller ✓
Precondition: ∀ item ∈ line_items . item.valid = true → true ✓
Effect: DeliveryRecord: pending → confirmed ✓
Outcome: confirmed → step_check_threshold
Step 2: step_check_threshold (BranchStep)
Condition: verdict_present(within_threshold) → true
Route: → step_auto_release
Step 3: step_auto_release (OperationStep)
Operation: release_escrow
Persona: escrow_agent ✓
Precondition: verdict_present(release_approved) → true ✓
Effect: EscrowAccount: held → released ✓
Outcome: released → Terminal(success)
Result: success
Steps executed: 3
Entity changes:
DeliveryRecord: pending → confirmed
EscrowAccount: held → released
Provenance chain:
release_approved ← line_items_validated + delivery_confirmed + within_threshold
within_threshold ← escrow_amount (8500.00 USD) ≤ compliance_threshold (10000.00 USD)
delivery_confirmed ← delivery_status = "confirmed"
line_items_validated ← ∀ item ∈ line_items . item.valid = truetenor actions
Compute the action space for a given persona. Shows which flows the persona can initiate and which are blocked, with reasons.
tenor actions [files...] --persona PERSONA --facts facts.jsonFlags:
| Flag | Description |
|---|---|
--facts PATH | Path to JSON file containing fact values (required) |
--persona PERSONA | Persona to compute actions for (required) |
--entity-states PATH | JSON file with entity state map |
--json | Output as structured JSON |
Example usage:
# Text output
tenor actions escrow.tenor --persona escrow_agent --facts facts.json
# JSON for agent consumption
tenor actions escrow.tenor --persona escrow_agent --facts facts.json --jsonExample text output:
tenor actions escrow.tenor --persona escrow_agent --facts facts.json
Persona: escrow_agent
Verdicts: 4 active
Available Actions:
✓ standard_release
Instances: {EscrowAccount: "esc-001", DeliveryRecord: "del-001"}
Enabling verdicts: release_approved, delivery_confirmed
✓ refund_flow
Blocked — verdict refund_approved not present
Blocked Actions:
✗ refund_flow
Reason: precondition not met — verdict_present(refund_approved) = falseExample JSON output:
{
"persona": "escrow_agent",
"current_verdicts": ["line_items_validated", "delivery_confirmed", "within_threshold", "release_approved"],
"actions": [
{
"flow_id": "standard_release",
"instance_bindings": {
"EscrowAccount": ["esc-001", "esc-002"],
"DeliveryRecord": ["del-001"]
},
"verdicts_enabling": ["release_approved"],
"personas": ["escrow_agent"]
}
],
"blocked_actions": [
{
"flow_id": "refund_flow",
"reason": "precondition_not_met",
"details": "verdict_present(refund_approved) = false"
}
]
}tenor explain
Generate a natural-language explanation of a contract. Useful for onboarding, documentation, and agent orientation.
tenor explain [files...]Flags:
| Flag | Description |
|---|---|
--verbose | Include detailed analysis of all constructs |
--format text|markdown | Output format (default: text) |
Example usage:
# Brief explanation
tenor explain escrow.tenor
# Detailed markdown for documentation
tenor explain escrow.tenor --verbose --format markdownExample output:
tenor explain escrow.tenor
Escrow Release Contract
This contract manages escrow transactions between buyers and sellers.
Payment is held in escrow and released upon delivery confirmation,
or refunded if delivery fails.
Participants:
buyer — Can flag disputes
seller — Confirms delivery
escrow_agent — Releases/refunds escrow, records delivery failure
compliance_officer — Approves high-value releases
Entities:
EscrowAccount — States: held → released, refunded, or disputed
DeliveryRecord — States: pending → confirmed or failed
Key Rules:
- Escrow release is auto-approved when amount ≤ compliance threshold
- High-value releases require compliance officer approval
- Refunds require delivery failure AND buyer request
Flows:
standard_release — Confirm delivery → threshold check → release (auto or compliance)
refund_flow — Direct refund when conditions met
External Systems:
escrow_service (HTTP) — Account balances
delivery_service (HTTP) — Shipment status
order_service (HTTP) — Line items
compliance_service (Database) — Threshold configurationCode Generation
tenor generate typescript
Generate TypeScript types, Zod validation schemas, and an API client from a contract's interchange JSON.
tenor generate typescript INPUTFlags:
| Flag | Description |
|---|---|
--out PATH | Output directory (default: ./generated/) |
--sdk-import MODULE | SDK import path (default: @tenor/sdk) |
Generated files:
| File | Contents |
|---|---|
types.ts | TypeScript interfaces for all Facts, Entities, Verdicts, Operations |
schemas.ts | Zod schemas for runtime validation of all types |
client.ts | API client class with typed methods for evaluate, execute, simulate |
index.ts | Re-exports from all generated modules |
Example usage:
# Generate with defaults
tenor generate typescript contract.json
# Custom output and SDK import path
tenor generate typescript contract.json \
--out ./src/generated \
--sdk-import @tenor/sdkExample generated types:
// generated/types.ts
export interface EscrowFacts {
escrow_amount: Money;
delivery_status: "pending" | "confirmed" | "failed";
line_items: LineItemRecord[];
compliance_threshold: Money;
buyer_requested_refund: boolean;
}
export type EscrowAccountState = "held" | "released" | "refunded" | "disputed";
export type DeliveryRecordState = "pending" | "confirmed" | "failed";
export interface EscrowVerdicts {
line_items_validated?: boolean;
delivery_confirmed?: boolean;
within_threshold?: boolean;
release_approved?: string;
compliance_review_required?: boolean;
refund_approved?: boolean;
}tenor ui
Generate a complete React application from a contract. The generated app includes entity state viewers, fact input forms, flow execution panels, verdict displays, and an action space dashboard.
tenor ui CONTRACTFlags:
| Flag | Description |
|---|---|
--out PATH | Output directory (default: ./ui/) |
--api-url URL | Backend API URL (default: http://localhost:8080) |
--contract-id ID | Contract identifier for multi-contract servers |
--theme PATH | Custom theme configuration file |
--title TEXT | Application title |
Generated structure:
ui/
├── src/
│ ├── components/ Entity viewers, fact forms, verdict displays
│ ├── pages/ Dashboard, flow execution, entity detail
│ ├── hooks/ React hooks for evaluation and state
│ ├── api/ API client targeting tenor serve endpoints
│ └── types/ TypeScript types from contract
├── package.json
├── tsconfig.json
├── vite.config.ts
└── tailwind.config.tsExample usage:
# Generate and run
tenor ui escrow.tenor --out ./my-app --api-url http://localhost:8080
cd my-app && npm install && npm run devServer & Interactive
tenor serve
Start an HTTP API server that exposes contract elaboration, evaluation, simulation, and action space computation over REST endpoints.
tenor serve [contracts...]Flags:
| Flag | Description |
|---|---|
--port PORT | Listen port (default: 8080) |
--tls-cert PATH | TLS certificate file (enables HTTPS) |
--tls-key PATH | TLS private key file |
--hosted | Enable hosted platform mode (multi-tenant) |
--adapter-config PATH | TOML adapter configuration file |
Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /.well-known/tenor | Contract manifest with etag (E10) |
POST | /elaborate | Elaborate DSL source to interchange JSON |
POST | /evaluate | Evaluate rules against facts |
POST | /evaluate/flow | Execute a flow |
POST | /simulate | Dry-run evaluation (no side effects) |
POST | /actions | Compute action space for a persona |
GET | /health | Health check |
Example usage:
# Start with a single contract
tenor serve escrow.tenor
# Custom port with TLS
tenor serve escrow.tenor --port 3000 \
--tls-cert cert.pem --tls-key key.pem
# Multiple contracts with adapter config
tenor serve trade.tenor inspection.tenor settlement.tenor \
--adapter-config adapters.tomlAdapter configuration (TOML):
[global]
timeout_ms = "30000"
[sources.order_service]
base_url = "https://api.example.com/v2"
auth_header = "Bearer <token>"
[sources.compliance_db]
connection_string = "postgresql://user:pass@host/db"tenor agent
Start an interactive agent shell with policy-driven action selection. The agent observes the contract state, evaluates available actions, selects an action using the configured policy, and executes it.
tenor agent FILEThe agent shell supports multiple action-selection policies:
| Policy | Description |
|---|---|
AlwaysApprove | Approve every proposed action |
NeverApprove | Reject every proposed action (observation only) |
FirstAvailablePolicy | Select the first available flow in declaration order |
PriorityPolicy | Select based on a priority ordering of flow IDs |
RandomPolicy | Select uniformly at random |
HumanInTheLoopPolicy | Interactive approval via stdin |
LlmPolicy | AI-powered selection via Claude API |
CompositePolicy | Three-stage pipeline: proposer, predicate, approver |
Example session:
$ tenor agent escrow.tenor
tenor agent v1.0 — interactive contract shell
Contract: escrow (4 personas, 7 operations, 2 flows)
Policy: HumanInTheLoopPolicy
> status
EscrowAccount: held
DeliveryRecord: pending
Verdicts: line_items_validated, delivery_confirmed, within_threshold, release_approved
> actions escrow_agent
Available:
1. standard_release (EscrowAccount: held, DeliveryRecord: pending)
Blocked:
- refund_flow (verdict refund_approved not present)
> execute standard_release --persona escrow_agent
Step 1: confirm_delivery (seller) → confirmed
Step 2: check_threshold → true → step_auto_release
Step 3: release_escrow (escrow_agent) → released
Result: success
Entity state:
EscrowAccount: released
DeliveryRecord: confirmed
> quittenor builder dev / tenor builder build
Start the visual contract Builder development server or produce a production build.
tenor builder dev
tenor builder buildFlags:
| Flag | Description |
|---|---|
--contract PATH | Pre-load a contract file on startup |
--port PORT | Dev server port (default: 5173) |
--open | Open browser automatically |
Example usage:
# Start Builder in dev mode
tenor builder dev
# Pre-load a contract and open browser
tenor builder dev --contract escrow.tenor --open
# Custom port
tenor builder dev --port 3000
# Production build
tenor builder buildThe Builder provides visual editors for entities (drag-and-drop state machines), flows (DAG editor with outcome routing), predicates (structured expression builder), rules, operations, facts, personas, sources, and systems. It includes a simulation mode powered by the WASM evaluator running in the browser.
Source Wiring
tenor connect
Introspect a contract's Source declarations and generate adapter scaffolding. Supports LLM-powered mapping (default), heuristic pattern matching, batch review, and application of reviewed mappings.
tenor connect CONTRACTModes:
| Mode | Flag | Description |
|---|---|---|
| Bare | (none) | Introspect sources, show summary |
| Environment | --environment SPEC | Match against OpenAPI, GraphQL SDL, or SQL schema |
| Heuristic | --heuristic | Pattern-matching mode (no LLM required) |
| Batch | --batch FILE | Generate review file for human approval |
| Apply | --apply FILE | Apply reviewed mappings, generate adapter code |
Additional flags:
| Flag | Description |
|---|---|
--verbose | Show detailed matching rationale |
--out PATH | Output directory for generated adapters |
Example usage:
# Introspect sources
tenor connect contract.tenor
# Match against an OpenAPI spec
tenor connect contract.tenor --environment api-spec.yaml
# Heuristic mode (no LLM, no API key needed)
tenor connect contract.tenor --heuristic --verbose
# Generate review file for human approval
tenor connect contract.tenor --batch review.json
# Apply reviewed mappings and generate adapter code
tenor connect contract.tenor --apply reviewed.json --out ./adaptersExample output (bare mode):
tenor connect escrow.tenor
Source declarations:
escrow_service (http) — https://api.escrow.com/v1
delivery_service (http) — https://delivery.internal/api
order_service (http) — https://api.orders.com/v2
compliance_service (database) — postgres
Fact → Source mappings:
escrow_amount → escrow_service { path: "accounts.{id}.balance" }
delivery_status → delivery_service { path: "shipments.{id}.status" }
line_items → order_service { path: "orders.{id}.line_items" }
compliance_threshold → compliance_service { path: "compliance_thresholds.release_amount" }
buyer_requested_refund → (freetext: "buyer_portal.refund_requested")
Run with --environment to match against your API spec.Migration
tenor diff
Compute a structural diff between two interchange bundles. Classifies each change as BREAKING, NON_BREAKING, REQUIRES_ANALYSIS, or INFRASTRUCTURE.
tenor diff V1 V2Flags:
| Flag | Description |
|---|---|
--breaking | Show only breaking and requires-analysis changes |
--json | Output as structured DiffEntry JSON |
--migration | Generate a Tenor migration contract from the diff |
Example usage:
# Full structural diff
tenor diff v1.json v2.json
# Show only breaking changes
tenor diff v1.json v2.json --breaking
# Machine-readable diff
tenor diff v1.json v2.json --jsonExample output:
tenor diff v1.json v2.json
Entity: EscrowAccount
states: + suspended NON_BREAKING (additive state)
transitions: + (held, suspended) NON_BREAKING (additive transition)
transitions: + (suspended, released) NON_BREAKING (additive transition)
Operation: release_escrow
precondition: changed REQUIRES_ANALYSIS
v1: verdict_present(release_approved)
v2: verdict_present(release_approved) and verdict_present(kyc_cleared)
Fact: kyc_status
(added) NON_BREAKING (new construct)
Rule: kyc_check
(added) REQUIRES_ANALYSIS (new rule at stratum 0)
Source: kyc_service
(added) NON_BREAKING (new source)
Summary: 2 REQUIRES_ANALYSIS, 4 NON_BREAKING
Migration policy required: YES (treat REQUIRES_ANALYSIS as BREAKING per M6)tenor migrate
Full migration analysis between two contract versions. Includes diff, breaking change classification, entity state migration plan, and in-flight flow compatibility assessment.
tenor migrate V1 V2Flags:
| Flag | Description |
|---|---|
--yes | Skip confirmation prompt |
--policy blue-green|force-migrate|abort | Declare in-flight flow migration policy |
Example usage:
# Interactive migration analysis
tenor migrate v1.json v2.json
# Non-interactive with policy declaration
tenor migrate v1.json v2.json --yes --policy blue-greenExample output:
tenor migrate v1.json v2.json
Structural diff: 6 changes (2 REQUIRES_ANALYSIS, 4 NON_BREAKING)
Entity state migration:
EscrowAccount: no instances in removed states ✓
DeliveryRecord: unchanged ✓
In-flight flow analysis:
standard_release:
Position step_confirm: COMPATIBLE (all forward paths exist in v2)
Position step_auto_release: INCOMPATIBLE
Layer 3: precondition requires verdict_present(kyc_cleared),
not in frozen snapshot
Recommendation: Blue-Green deployment
- New flows use v2
- In-flight flows at step_auto_release complete under v1
- In-flight flows at step_confirm can be force-migrated
Proceed? [y/N]Template Management
tenor pack
Package the current directory as a reusable contract template. Reads tenor-template.toml for metadata.
tenor packCreates a .tar.gz archive containing the contract files, interchange JSON, and template metadata.
Template metadata (tenor-template.toml):
[template]
name = "escrow-release"
version = "1.0.0"
description = "Standard escrow release with compliance review"
category = "finance"
tags = ["escrow", "compliance", "payment"]
[author]
organization = "riverline-labs"tenor publish
Publish a packaged template to the Tenor template registry. Requires TENOR_REGISTRY_TOKEN.
tenor publishTemplates go through a review workflow before becoming publicly available.
tenor search
Search the template registry by name, description, category, or tags.
tenor search QUERYFlags:
| Flag | Description |
|---|---|
--category CATEGORY | Filter by category (e.g., finance, supply-chain) |
Example usage:
# Search by keyword
tenor search "escrow"
# Filter by category
tenor search "compliance" --category financeExample output:
tenor search "escrow"
@riverline/escrow-standard v1.0.0 finance
Standard escrow release with compliance review and multi-persona authority.
@riverline/escrow-milestone v0.9.0 finance
Milestone-based escrow with phased release and inspection gates.
2 templates foundtenor install
Install a template from the registry to the local directory.
tenor install TEMPLATEExample usage:
tenor install @riverline/escrow-standardtenor deploy
Deploy a template directly to the hosted platform for a given organization.
tenor deploy TEMPLATE --org ORG_IDRequires TENOR_PLATFORM_TOKEN. Creates a new contract deployment on the hosted platform from the template, provisioning all necessary infrastructure.
Example usage:
tenor deploy @riverline/escrow-standard --org my-orgExample output:
tenor deploy @riverline/escrow-standard --org my-org
Deploying escrow-standard v1.0.0 to organization my-org...
Contract ID: ct_a1b2c3d4
API endpoint: https://my-org.tenor.run
Manifest: https://my-org.tenor.run/.well-known/tenor
Etag: 3f7a9b2c...
Personas mapped:
buyer → API key required
seller → API key required
escrow_agent → API key required
compliance_officer → API key required
✓ Deployed successfully.Cryptography
tenor keygen
Generate an Ed25519 signing keypair for contract and WASM bundle signing.
tenor keygenFlags:
| Flag | Description |
|---|---|
--prefix NAME | Custom filename prefix (default: tenor-key) |
Example usage:
# Default keypair
tenor keygen
# Creates: tenor-key.secret, tenor-key.public
# Custom prefix
tenor keygen --prefix my-signer
# Creates: my-signer.secret, my-signer.publicOutput:
tenor keygen
Generated Ed25519 keypair:
Secret key: tenor-key.secret
Public key: tenor-key.public
Keep tenor-key.secret safe. Do not commit it to version control.tenor sign
Sign an interchange bundle with an Ed25519 secret key. Produces a signed bundle with an embedded attestation.
tenor sign BUNDLE --key SECRET_KEYThe attestation includes: signer public key, signature (base64), algorithm (ed25519), signed-at timestamp, and signed etag (SHA-256 of bundle content).
Example usage:
tenor sign contract.json --key tenor-key.secret
# Creates: contract.signed.jsonExample output:
tenor sign contract.json --key tenor-key.secret
Bundle etag: 3f7a9b2c4d5e6f...
Signer: tenor-key.public (ed25519)
Signed at: 2026-03-01T12:00:00Z
Output: contract.signed.json
✓ Bundle signed.tenor verify
Verify the signature on a signed interchange bundle.
tenor verify BUNDLEExample usage:
tenor verify contract.signed.jsonExample output:
tenor verify contract.signed.json
Algorithm: ed25519
Signer: Hx7Kp2... (public key)
Signed at: 2026-03-01T12:00:00Z
Signed etag: 3f7a9b2c4d5e6f...
Current etag: 3f7a9b2c4d5e6f...
✓ Signature valid. Bundle has not been modified since signing.tenor sign-wasm
Sign a WASM evaluator binary, binding it to a specific contract bundle via etag. Prevents substitution attacks where a signed WASM module is used with a different contract.
tenor sign-wasm WASM --key SECRET_KEY --bundle-etag ETAGExample usage:
tenor sign-wasm evaluator.wasm --key tenor-key.secret --bundle-etag "3f7a9b2c..."
# Creates: evaluator.wasm.sigtenor verify-wasm
Verify a WASM evaluator binary's signature against a public key.
tenor verify-wasm WASM --sig SIG --pubkey PUBLIC_KEYExample usage:
tenor verify-wasm evaluator.wasm --sig evaluator.wasm.sig --pubkey tenor-key.publicExample output:
tenor verify-wasm evaluator.wasm --sig evaluator.wasm.sig --pubkey tenor-key.public
WASM hash: a9f3c7...
Bundle etag: 3f7a9b2c4d5e6f...
Signer: Hx7Kp2... (public key)
✓ WASM signature valid. Binary is bound to bundle etag 3f7a9b2c...Testing
tenor test conformance
Run the elaborator conformance test suite. The suite validates all six elaboration passes against 127 test fixtures covering positive, negative, numeric precision, type promotion, shorthand expansion, cross-file, parallel entity conflict, and verdict uniqueness cases.
tenor test conformanceOutput uses TAP v14 format.
Example output:
tenor test conformance
TAP version 14
1..127
ok 1 - positive/basic_fact.tenor
ok 2 - positive/entity_transitions.tenor
ok 3 - positive/rule_stratification.tenor
...
ok 41 - positive/integration_escrow.tenor
ok 42 - negative/pass0_unterminated_comment.tenor
ok 43 - negative/pass1_import_cycle.tenor
...
ok 90 - negative/pass5_duplicate_outcome.tenor
ok 91 - numeric/decimal_precision.tenor
...
ok 100 - numeric/money_comparison.tenor
ok 101 - promotion/int_decimal_cross.tenor
ok 102 - promotion/mul_type_promotion.tenor
ok 103 - shorthand/simple_rule.tenor
ok 104 - shorthand/operation_single_effect.tenor
ok 105 - cross_file/import_types.tenor
ok 106 - cross_file/import_facts.tenor
ok 107 - parallel/overlapping_effects.tenor
ok 108 - parallel/non_overlapping.tenor
...
ok 127 - manifest/basic_manifest.tenor
# 127 tests, 127 passed, 0 failedtenor ambiguity
Run AI-powered ambiguity testing against a contract. Uses Claude to identify potential ambiguities between the contract's behavior and the formal specification, then generates test cases targeting those ambiguities.
tenor ambiguity CONFORMANCE_DIR --spec SPEC_PATHRequires ANTHROPIC_API_KEY.
Example usage:
tenor ambiguity conformance/ --spec docs/tenor-language-specification.mdExample output:
tenor ambiguity conformance/ --spec docs/tenor-language-specification.md
Analyzing conformance suite against specification...
Ambiguity 1: §7.3 stratum equality prohibition
The spec says "equality is not permitted" for same-stratum references.
Existing tests cover cross-stratum references but not same-stratum
with zero dependencies between rules.
Generated: ambiguity_stratum_same_no_dep.tenor
Ambiguity 2: §4.2 Duration cross-unit promotion
The spec defines Duration(days) + Duration(hours) → Duration(hours).
No conformance test exercises Duration arithmetic with mixed units.
Generated: ambiguity_duration_cross_unit.tenor
Ambiguity 3: §10.6 Entity state in predicate
The spec prohibits entity state in predicates.
No negative test verifies the error message for this case.
Generated: ambiguity_entity_state_predicate.tenor
3 ambiguity test cases generated.LSP
tenor lsp
Start the Language Server Protocol server for .tenor files. Communicates over stdio and integrates with any LSP-compatible editor.
tenor lspThe LSP server is typically launched automatically by the VS Code extension, but can be used with any editor that supports LSP.
Capabilities:
| Feature | Description |
|---|---|
| Diagnostics | Real-time elaboration errors and warnings as you type |
| Go-to-definition | Navigate to construct declarations (facts, entities, rules, operations, flows, personas, sources) |
| Hover | Type information, source declarations, construct details on hover |
| Autocomplete | Context-aware completion for construct references, persona names, entity states, verdict types |
| Semantic tokens | Syntax highlighting for all Tenor constructs |
| References | Find all references to a construct across files |
VS Code extension setup:
The VS Code extension (editors/vscode/) uses vscode-languageclient to connect to the LSP server. Install the extension, and it will automatically start the tenor lsp process when you open a .tenor file.
Validation
tenor validate
Validate an existing interchange JSON bundle against the formal JSON Schema (schema/interchange-schema.json).
tenor validate BUNDLEExample usage:
tenor validate contract.jsonExample output:
tenor validate contract.json
Schema: interchange-schema.json v1.0
Bundle: contract.json
Constructs: 4 Personas, 4 Sources, 5 Facts, 2 Entities, 8 Rules, 7 Operations, 2 Flows
✓ Valid interchange bundle.