Introduction

Parallax is a universal polyglot execution runtime written in Rust.

Capture program state in one language, encode it as language-neutral PIR, and restore it in another — with real workers, measured timings, and honest semantic-loss reporting.

This site documents what exists today in the 0.1.x workspace: Python ↔ JavaScript state migration, snapshots, the plx CLI, and a constrained WASM executor.

ResourceLink
Sourcegithub.com/parallax-runtime/parallax
Docs (this site)parallax-runtime.github.io/parallax
ChangelogCHANGELOG.md
SecuritySECURITY.md
PrivacyPRIVACY.md
LicenseApache-2.0
MSRVRust 1.75

Start here

  1. What Parallax is — scope and non-goals
  2. Getting started — install and first commands
  3. Migration demo — Python → JavaScript in one command
  4. Architecture — crates, workers, pipeline

Design principles

  • No fake demos — unsupported work returns structured Unsupported / MigrationRejected
  • Measured timings — capture / analyze / convert / restore durations are real wall-clock microseconds
  • Explicit capabilities — every adapter declares what it can and cannot do
  • Process isolation — Python and JavaScript guests run in subprocess workers over a versioned NDJSON protocol

What Parallax is

Parallax is infrastructure for polyglot execution and state migration.

You write (or already have) a small program that defines data bindings. Parallax:

  1. Executes it in a host runtime (Python, JavaScript, or WASM)
  2. Captures named bindings into PIR (Parallax Intermediate Representation)
  3. Analyzes semantic compatibility for a target runtime
  4. Converts the PIR under an explicit policy
  5. Restores the bindings into the target runtime
  6. Optionally emits a source preview and/or a .plx snapshot

The headline path in 0.1 is:

Python program defining `state` → PIR → JavaScript object
JavaScript program defining `state` → PIR → Python dict

What Parallax is not

Be explicit about non-goals so expectations stay honest:

Not thisReality in 0.1
A full cross-language VM that migrates running stacksStack / continuation migration is not supported
Transparent function / closure migrationFunctions become Unsupported
A language transpilerEmit is a preview of restored bindings, not a compiler
A sandbox for untrusted multi-tenant SaaSLimits exist; network/FS isolation is policy-level, not a hardened jail
A drop-in replacement for gRPC / FFIDifferent problem — Parallax moves values, not RPCs

Who it is for

  • Runtime / compiler engineers exploring polyglot state interchange
  • Tooling authors who need a checked, language-neutral value layer
  • Projects that want opt-in migration with loss reporting instead of silent coercion

Version posture

0.1.0 is an early but working release of the migration path. APIs and PIR schema may evolve; schema and protocol versions are versioned independently (PIR_SCHEMA_VERSION, PROTOCOL_VERSION, SNAPSHOT_FORMAT_VERSION).

Getting started

Prerequisites

DependencyRequired forNotes
Rust 1.75+ (stable)Build / CLIrustup
Node.js 18+JavaScript adapterDetected as node
Python 3.10+Python adapterDetected as python, python3, py, then common install paths
GitCloneOptional if you use a release binary later

Windows tip: The Microsoft Store python alias often fails. Install from python.org or ensure a real interpreter is on PATH. plx doctor will say clearly when Python is missing.

Install from source

git clone https://github.com/parallax-runtime/parallax.git
cd parallax
cargo build -p parallax-cli --release

Binaries land at:

target/release/plx
target/release/parallax

plx and parallax are equivalent entry points.

Add the release directory to your PATH, or invoke via Cargo:

cargo run -p parallax-cli --bin plx -- doctor

First health check

plx doctor

Example healthy output (versions will vary):

Parallax 0.1.0
Host: windows x86_64

[javascript] READY
  binary: node
  version: 24.x

[python] READY
  binary: .../python.exe
  version: 3.12.x

[wasm] READY
  binary: wasmtime (in-process)

Doctor: OK — at least one runtime is ready.

JSON form:

plx doctor --json

Run a program

plx run examples/demo.py
plx run examples/demo.js
plx run examples/hello.wat --entry run

Runtime is inferred from the file extension (.py, .js, .wat / .wasm) unless you pass --runtime.

Next steps

Migration demo

The canonical demo migrates a small Python object into JavaScript (and back).

Source (examples/demo.py)

state = {
    "username": "Ada",
    "score": 42,
    "projects": ["compiler", "runtime", "vm"],
}
print("python state ready:", state)

Python → JavaScript

plx migrate examples/demo.py --to javascript -o examples/demo.migrated.js

What happens:

  1. Capture — Python worker executes the file and encodes state as PIR
  2. Analyze — semantic-loss pass for JavaScript
  3. Convert — PIR rewritten under the default conversion policy
  4. Restore — JavaScript worker materializes the bindings
  5. Emit — optional JS source preview written to -o

You should see measured timings similar to:

Migration python → javascript (OK)
timings:
  capture: … µs
  analyze: … µs
  convert: … µs
  restore: … µs
  total:   … µs

migrated bindings:
  state: map{3}

Numbers are wall-clock measurements, not placeholders.

Emitted preview (shape):

const state = { "username": "Ada", "score": 42, "projects": ["compiler", "runtime", "vm"] };

JavaScript → Python

plx migrate examples/demo.js --to python -o examples/demo.migrated.py

Integer precision policy

examples/demo_bigint.py uses a value outside the JS safe integer range (9007199254740993).

FlagsResult
(default)Convert to BigInt (prefer_bigint=true) — migration OK, finding SAFE
--no-prefer-bigintRejected as LOSSY / MigrationRejected
--no-prefer-bigint --allow-lossyCoerce to JS Number (opt-in precision loss)
plx migrate examples/demo_bigint.py --to javascript --no-prefer-bigint
# → fails with structured MigrationRejected

plx migrate examples/demo_bigint.py --to javascript -o examples/demo_bigint.migrated.js
# → score becomes 9007199254740993n in the preview

Snapshot along the way

plx migrate examples/demo.py --to javascript \
  --snapshot /tmp/demo.migrated.plx \
  -o /tmp/demo.migrated.js

plx inspect /tmp/demo.migrated.plx

Machine-readable report

plx migrate examples/demo.py --to javascript --json

Includes the migration report (findings + timings) and the migrated PIR bindings object.

Transmute — project migration

Transmute migrates an entire software project from one language/ecosystem to another using a semantic pipeline — not file-by-file text translation.

SOURCE PROJECT
      ↓
Project Analysis → ProjectGraph + PUIR
      ↓
Migration plan (deps, frameworks, layout)
      ↓
Code generation
      ↓
Build → Test → Repair → Report
      ↓
TARGET PROJECT

First supported path

SourceTargetStatus
TypeScript / JavaScript (Node, Express)Rust (Axum)Implemented (weather-api demo)
PythonRustAnalysis / planning only
Other pairsStructured Unsupported

CLI

# Analyze + migrate a project
plx migrate ./examples/weather-api --to rust --output ./examples/weather-api-rust --verify

# Plan only
plx migrate ./api --to rust --dry-run

# Quality gates
plx migrate ./api --to rust --require-build --require-tests --min-confidence 0.9

# Origin lookup (source maps)
plx origin src/service.rs:14 -C ./examples/weather-api-rust

plx migrate auto-selects Transmute when the path is a project directory (or --to is a language such as rust). Use --mode value for PIR state migration of a single guest program.

Representations

IRMeaning
PIRValues / heap bindings
PUIRProgram semantics (functions, types, intent ops)
PCIR / UESSuspended execution (Continuum)
ProjectGraphModules, deps, edges, entrypoints, tests

PUIR is versioned independently (puir_schema on plx version).

Workspace

Migrations write .parallax/ under the source root (project.json, graph.json, puir.json, plan.json, …) for inspection and future incremental updates.

Demo

plx migrate examples/weather-api --to rust -o examples/weather-api-rust --require-build --require-tests
cd examples/weather-api-rust
cargo test
cargo run

See PARALLAX_MIGRATION.md and parallax-report.json in the output directory.

Honesty rules

  • Compatibility percentages come from measured analysis (PUIR coverage, dep confidence, …) — never invented.
  • Uncertain regions get // PARALLAX REVIEW: markers and report entries.
  • Secrets in .env are never copied; only .env.example names are emitted.
  • Cross-language project migration is not Continuum live-stack resume.

Mirror — continuous cross-language sync

Mirror keeps a migrated target project synchronized with an evolving source project. After Transmute produces a first target, link the pair and sync incrementally instead of remigrating the whole repository.

TypeScript changes
        ↓
semantic diff vs baseline PUIR
        ↓
regenerate affected regions
        ↓
build + differential tests
        ↓
Rust (or other target) updated

First supported path

SourceTargetTier
TypeScript / JavaScriptRustTier 1 (weather-api demo)
PythonRustTier 2 (planning / partial)
Rust → TypeScriptExperimental (reverse sync gated)

Tiers reflect implemented conformance, not marketing claims.

Workflow

# One-time: migrate, then link
plx migrate ./examples/weather-api --to rust -o ./examples/weather-api-rust --require-build --require-tests
plx link ./examples/weather-api ./examples/weather-api-rust

# Ongoing
# edit TypeScript…
plx sync
plx sync --check    # CI / no writes
plx status          # drift summary
plx ci              # sync --check + target verify

Link metadata lives under the target:

.parallax-link/
├── link.json
├── source-index.bin
├── semantic-map.bin
├── dependency-map.json
├── manual-regions.json
├── ownership.json
├── baselines/
└── history/

Default policy: source-authoritative.

Commands

CommandPurpose
plx link <src> <tgt>Create Mirror link
plx syncIncremental translate + verify
plx sync --checkFreshness only (fails if stale)
plx sync --reverseTarget→source when node is ExactYes (else Unsupported)
plx sync --patchPreview regenerate without writing
plx status / --jsonDrift / machine-readable status
plx cisync --check + differential verify
plx historySync history
plx rollbackRestore last pre-sync target snapshot
plx explain <file:line> -C <tgt>Source-map explanation
plx why <file> -C <tgt>Why a target file changed
plx verifyRun differential / property notes

What sync does (and does not)

Does

  • Semantic diff of PUIR (not text-only)
  • Stable semantic IDs (plx:function:…)
  • Regenerate affected modules transactionally (snapshot → apply → build/test → commit or restore)
  • Preserve files marked with manual BEHAVIOR_CHANGE ownership
  • Report testing confidence (migrated suite), never claim formal proof

Does not (yet / honest limits)

  • Full bidirectional live migration without review gates
  • Property-based equivalence as a complete fuzzer (--property notes only)
  • plx watch daemon (not shipped)
  • Guaranteed idiom preservation for every manual refactor
  • All language pairs as Tier 1

Manual edits

Ownership metadata is stored in .parallax-link/ownership.json and manual-regions.json (sidecar preferred over invasive markers). Behavior-changing target edits block overwrite under source-authoritative policy until you choose preserve / overwrite / inspect.

CI

- run: plx sync --check
- run: plx ci

Fails when the link is stale, the target fails build/tests, or verification mismatches.

Event Horizon

Event Horizon is Parallax's semantic reconstruction layer for migrations that look "impossible" on paper — dynamic Python, open dispatch, eval, native extensions, and other constructs with no direct target equivalent.

Philosophy: no direct equivalent ≠ migration impossible. Preserve behavior via native lowering, specialized capsules, polyglot islands, or (eventually) behavioral synthesis — never silent semantic drift.

Crate layout (consolidated)

Phase X originally scaffolded ~20 small crates; they are merged into one workspace member:

CrateRole
parallax-horizonFull Event Horizon stack — PVABI (pvabi/), semantics, behavior, IR, VCS stubs, and orchestration (analyze_impossible, debt, dissolve, detach, etc.)

Inside parallax-horizon, modules are grouped as pvabi/, semantics/, behavior/, ir/, and vcs/. Public types are re-exported at the crate root (e.g. ProjectObserver, PreservationPolicy, SemanticPatch) and also available via submodule paths (e.g. parallax_horizon::pvabi::PvValue, parallax_horizon::behavior::ProjectObserver, parallax_horizon::vcs::SemanticPatch).

CLI commands

Top-level plx commands (Windows stack size is raised in parallax-cli/build.rs):

CommandPurpose
plx observe [path]Static semantic inspection (languages, dynamic signals, effects)
plx impossible [path] --to rustHard barriers + proposed preservation strategies
plx dissolve [path]One-step polyglot island shrink (scaffold)
plx debt [path]Compatibility debt / target purity score
plx detach [path]Whether source runtime can be dropped (threshold-based)
plx reconstructBehavioral reconstruction status (scaffold)
plx optimize-migration [path]Propose native replacements for capsules/islands
plx explain-barrier --id N [path]Explain a barrier from plx impossible
plx blame <file:line>Semantic blame (scaffold — needs .plxmap.json)
plx cherry-pick <commit>Semantic cherry-pick (scaffold)
plx patch --examplePrint example .plxp semantic patch

Use --json on any command for machine-readable output.

Example

plx observe examples/hostile-dynamic
plx impossible examples/hostile-dynamic --to rust
plx debt examples/hostile-dynamic --to rust

The hostile-dynamic fixture includes getattr, decorators, and asyncio signals.

Honest limits

  • Observatory uses static heuristics, not dynamic tracing.
  • Behavior synthesis / CEGIS / reconstruct are scaffolds — no end-to-end behavioral equivalence yet.
  • Semantic git (blame, cherry-pick) requires .plxmap.json + git linkage (not wired).
  • Debt / dissolve / detach scores are estimates from preservation decisions — verify with tests before production detach.
  • Transmute / Mirror / weather-api paths are unchanged; Horizon is additive analysis tooling.

See also: Transmute, Mirror, Limitations.

CLI reference

Binaries: plx and parallax (identical).

plx [GLOBAL FLAGS] <COMMAND>

Global flags

FlagDescription
--jsonPrefer JSON on stdout for supporting commands; errors as JSON on stderr when set
-v, --verboseRicher human diagnostics
--traceStructured tracing to stderr (JSON subscriber)

plx run <file>

Execute a guest program.

OptionDefaultDescription
-r, --runtime <name>inferredpython / javascript / wasm (aliases: py, js, node, wat)
--timeout-ms <n>30000Wall-clock timeout
--entry <name>run (WASM)Exported WASM function
--capture <names>Comma-separated bindings to capture after execution

Examples:

plx run examples/demo.py
plx run examples/demo.py --capture state
plx run examples/hello.wat --entry run
plx run app.js --runtime javascript --timeout-ms 5000

plx migrate <file> --to <runtime>

Capture → analyze → convert → restore.

OptionDefaultDescription
-t, --to <runtime>requiredTarget runtime
-f, --from <runtime>inferredSource runtime override
--capture <names>stateBindings to migrate
--allow-lossyoffPermit known-lossy conversions
--no-prefer-bigintoffDo not auto-promote unsafe ints to BigInt
-o, --output <path>Emit target-language source preview
--snapshot <path>Write migrated .plx
--pir-inputoffTreat file as a PIR JSON document (skip live capture)
plx migrate examples/demo.py --to javascript -o out.js
plx migrate examples/demo.js --to python --json

plx snapshot <file> -o <out.plx>

Capture bindings into a validated snapshot.

OptionDefaultDescription
-o, --outputrequiredOutput path
-r, --runtimeinferredRuntime override
--capturestateBinding names
--labelOptional label stored in the snapshot

plx inspect <file.plx>

Validate magic, format version, PIR schema, and content hash; print summary (or JSON).

plx restore <file.plx> --target <runtime>

Restore snapshot bindings into a fresh worker and report restored names / types.

plx runtimes

List registered adapters with readiness and host versions (production + scaffold connectors).

plx connectors

Full language connector catalog (60+ languages) with maturity and transmute roles.

plx connectors
plx connectors --pairs
plx connectors java
plx connectors --maturity scaffold --family managed_vm
plx connectors --json

See Language connectors.

Atlas (plx analyze / adapters / …)

Modular stack detection and adapter planning. Guide: Atlas architecture.

plx adapters
plx adapters info typescript
plx adapters capabilities python
plx adapters health
plx analyze examples/weather-api --to rust
plx stacks
plx mappings axios
plx compatibility python rust
plx unsupported examples/weather-api
plx explain-stack examples/weather-api --to rust
CommandNotes
adapters [list|info|capabilities|health|update|report]Built-in Atlas registry
analyze [path] [--to lang] [--write-lock]Detect stack + estimate coverage
stacksTarget stack presets
mappings [query]Dependency equivalence DB
compatibility <src> <tgt>Pair feature scores
unsupported [path]Scaffold / limited adapters
explain-stack [path] [--to]Why a target stack was chosen
adapter new|validateThird-party tooling stubs

plx capabilities [runtime]

Print the capability matrix (YES / PARTIAL / EXPERIMENTAL / NO).

Optional positional filter: plx capabilities python.

plx doctor

Probe the host for Python, Node, and WASM readiness. Exit non-zero if no runtime is ready.

plx bench

Measured micro-benchmark of capture → migrate → restore.

OptionDefaultDescription
--iterations <n>5Sample count
--file <path>examples/demo.pySource program
--to <runtime>javascriptTarget
plx bench --iterations 20 --json

Continuous sync after a Transmute migration. Full guide: Mirror.

plx link ./api-ts ./api-rust
plx sync
plx sync --check
plx status --json
plx ci
plx history
plx rollback
plx explain src/service.rs:20 -C ./api-rust
plx why src/service.rs -C ./api-rust
plx verify
CommandNotes
link <src> <tgt> [--policy …]Default policy: source-authoritative
sync [--check|--reverse|--patch|--lint|--no-verify]Incremental; --check is non-mutating
cisync --check + differential verify
statusDrift; --json for editors/CI

plx version

Print product / schema versions (--format json or global --json).

Capabilities matrix

Adapters declare capabilities explicitly. Attempting an unsupported operation returns a structured error — it is never silently ignored.

Run plx capabilities on your machine for the live table.

Python

CapabilityLevel
ValuesYES
GlobalsYES
LocalsPARTIAL
FunctionsPARTIAL (encoded as function / unsupported for migrate)
ClosuresPARTIAL
Stack captureEXPERIMENTAL
Stack frames / control positionEXPERIMENTAL (explicit checkpoint only)
Continuation capture / restoreEXPERIMENTAL (same-runtime checkpoint)
Cross-runtime resumeNO
Async migrationNO
ExecutionYES
Stdio captureYES
TimeoutsYES
Resource limitsPARTIAL
CancellationYES

JavaScript (Node.js)

CapabilityLevel
ValuesYES
GlobalsYES
LocalsPARTIAL
FunctionsPARTIAL
ClosuresPARTIAL
Stack captureNO
Stack frames / control positionEXPERIMENTAL (explicit checkpoint only)
Continuation capture / restoreEXPERIMENTAL (same-runtime checkpoint)
Cross-runtime resumeNO
Async migrationNO
ExecutionYES
Stdio captureYES
TimeoutsYES
Resource limitsPARTIAL
CancellationYES

WebAssembly (wasmtime)

CapabilityLevel
ValuesPARTIAL
Globals / locals / closuresNO
FunctionsPARTIAL (call zero-arg exports)
Stack / continuation / asyncNO
ExecutionYES
Stdio captureNO
Timeouts / fuel / limitsYES
CancellationYES
State restore / migrateNO

Cross-runtime migration

From \ ToPythonJavaScriptWASM
Pythonrestore OKmigrate OKUnsupported
JavaScriptmigrate OKrestore OKUnsupported
WASMUnsupportedUnsupportedUnsupported

Language connectors

Run plx connectors for the live catalog. Summary:

MaturityCount (approx.)Execute / migrate
production4 (py, js, ts analyze, wasm)Real (wasm: execute only)
experimentalruby, php, go (+ Rust target)Workers when host present
scaffold / planned50+NO (registered Unsupported)

Scaffold adapters appear in plx runtimes as DEGRADED (host found) or UNAVAILABLE (host missing). That is intentional.

Mirror (project sync)

CapabilityLevel
Link TS/JS → RustYES (Tier 1 demo)
Semantic diff + incremental syncYES
sync --check / plx ciYES
Manual-region preservation (sidecar)PARTIAL
Three-way semantic mergePARTIAL (conflicts reported; no silent guess)
Differential executionPARTIAL (migrated test suite; not formal proof)
Reverse syncEXPERIMENTAL / gated Unsupported
Watch daemonNO
Property fuzz equivalenceEXPERIMENTAL notes only

Limitations

This page is the honest list for 0.1. Prefer reading it over marketing claims.

Explicitly unsupported

  • Migrating arbitrary live call stacks / instruction pointers across runtimes (Continuum does not claim this)
  • Cross-runtime continuation resume (contract returns Unsupported; same-runtime explicit checkpoint is Experimental — see Continuum)
  • Deterministic replay engine (journal schema only)
  • Migrating functions / closures as callable values across runtimes
  • Migrating in-flight async tasks / promises / coroutines
  • WASM binding capture or restore / continuum
  • Non-string map keys round-tripping cleanly to JS objects
  • Shared object-identity graphs with cycles (bindings-first model; ref exists but restore is incomplete)
  • Hard multi-tenant isolation (no seccomp/Seatbelt/Windows job-object enforcement yet)
  • Mirror reverse sync for arbitrary nodes (gated; returns Unsupported unless ExactYes)
  • Mirror property-based equivalence as a complete fuzzer (plx verify --property is notes / confidence only — not proof)
  • Mirror watch daemon (plx watch) — not shipped
  • Treating all language pairs as equally mature (see pair tiers in Mirror and Connectors)
  • Scaffold connectors (Go, Java, Ruby, C#, …): identity + host probe only — execute/restore/migrate return Unsupported until a real worker/codegen ships

Semantic edge cases

CaseDefault behavior
Python int outside JS safe integer rangePromote to JS BigInt
Same, with --no-prefer-bigintReject (MigrationRejected / LOSSY)
Same, with --allow-lossy and no BigIntCoerce to Number (lossy)
Python tuple → JSBecomes Array (SAFE)
Python set → JSBecomes Array (SAFE)
bytes → JSUint8Array (SAFE)
Unknown host typesUnsupported PIR node

Host discovery quirks

  • Windows Store Python stubs are treated as unavailable
  • Discovery order: python, python3, py, then %LOCALAPPDATA%\Programs\Python\*\python.exe and Program Files trees
  • Node discovery: node, nodejs, then %ProgramFiles%\nodejs\node.exe

Stability

  • PIR schema, protocol, snapshot format, adapter interface, UES format, PCIR schema, PUIR schema, and Mirror link format are versioned independently (1 today unless noted)
  • Breaking changes will bump those constants; loaders reject mismatches
  • CLI flag surface may grow; prefer --json for scripting
  • See Versioning for which constant to bump

Architecture

Parallax separates orchestration in Rust from guest execution in language-specific workers.

System overview

flowchart LR
  CLI["plx / parallax CLI"] --> RT["parallax-runtime<br/>RuntimeManager"]
  RT --> PY["Python adapter"]
  RT --> JS["JS adapter"]
  RT --> WASM["WASM adapter"]
  PY --> PW["python worker.py<br/>NDJSON stdin/stdout"]
  JS --> JW["node worker.js<br/>NDJSON stdin/stdout"]
  WASM --> WT["wasmtime<br/>in-process + fuel"]
  RT --> MIG["parallax-migrate"]
  RT --> SNAP["parallax-snapshot"]
  MIG --> PIR["parallax-ir PIR"]
  SNAP --> PIR

Process model

sequenceDiagram
  participant Core as Parallax Core
  participant Worker as Runtime Worker
  participant Guest as Guest program

  Core->>Worker: hello
  Worker-->>Core: hello ack + host version
  Core->>Worker: execute + capture names
  Worker->>Guest: exec / vm.run
  Guest-->>Worker: bindings
  Worker-->>Core: PIR-tagged JSON bindings
  Core->>Worker: restore bindings
  Worker-->>Core: restored summaries
  Core->>Worker: shutdown

Python and JavaScript guests never share an address space with the core. WASM is the exception: it runs in-process via wasmtime with fuel limits.

Crate map

The workspace ships 22 Rust crates (Event Horizon is one crate — not a meta-workspace explosion).

LayerCrateResponsibility
Coreparallax-coreErrors, IDs, capabilities, execution model, semantic-loss enums
IRparallax-irPIR values, documents, hashing
IRparallax-pcirContinuation IR (Continuum)
IRparallax-puirUniversal Program IR (Transmute)
IRparallax-uesUniversal Execution State, safepoints
Protocolparallax-protocolVersioned NDJSON envelopes
Projectparallax-projectProjectGraph for whole-repo migration
Securityparallax-securitySandbox / limit policy
Diagnosticsparallax-diagnosticsTracing helpers, doctor report types
Snapshotparallax-snapshot.plx format + integrity validation
Migrateparallax-migrateAnalyze + convert PIR across runtimes
Transmuteparallax-transmuteProject analyze → plan → codegen → repair
Mirrorparallax-mirrorLinked sync, semantic diff, CI gates
Horizonparallax-horizonImpossible migration analysis (observe / debt / impossible)
Atlasparallax-adapter-sdkAdapter contracts, manifests, capabilities
Atlasparallax-atlasRegistry, stack detection, parallax.lock
Connectorsparallax-connectors60+ language catalog + experimental workers
Runtimeparallax-runtimeAdapter trait, discovery, worker process, manager
Runtimeparallax-adapter-pythonCPython subprocess adapter
Runtimeparallax-adapter-jsNode.js subprocess adapter
Runtimeparallax-adapter-wasmwasmtime adapter
CLIparallax-cliplx / parallax binaries

Product layers

flowchart TB
  subgraph exec [Execution and value migration]
    CLI1[plx run / migrate / snapshot]
    RT[parallax-runtime]
    PIR[parallax-ir PIR]
    CLI1 --> RT --> PIR
  end
  subgraph project [Project migration]
    TM[parallax-transmute]
    AT[parallax-atlas]
    PUIR[parallax-puir]
    CLI2[plx migrate dir / analyze]
    CLI2 --> AT --> TM --> PUIR
  end
  subgraph sync [Continuous sync]
    MR[parallax-mirror]
    CLI3[plx link / sync / ci]
    CLI3 --> MR
  end
  subgraph horizon [Event Horizon]
    HZ[parallax-horizon]
    CLI4[plx impossible / observe]
    CLI4 --> HZ
  end
Product surfacePrimary cratesTier-1 maturity
Transmutetransmute, puir, project, atlasTypeScript/JS → Rust (weather-api demo)
Mirrormirror, transmuteLinked TS ↔ Rust sync with CI gate
Continuumues, pcir, migrateSame-runtime checkpoint only
Atlasatlas, adapter-sdk120+ detectors; honest maturity
Connectorsconnectors, runtime60+ languages; Ruby/PHP/Go workers experimental
Event HorizonhorizonDynamic/reflection debt analysis

See Atlas adapter index and Horizon.

Migration pipeline

flowchart TD
  A[Source program] --> B[Capture bindings]
  B --> C[PIR document]
  C --> D[Analyze semantic loss]
  D --> E{Policy allows?}
  E -->|no| F[MigrationRejected / Unsupported]
  E -->|yes| G[Convert PIR]
  G --> H[Restore into target worker]
  H --> I[Report timings + findings]
  I --> J[Optional emit / .plx]
  1. Capture — execute source; worker encodes named bindings as PIR JSON
  2. Analyze — classify loss for the target (NONEUNSUPPORTED)
  3. Convert — rewrite PIR under ConversionPolicy
  4. Restore — target worker materializes values
  5. Report — findings + real microsecond timings

Concurrency

RuntimeManager enforces a configurable maximum concurrent adapter operations (default 4). Excess work fails with ResourceLimitExceeded rather than unbounded spawn.

PIR — Parallax Intermediate Representation

Schema version: 1 (PIR_SCHEMA_VERSION)

PIR is a tagged JSON value graph used for capture, snapshots, and migration. It is language-neutral and intentionally boring: dictionaries of typed nodes, not bytecode.

Document shape

{
  "schema": 1,
  "bindings": {
    "state": { "t": "map", "entries": [ /* ... */ ] }
  },
  "objects": {},
  "roots": [],
  "metadata": {}
}
  • bindings — primary migration surface (name → value)
  • objects / roots — reserved for richer heap graphs (ref targets)
  • metadata — free-form; migration fills migrated_from / migrated_to

Value tags

tPayloadNotes
nullNone / null / undefined
boolv: bool
intv: { "decimal": "…" }Arbitrary precision decimal text
floatv: numberIEEE-754 binary64
stringv: stringUTF-8
bytesv: base64
listv: [...]Arrays
tuplev: [...]Becomes list when targeting JS
setv: [...]Becomes list when targeting JS
mapentries: [{key,value}]Ordered; string keys preferred
bigintv: decimal stringFirst-class in JS restore
functionname, descriptorNot migratable
refidObject-graph pointer
unsupportedreason, repr, type_name?Explicit failure node

Example — demo state

{
  "t": "map",
  "entries": [
    { "key": { "t": "string", "v": "username" }, "value": { "t": "string", "v": "Ada" } },
    { "key": { "t": "string", "v": "score" }, "value": { "t": "int", "v": { "decimal": "42" } } },
    {
      "key": { "t": "string", "v": "projects" },
      "value": {
        "t": "list",
        "v": [
          { "t": "string", "v": "compiler" },
          { "t": "string", "v": "runtime" },
          { "t": "string", "v": "vm" }
        ]
      }
    }
  ]
}

Validation

PirDocument::validate rejects unknown/future schema versions and dangling roots. Snapshots additionally hash a canonical payload and reject tampering.

Offline PIR input

plx migrate path/to/doc.json --to javascript --pir-input

Skips live capture; useful for fixtures and fuzz corpora.

Continuum (Phase VI)

Continuum moves beyond value/state PIR exchange toward suspended computation migration:

pause → capture continuation → Universal Execution State → translate → resume

This chapter describes what is implemented today versus what remains experimental or unsupported.

PIR vs UES vs PCIR

ArtifactModelsVersion constant
PIRPortable values / object graphspir_schema
UESSuspended execution (control, frames, heap, capabilities)ues_format
PCIRPortable control-flow subset for supported regionspcir_schema

These versions advance independently (see Versioning). Serialization alone is not migration.

What is real in this milestone

  1. Types + serde for UniversalExecutionState, UniversalFrame, PCIR ops, binary/JSON envelopes, version rejection.
  2. Safepoint model with machine-readable reports (can_capture / snapshot / replay / migrate, targets, semantic loss).
  3. Explicit checkpoint capture in Python and JavaScript workers via parallax.checkpoint(label) (and @parallax.safepoint / parallax.safepoint conceptually).
  4. Same-runtime resume of the post-checkpoint source region with restored bindings (not a full program restart).
  5. MigrationContract analysis before continuation attempts; clear reject reports when unsatisfied.
  6. Continuation capability matrix via CLI.

What is Explicitly Unsupported / Experimental

CapabilityStatus
Arbitrary live stack frame migrationNO — not claimed
Cross-runtime continuation resumeNO (contract-gated)
Deterministic replay engineUNSUPPORTED (journal schema / hooks only)
Async / await / yield migrationNO
WASM continuumNO
Same-runtime checkpoint capture + resumeEXPERIMENTAL

If a path is not truly implemented, Continuum returns structured Unsupported / capability levels (YES / PARTIAL / EXPERIMENTAL / NO) — it never pretends resume worked.

Safepoints

Supported boundary for this pass: explicit checkpoint.

x = 1
parallax.checkpoint("after_init")
x = x + 41  # runs only on resume

At the safepoint the worker reports whether it can capture / snapshot / replay / migrate, candidate targets, and semantic-loss notes.

CLI

# Continuation capability matrix
plx capabilities python --continuations
plx capabilities --continuations --json

# Capture UES at checkpoint (experimental)
plx continuum examples/checkpoint_demo.py -o demo.ues.json --json

# Same-runtime resume after capture
plx continuum examples/checkpoint_demo.py --resume --json

# Inspect a written UES
plx continuum demo.ues.json --inspect-ues

# Contract-only analysis
plx continuum examples/checkpoint_demo.py --analyze-only -t javascript

# Honest continuation migrate mode (rejects cross-runtime)
plx migrate examples/checkpoint_demo.py -t javascript --mode continuation

Value/state PIR migration remains the default:

plx migrate examples/demo.py -t javascript

Migration contracts

Before a live continuation attempt, Parallax builds a MigrationContract describing required surviving semantics (values, locals, control position, stack frames, same-runtime vs cross-runtime resume, …). Analysis runs first; unsatisfied contracts produce a readable reject report.

Crates

  • parallax-pcir — Continuation IR ops / programs
  • parallax-ues — UES, frames, safepoints, deterministic hooks, continuation matrix
  • parallax-migrate::contractMigrationContract + analysis

Migration engine

Implemented in parallax-migrate.

Goals

  • Move data bindings between runtimes through PIR
  • Detect semantic incompatibilities before pretending success
  • Keep policy explicit (ConversionPolicy / CLI flags)
  • Report measured phase timings

Loss taxonomy

LevelMeaningDefault policy
NONEEquivalentAllow
SAFERepresentation differs, semantics preservedAllow
POTENTIALLY_LOSSYDepends on contentsAllow (allow_potentially_lossy)
LOSSYKnown corruption risk (e.g. unsafe int → Number)Reject unless --allow-lossy
UNSUPPORTEDCannot representKeep as Unsupported node (or reject if configured)

Conversion policy knobs

Field / flagDefaultEffect
prefer_bigint / (default on)trueUnsafe ints → PIR bigint for JS
--no-prefer-bigintDisable BigInt promotion
--allow-lossyoffPermit LOSSY coercions
allow_potentially_lossytrueAllow amber findings
reject_unsupportedfalseHard-fail on Unsupported

Phase timings

MigrationReport.timings fields (microseconds):

FieldSource
capture_usLive adapter execution (when used)
analyze_usSemantic walk
convert_usPIR rewrite
restore_usTarget adapter restore
total_usSum of measured phases

Never fabricated — if a phase did not run, the optional field is omitted / zero as documented by the CLI JSON schema.

Typical findings

  • SAFE — tuple/set → JS array; BigInt promotion path
  • LOSSY — integer outside [−2^53+1, 2^53−1] without BigInt preference
  • UNSUPPORTED — functions, host objects without encoders

API surface (library)

#![allow(unused)]
fn main() {
use parallax_migrate::migrate_document;
use parallax_core::{ConversionPolicy, RuntimeKind};

let (pir_out, report) = migrate_document(
    RuntimeKind::Python,
    RuntimeKind::JavaScript,
    &pir_in,
    &ConversionPolicy::default(),
)?;
}

CLI users should prefer plx migrate — it wires capture and restore around this function.

Snapshots (.plx)

Deterministic JSON documents with integrity hashing. Implemented in parallax-snapshot.

Format

FieldDescription
magicMust be PARALLAX_PLX
format_versionSNAPSHOT_FORMAT_VERSION (1)
idUUID
created_atUTC timestamp
runtimeOrigin / target runtime kind
labelOptional
stateExecutionState shell (capabilities, heap JSON, metadata)
pirFull PirDocument
content_hashSHA-256 hex of canonical {format_version, runtime, state, pir}

Loaders reject bad magic, unsupported versions, invalid PIR, and hash mismatches (InvalidSnapshot).

CLI

# Capture
plx snapshot examples/demo.py -o demo.plx --label demo

# Inspect
plx inspect demo.plx
plx inspect demo.plx --json

# Restore into a runtime
plx restore demo.plx --target javascript

During migrate:

plx migrate examples/demo.py --to javascript --snapshot migrated.plx -o migrated.js

What is stored

For the supported binding-capture path, the important payload is pir.bindings. Stack frames, instruction pointers, and async state are typically empty — capabilities say so.

Integrity model

Snapshots are not cryptographic signatures. The content hash detects accidental corruption and casual edits. Treat them like build artifacts: transfer over trusted channels if the binding data is sensitive.

Worker protocol

Versioned NDJSON over stdin/stdout. Implemented in parallax-protocol (PROTOCOL_VERSION = 1).

Envelope

Every line is one JSON object:

{
  "v": 1,
  "id": "<uuid>",
  "op": "execute",
  "ok": true,
  "payload": { },
  "error": null
}
FieldRole
vProtocol version — mismatch → ProtocolViolation
idCorrelation id (request/response)
opOperation name
okPresent on responses
payloadOp-specific JSON
error{ code, message, diagnostic? } on failure

Operations

opDirectionPurpose
helloreq/respNegotiate version; report host/adapter versions
executereq/respRun source; optional capture list → PIR bindings
restorereq/respMaterialize PIR bindings in a fresh context
pingreq/respLiveness
shutdownreq/respWorker exits

Execute request (abbrev.)

{
  "source": "state = {'a': 1}",
  "filename": "demo.py",
  "capture": ["state"],
  "limits": { "timeout": 30000, "max_output_bytes": 1048576 }
}

limits.timeout is milliseconds (serde of ExecutionLimits).

Execute response (abbrev.)

{
  "stdout": "",
  "stderr": "",
  "duration_us": 1234,
  "bindings": { "state": { "t": "map", "entries": [] } },
  "exception": null,
  "success": true
}

Worker locations

Workers are embedded in the adapter crates and materialized under the system temp directory at runtime:

RuntimeEmbedded sourceTemp file
Pythonadapters/python/worker.py%TEMP%/parallax-workers/python_worker.py
JavaScriptadapters/js/worker.js%TEMP%/parallax-workers/js_worker.js

Timeouts

The core wraps each request in tokio::time::timeout. On expiry the worker process is killed and the caller receives ExecutionTimeout.

Versioning

Parallax uses several version numbers that can advance independently. Bumping the product version does not automatically imply a PIR or protocol break, and vice versa.

Inspect live values:

plx version
plx version --format json

Constants live in parallax-core (version.rs):

SurfaceConstantRole
Parallax (product)PARALLAX_VERSIONSemVer from workspace Cargo.toml (0.1.x today). CLI, crates, and release tags.
PIR schemaPIR_SCHEMA_VERSIONLanguage-neutral IR document schema. Loaders reject unsupported schema numbers.
Worker protocolPROTOCOL_VERSIONNDJSON envelope version between host adapters and Python/JS workers.
Snapshot formatSNAPSHOT_FORMAT_VERSION.plx container fields / hashing contract.
Adapter interfaceADAPTER_INTERFACE_VERSIONHost-facing adapter metadata / registration contract.
UES formatUES_FORMAT_VERSIONUniversal Execution State wire format (execution, not values).
PCIR schemaPCIR_SCHEMA_VERSIONContinuation IR schema for supported control regions.
PUIR schemaPUIR_SCHEMA_VERSIONProgram / project IR used by Transmute and Mirror.
Mirror link formatMIRROR_LINK_FORMAT_VERSION.parallax-link/ metadata layout.

As of 0.1.0, these integer surfaces are at 1 unless noted otherwise.

Compatibility expectations

  • Product SemVer (CHANGELOG.md): user-facing CLI and library behavior for the Parallax release line.
  • Integer schema/protocol/format versions: treat a bump as a potential breaking change for that surface. Readers should reject unknown or mismatched versions rather than guessing.
  • Adapters: workers and host crates must agree on PROTOCOL_VERSION. Capability matrices may grow without a protocol bump when messages stay compatible; incompatible message shapes require a protocol bump.
  • Snapshots: plx inspect / restore validate magic, format_version, PIR, and content hash. Older writers are not guaranteed to load in newer readers until migration rules are documented.

When to bump what

ChangeBump
CLI flag, migrate policy default, crate API for usersProduct SemVer (per SemVer once published; pre-1.0 may move faster)
PIR node shapes or document required fieldsPIR_SCHEMA_VERSION
NDJSON request/response envelope or required fieldsPROTOCOL_VERSION
.plx top-level fields or hash canonicalizationSNAPSHOT_FORMAT_VERSION
RuntimeAdapter method/metadata contract across cratesADAPTER_INTERFACE_VERSION
UES document fields / envelopeUES_FORMAT_VERSION
PCIR op set or program schemaPCIR_SCHEMA_VERSION
PUIR item / program schemaPUIR_SCHEMA_VERSION
.parallax-link/ layoutMIRROR_LINK_FORMAT_VERSION

Record product-facing changes in the root CHANGELOG.md. Call out schema/protocol/format bumps explicitly in the same release notes.

Security & limits

Vulnerability reporting, supported versions, and a concise threat-model summary for operators: SECURITY.md in the repository root.

Implemented primarily in parallax-security and enforced by adapters / the runtime manager.

Threat model (0.1)

Parallax assumes developer-trusted guest code on a local or CI machine. It is not a hardened multi-tenant sandbox.

What exists today:

  • Subprocess isolation for Python / JS
  • Wall-clock timeouts
  • Output / message size limits in ExecutionLimits
  • WASM fuel budgets via wasmtime
  • Bounded concurrent workers
  • Explicit capability tokens recorded in state metadata

What does not exist yet:

  • seccomp / Seatbelt / Windows job objects
  • Network namespace isolation
  • Filesystem jails
  • Cryptographic attestation of snapshots

SandboxPolicy

FieldDefaultNotes
limits.timeout30sWall clock
limits.max_output_bytes1 MiBStdio capture budget
limits.max_message_bytes16 MiBProtocol message ceiling
limits.max_memory_bytes256 MiBSoft hint where supported
limits.max_fuel10_000_000WASM
allow_networkfalsePolicy flag (not fully enforced in MVP workers)
allow_fs_readtrueGuests can read files the OS user can read
allow_fs_writefalsePolicy flag
max_concurrent_workers4Manager hard limit

SandboxPolicy::strict() tightens timeouts and memory for experimentation.

Error codes worth knowing

CodeMeaning
CapabilityViolationRequested feature not available
ResourceLimitExceededConcurrency / size / fuel
ExecutionTimeoutDeadline exceeded
AdapterCrashedWorker died unexpectedly
InvalidSnapshotTamper / schema failure

Handling untrusted input

If you must evaluate untrusted code:

  1. Use strict() limits and short timeouts
  2. Run inside an external container / VM
  3. Do not pass secrets into guest globals
  4. Treat .plx files as untrusted data — validate, but do not assume secrecy

Supply chain

CI runs cargo deny / advisory checks when configured (see repository workflows). Pin toolchain via rust-toolchain / Actions dtolnay/rust-toolchain.

Performance

Parallax optimizes for correct, measurable migration, not micro-benchmark theater.

How to measure

# End-to-end averages (real samples)
plx bench --iterations 20 --json

# Single migration with phase breakdown
plx migrate examples/demo.py --to javascript --json

JSON includes per-phase microseconds. Use those — do not invent numbers for blog posts.

Cost model (qualitative)

PhaseDominant cost
CaptureProcess spawn + interpreter startup + encode
Analyze / convertUsually tiny vs spawn for demo-sized graphs
RestoreProcess spawn + decode
WASM executeIn-process; fuel accounting overhead

On warm disks, demo migrations are typically dominated by worker spawn (tens of milliseconds), not PIR walks (tens of microseconds).

Guidance

  • Prefer long-lived workers in future versions if you need lower latency (not in 0.1)
  • Keep captured graphs small — migrate data, not whole heaps
  • Use --pir-input offline fixtures when benchmarking pure analyze/convert
  • Release builds (cargo build --release) matter for CLI overhead

Benchmarks directory

See benchmarks/README.md. Criterion crates can be added later; the supported user-facing tool is plx bench.

Adapters overview

An adapter implements RuntimeAdapter in parallax-runtime:

  • probe — host readiness
  • execute — run a ProgramSource
  • restore — materialize a PirDocument
  • capabilities / metadata — declarations for CLI and snapshots

Atlas (Phase IX) adds a second adapter surface for project migration: language/framework/build/test/ORM/deploy detectors and planners via parallax-adapter-sdk + parallax-atlas. Runtime adapters and Atlas adapters are complementary — see Atlas architecture.

Registration

The CLI registers adapters at startup:

parallax_adapter_python::register_lenient
parallax_adapter_js::register_lenient
parallax_adapter_wasm::register_lenient
parallax_connectors::register_all_lenient   # 60+ language scaffolds

Lenient registration means a missing host binary still registers an adapter that probes UNAVAILABLEplx doctor stays informative.

Scaffold connectors (Go, Java, Ruby, C#, …) register with honest Unsupported execute/restore until a real worker exists. Browse them with plx connectors. See Language connectors.

Program sources

VariantUse
FilePath on disk
InlineSource text + filename hint
CaptureBindingsSource + explicit capture names (used internally by migrate/snapshot)
BytesRaw WASM module bytes

Chapters

Atlas adapter index

Parallax Atlas ships 120+ built-in adapters across languages, frameworks, tooling, and deployment surfaces. Maturity is honest: stable / beta / experimental / scaffold / parse-only.

Browse live inventory:

plx adapters              # grouped by kind
plx adapters --json       # machine-readable
plx adapters info <id>    # manifest + capabilities
plx analyze <path>        # detect stack for a project

Adapter kinds

KindExamplesCLI group
Source / target languageTypeScript, Python, Rust, GoLANGUAGE ADAPTERS / TARGET ADAPTERS
FrameworkExpress, FastAPI, NestJS, Axum, QuarkusFRAMEWORK ADAPTERS
Web frontendReact, Vue, Svelte, AngularWEB FRONTEND
Build systemnpm, Cargo, pnpm, uv, Poetry, sbtBUILD ADAPTERS
Test frameworkJest, Vitest, pytest, cargo testTEST ADAPTERS
Database / ORMPostgreSQL, Prisma, SQLAlchemy, SeaORMDATABASE / ORM ADAPTERS
Deployment / CIDocker, Fly.io, GitHub Actions, LambdaDEPLOYMENT
RuntimeNode, CPython, WASMRUNTIME
CLI frameworkclap, commander, click, typerCLI FRAMEWORKS
Validation / serializationZod, Pydantic, SerdeVALIDATION / SERIALIZATION
FormatterPrettier, rustfmt, Black, Ruff, BiomeFORMATTERS
LinterESLint, Clippy, Ruff, mypy, golangci-lintLINTERS
CodegenOpenAPI/Swagger, Protobuf, GraphQL CodegenCODEGEN
Desktop GUITauri, Electron, WailsDESKTOP GUI
Pair profileTypeScript→Rust, Python→RustPAIR PROFILES

Stack demo fixtures

Under examples/stacks/:

FixtureStack signal
nest-prisma/NestJS + Prisma + Vitest + ESLint/Prettier
fastapi-sqlalchemy/FastAPI + SQLAlchemy + Ruff + mypy
tauri-desktop/Tauri desktop shell + TypeScript
plx analyze examples/stacks/nest-prisma --to rust
plx analyze examples/stacks/fastapi-sqlalchemy --to rust
plx analyze examples/stacks/tauri-desktop

Dependency mappings

Transmute uses DependencyMapDb for npm / PyPI / Maven / Go → multi-target equivalences:

plx mappings express
plx mappings prisma
plx mappings @tauri-apps/api

See Dependencies for confidence scoring and manual-review rules.

Atlas adapter architecture

Parallax Atlas makes language, framework, build, test, database, and deployment support a modular adapter problem — not a core rewrite.

Parallax Core / Transmute / Mirror
│
├── parallax-adapter-sdk   formal contracts
└── parallax-atlas         registry, detection, stack planning
        └── built-in adapters (languages, frameworks, …)

Principles

  1. Core orchestrates — migration planning consumes normalized IR (PUIR, ProjectGraph) produced or planned via adapters.
  2. Capabilities are explicit — never assume an adapter supports a construct because it claims a language.
  3. Composition over hardcoding — TypeScript + NestJS + Prisma + Jest + Docker stack as cooperating adapters with ownership scopes.
  4. Honest maturitystable / beta / experimental / parse_only / target_only / scaffold.
  5. Conflicts are visible — when two adapters of the same kind match, Atlas selects by priority and reports the resolution.

Crates

CrateRole
parallax-adapter-sdkParallaxAdapter trait, manifests, capabilities, detection types
parallax-atlasAdapterRegistry, built-ins, analyze_stack, compatibility, lockfile
parallax-connectorsLanguage identity catalog (roles, host tools) — complementary to Atlas
parallax-transmuteActual TS→Rust (etc.) migration execution

Detection → plan

DISCOVER files/manifests
  → CLASSIFY project kind
  → DETECT adapters
  → RESOLVE conflicts (priority)
  → SUGGEST target stack (--to)
  → ESTIMATE coverage (from maturity + pair tier)

CLI: plx analyze . --to rust

Lockfile

parallax.lock records adapter ids/versions for reproducible migrations (plx analyze . --write-lock).

What Atlas does not claim yet

Scaffold adapters detect ecosystems (Java, Spring, Rails, …) but do not fully migrate them. Tier-1 execution remains TypeScript/JavaScript → Rust (Express→Axum pack) with expanding mappings.

Tooling adapters

Atlas detects formatters, linters, codegen inputs, and desktop GUI shells. These adapters inform stack analysis and dependency mapping — they do not auto-run external tools today.

Formatters (AdapterKind::Formatter)

AdapterDetection signal
Prettierprettier dep, .prettierrc, prettier.config.js
Biome@biomejs/biome, biome.json
rustfmtCargo.toml, rustfmt.toml
Black[tool.black] in pyproject
Ruff format[tool.ruff] + format section
gofmtgo.mod present
dart formatpubspec.yaml, analysis_options.yaml

Linters (AdapterKind::Linter)

AdapterDetection signal
ESLinteslint dep, eslint.config.js, .eslintrc.*
ClippyRust project (Cargo.toml)
Ruff lint[tool.ruff.lint]
Pylintpylint dep
golangci-lint.golangci.yml
RuboCoprubocop gem, .rubocop.yml
mypy[tool.mypy], mypy.ini

Codegen (AdapterKind::Codegen)

AdapterDetection signal
OpenAPI / Swaggeropenapi.yaml, swagger.json, FastAPI, @nestjs/swagger
Protocol Buffers*.proto, prost, tonic, protobuf deps
GraphQL Codegen@graphql-codegen/*, codegen.yml
OpenAPI Generatoropenapitools.json

Mappings example: @nestjs/swaggerutoipa (Axum OpenAPI) with honest confidence.

Desktop GUI (AdapterKind::DesktopGui)

AdapterDetection signal
Tauri@tauri-apps/api, src-tauri/tauri.conf.json
Electronelectron dep, electron-builder.yml
Wailswails.json, Go + frontend bundle

Try the fixture: plx analyze examples/stacks/tauri-desktop.

CLI grouping

plx adapters lists these under FORMATTERS, LINTERS, CODEGEN, and DESKTOP GUI — see Adapter index.

Adapter SDK

Crate: parallax-adapter-sdk

Base trait

#![allow(unused)]
fn main() {
trait ParallaxAdapter {
    fn manifest(&self) -> AdapterManifest;
    fn detect(&self, context: &ProjectContext) -> DetectionResult;
    fn capabilities(&self) -> AdapterCapabilities;
}
}

Specialized markers: SourceLanguageAdapter, TargetLanguageAdapter, FrameworkAdapter, DependencyAdapter, BuildSystemAdapter, TestFrameworkAdapter, DatabaseAdapter, ConfigurationAdapter, DeploymentAdapter, VerificationAdapter.

Manifest

Every adapter exposes AdapterManifest:

  • id — stable (parallax.typescript.source)
  • version — independently versioned with the product today; package distribution later
  • adapter_type — source-language, framework, orm, …
  • languages / ecosystems
  • maturity / conformance (Bronze / Silver / Gold)
  • priority — conflict resolution
  • owns — semantic nodes this adapter transforms
  • permissions — capability sandbox for third-party adapters
  • sdk_versionADAPTER_SDK_VERSION

Capabilities

Machine-readable flags (FULL / PARTIAL / UNSUPPORTED), e.g. TypeScript source:

parsing...................FULL
types.....................FULL
decorators................PARTIAL
dynamic_eval..............UNSUPPORTED

Detection

ProjectContext carries root, relative files, manifests, package names, language mix, and CLI hints (to).

DetectionResult includes confidence, evidence, and optional owns_nodes.

Developing an adapter

  1. Read examples/custom-adapter
  2. Implement ParallaxAdapter (+ specialized trait)
  3. Register via AdapterRegistry::register or ship under .parallax/adapters/ (discovery planned)
  4. Aim for Bronze → Silver → Gold conformance (conformance)

Scaffold command (plx adapter new) is stubbed; use the example tree as the template today.

Source-language adapters

Source adapters normalize into shared semantic structures (functions, types, modules, control flow, async, …) without leaking language-specific ASTs into the planner.

LanguageMaturityNotes
TypeScript / JavaScriptstableTransmute frontend via TS compiler API
PythonbetaExpanding
Go, Java, Kotlin, C#, Ruby, PHPexperimentalDetection + connectors
Swift, Dart, LuascaffoldIdentity / detect
C / C++parse_onlyNo claim of migration

See also Language connectors.

Target-language adapters

Targets consume PUIR + ProjectGraph + MigrationPlan (+ style profile) and own:

  • syntax emission
  • module / file layout
  • error & async conventions
  • package manifests
  • preferred formatter
LanguageMaturity
Ruststable (Tier-1 packs)
Gobeta
Python, TypeScriptexperimental
Java, Kotlin, C#, Ruby, Swift, Dartscaffold

Style profiles (idiomatic / minimal / …) via plx migrate --target-style and future --style.

Framework adapters

Frameworks are first-class Atlas adapters (AdapterKind::Framework).

Built-ins (detection)

AdapterMaturityNotes
ExpressstablePack: → Axum
FastAPIstablePack path → Axum
AxumstableTarget-side
NestJS, Fastify, Flask, Django, Gin, Chi, Hono, Koa, Fiber, Echo, Rocket, LitestarbetaDetection + mapping hints
Spring Boot, ASP.NET, Rails, Laravel, Next.js, Ktor, Vapor, Sanic, Phoenix, SinatraexperimentalDetect only
Quarkus, Micronaut, Symfony, Slim, Beego, BuffaloexperimentalJVM/PHP/Go detection

Web frontends (AdapterKind::WebFrontend)

Compose with backend frameworks (e.g. Express + React). Detection only today:

AdapterMaturity
React, Vue, Svelte, Solid, Angularexperimental

Preferred mappings

Express  → Rust: Axum | Go: Chi | Python: FastAPI
FastAPI  → Rust: Axum | Go: Chi | TypeScript: Fastify

Scores come from dependency knowledge (plx mappings) and stack suggestion (plx analyze --to / plx explain-stack).

Contract (intent)

Framework adapters should eventually:

  • detect presence
  • extract routes / middleware / services
  • map to a target framework via a MigrationPack

Today, Express→Axum remains the implemented Transmute pack; other frameworks contribute detection and planning honesty.

Dependency mappings

Atlas / Transmute share DependencyMapDb (parallax-transmute).

plx mappings
plx mappings axios
plx mappings --json

Mappings are capability-aware candidates, not rename tables:

  • confidence
  • API similarity
  • feature overlap
  • async model
  • maturity notes

Example:

npm:axios → crates.io:reqwest (92%)
npm:express → crates.io:axum (90%), actix-web (85%)
npm:hono → crates.io:axum (85%)
npm:drizzle-orm → sqlx / sea-orm
pypi:litestar → axum
pypi:pydantic → serde + validator
npm:commander → clap

Deploy/CI hints: Fly.io (fly.toml), Railway, Netlify, GitLab CI, CircleCI, AWS Lambda (serverless/SAM/Pulumi hints).

ORM/DB additions: Drizzle, SeaORM, GORM, Eloquent, DynamoDB (detection + mapping candidates where known).

Multi-candidate selection prefers the highest confidence equivalent unless the user overrides (--framework, config — expanding).

Testing adapters

Test-framework adapters detect runners (Jest, Vitest, Mocha, pytest, unittest, cargo test / Criterion, Go testing, JUnit, Kotest, NUnit, XCTest, Dart test, RSpec, PHPUnit, …).

Build-system adapters also cover pnpm, Yarn, Bun, uv, Poetry, CMake, and Meson (manifest/lockfile detection).

Assertion IR (direction)

Future emission uses language-independent AssertionIR (Equal, Throws, Snapshot, …). Vitest/Jest → cargo test is the Tier-1 path used by weather-api.

Mocking

jest.mock, unittest.mock, Mockito, etc. often require manual review when no safe equivalent exists — Atlas reports maturity honestly rather than inventing mocks.

Adapter security

Third-party adapters must not get unrestricted host access.

Permissions (AdapterPermissions)

FlagMeaning
read_projectRead source tree
write_outputWrite generated files
execute_buildRun build/test tools
networkNetwork I/O
read_environmentRead env vars

Built-ins use a fuller permission set. External adapters default to minimal (read_project only) once package loading lands.

Isolation goals

  • Crash isolation (ADAPTER_FAILURE without killing the migration)
  • Timeouts and memory budgets for untrusted adapters
  • Deterministic hooks only

Telemetry from plx adapters report is local-only by default.

Adapter conformance

Levels:

Bronze

  • Parses / detects project
  • Emits valid IR or structured detection
  • Basic fixtures pass

Silver

  • Target compiles for supported packs
  • Tests migrate where claimed
  • Dependency mapping works

Gold

  • Behavioral verification
  • Edge-case suite
  • Incremental sync where applicable
  • High fixture coverage

plx adapters health exposes a heuristic score from maturity + conformance medals. Full fixture-driven scoring expands with parallax-adapter-testkit.

Publishing adapters

Today: adapters ship built-in with Parallax.

Planned distribution:

.parallax/adapters/          project-local
~/.parallax/adapters/        user-installed
package registries           versioned adapter crates / packs

Lockfiles

parallax.lock pins adapter versions for reproducible migrations.

plx analyze . --write-lock
plx adapters update --check

Breaking mapping changes between adapter versions must surface as review-required diagnostics (not silent semantic drift).

Checklist before publishing

  1. Valid adapter.toml / manifest
  2. Capability flags complete
  3. Bronze fixtures green
  4. Permissions minimized
  5. Determinism verified
  6. Document maturity honestly

Language connectors

Parallax catalogs dozens of languages as first-class connectors — not only the four production runtimes.

plx connectors
plx connectors --pairs
plx connectors go
plx connectors --maturity production
plx connectors --family scripting --json

What a connector is

RoleMeaning
RuntimeRuntimeAdapter registered with plx runtimes / doctor
Value migratePIR capture/restore across runtimes
Transmute sourceProject analysis → PUIR
Transmute targetCodegen backend

Production / experimental execute today

ConnectorExecuteValue migrateNotes
pythonYESYESNDJSON worker
javascriptYESYESNDJSON worker
typescriptvia JSAnalyze via tsc API
wasmYESNOwasmtime in-process
rubyYES (experimental)PARTIALNDJSON worker
phpYES (experimental)PARTIALNDJSON worker (when php on PATH)
goEXPERIMENTALNONDJSON worker via go run
plx run examples/demo.rb --runtime ruby --capture state
plx run examples/demo.go --runtime go
plx run examples/demo.php --runtime php --capture state

Maturity (honest)

LevelMeaning
productionReal worker/engine + tests (Python, JavaScript, WASM; TypeScript analyze)
experimentalPartial path (Ruby/PHP/Go workers; Rust Transmute target; reverse sync gated)
scaffoldIdentity registered; host probed; execute/restore return Unsupported
plannedCatalogued for roadmap; same scaffold behavior

Scaffold connectors exist so every serious language has a stable id, extension map, pair matrix row, and contribution hook — not so Parallax pretends to migrate COBOL today.

Families covered

Systems (C, C++, Rust, Go, Zig, …), managed VM (Java, Kotlin, C#, Dart, …), scripting (Ruby, PHP, Perl, Lua, …), functional (Haskell, OCaml, Elixir, Erlang, Clojure, …), mobile (Swift, Objective-C), data science (R, Julia), shell, SQL/GraphQL, smart contracts (Solidity, Move, Cairo), HDL, and more.

See plx connectors for the live table (60+ entries).

Pair highlights

typescript → rust     tier1
python → rust         tier2
typescript → go       tier2
java → rust           scaffold
csharp → rust         scaffold
solidity → rust       scaffold

Full list: plx connectors --pairs.

Contributing a real adapter

  1. Pick a scaffold id from the catalog (plx connectors <id>).
  2. Add adapters/<id>/ worker speaking the NDJSON protocol or an in-process engine.
  3. Raise maturity only when execute/capture/restore (as claimed) have tests.
  4. Follow Adapters overview — never claim YES for unsupported ops.

Dedicated crates remain for production: parallax-adapter-python, parallax-adapter-js, parallax-adapter-wasm. The catalog lives in parallax-connectors.

Python adapter

Crate: parallax-adapter-python
Worker: adapters/python/worker.py

Host discovery

Order:

  1. python
  2. python3
  3. py
  4. %LOCALAPPDATA%\Programs\Python\*\python.exe
  5. %ProgramFiles%\Python\*\python.exe (and x86)

Candidates that fail python -c "import sys; print(...)" or look like the Windows Store stub are skipped.

Execution model

  • Subprocess: python worker.py
  • Guest code runs via compile + exec into a dedicated globals dict
  • Stdout/stderr of the guest are captured separately from the NDJSON control channel
  • Named bindings are encoded with the PIR tagged JSON shapes

Supported value subset (encode)

PythonPIR
Nonenull
boolbool
intint (decimal string)
floatfloat
strstring
bytesbytes
listlist
tupletuple
setset
dictmap
callablesfunction
otherunsupported

Restore

PIR → Python values for the supported subset. bigint becomes int. Functions / unsupported nodes raise RESTORE_FAILURE.

Limitations

  • No true local-frame capture beyond post-exec globals
  • No continuation / async migration
  • Guest print is captured; it does not break the protocol channel

JavaScript adapter

Crate: parallax-adapter-js
Worker: adapters/js/worker.js

Host discovery

Order:

  1. node
  2. nodejs
  3. %ProgramFiles%\nodejs\node.exe

Execution model

  • Subprocess: node worker.js
  • Guest code runs in vm.Script / vm.createContext
  • Capture works for top-level let / const / var by appending a final expression that reads names from script scope
  • console.log / error / warn are redirected into captured stdout/stderr buffers

Supported value subset (encode)

JavaScriptPIR
null / undefinednull
booleanbool
safe integer numberint
other numberfloat
bigintbigint
stringstring
Buffer / Uint8Arraybytes
Arraylist
Setset
plain object / Mapmap
functionfunction
otherunsupported

Restore

  • PIR int within the safe integer range → number
  • Larger ints / bigint → JS BigInt
  • map with string keys → plain object
  • list / tuple / setArray (set semantics not reified as Set today)

Limitations

  • No DOM / browser engine — Node.js only in 0.1
  • No async migration
  • Module import / ESM loader hooks are not provided inside the vm context

WebAssembly adapter

Crate: parallax-adapter-wasm
Engine: wasmtime (in-process)

What works

  • Load .wasm bytes or .wat text (wasmtime wat feature)
  • Instantiate with fuel enabled
  • Call a zero-argument exported function (default name: run)
  • Return numeric results as JSON in ExecutionResult.value
plx run examples/hello.wat --entry run
# runtime: wasm  success: true  value: [42]

What does not work

FeatureStatus
Binding captureUnsupported
PIR restoreUnsupported (UnsupportedValue)
Cross-runtime migrateUnsupported
Host imports / WASINot wired in 0.1
Multi-arg entrypointsRejected with a clear error

Limits

Fuel comes from SandboxPolicy.limits.max_fuel / request limits (default 10M). Traps surface as ExecutionFailure.

Why include WASM now?

To prove the adapter interface and fuel-limited execution path. State migration remains a Python/JS concern until a deliberate WASM value ABI exists.

Contributing

Thanks for helping build Parallax.

Canonical short guide (setup commands, DCO note, PR norms):
CONTRIBUTING.md in the repository root.

Also see the Code of Conduct, Security policy, and Privacy policy.

Development setup

git clone https://github.com/parallax-runtime/parallax.git
cd parallax
cargo build --workspace
cargo test --workspace
cargo run -p parallax-cli --bin plx -- doctor

Prerequisites: Rust 1.75+, Node.js 18+ (JS adapter), Python 3.10+ (Python adapter).

Docs site

cd docs
mdbook serve --open
# http://localhost:3000

Build static site:

mdbook build
# output: docs/book/

Requires mdBook (cargo install mdbook).

Project norms

  • No fake capabilities — return Unsupported / structured errors
  • Prefer small, focused PRs
  • Use conventional commits: feat:, fix:, docs:, chore:, test:, ci:
  • Keep README and docs synchronized with real CLI behavior
  • Add tests for migration / PIR / snapshot critical paths
  • Update CHANGELOG.md for user-visible changes
  • Bump the correct versioning surface when you break PIR, protocol, snapshots, or adapter contracts

Adapter conformance

See root CONTRIBUTING.md and Adapters overview. In short: honest capabilities, versioned protocol, structured errors, lenient probe/registration, tests for paths you touch.

Code layout

See Architecture. Adapters live under crates/parallax-adapter-* with worker scripts in adapters/.

Checks before opening a PR

cargo fmt --all
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cd docs && mdbook build

CI runs these on Linux, Windows, and macOS (plus docs + audit jobs).

License

Contributions are accepted under the Apache-2.0 license. No CLA is required at this time; see the root contributing guide for the lightweight DCO note.

Changelog

User-facing changes are recorded in the repository root:

CHANGELOG.md

The project follows Keep a Changelog and Semantic Versioning for the Parallax product line. Independently versioned surfaces (PIR schema, protocol, snapshot format, adapter interface) are described in Versioning.

Snapshot of 0.1.0

Initial public workspace. Highlights:

  • Rust workspace: core, PIR, protocol, security, diagnostics, snapshot, migrate, runtime, adapters, CLI
  • Python and JavaScript NDJSON workers with execute / capture / restore
  • WASM execution via wasmtime (zero-arg exports, fuel); no binding migration
  • plx migrate Python ↔ JavaScript with semantic-loss analysis
  • .plx snapshots with content hashing
  • plx doctor, runtimes, capabilities, bench, --json
  • mdBook site and GitHub Actions CI / Pages / release scaffolding

Limitations: Limitations.

Privacy

Parallax is a local CLI/runtime. The project privacy policy lives in the repository root:

PRIVACY.md

Highlights for operators:

  • No telemetry or analytics by default in this workspace
  • Source, PIR, and .plx snapshots remain under your control
  • Snapshots may contain sensitive bindings — treat them like unencrypted artifacts
  • Guest programs you run can still use the network/filesystem as your OS user allows

Security reporting: SECURITY.md · Security & limits.