[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-105446":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":17,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":18,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":21,"hasPages":21,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":27,"readmeContent":28,"aiSummary":10,"trendingCount":16,"starSnapshotCount":16,"syncStatus":15,"lastSyncTime":29,"discoverSource":30},105446,"tla-ts","aidenybai\u002Ftla-ts","aidenybai","A TLA+ interpreter and model checker in TypeScript","https:\u002F\u002Ftla-ts.aidenybai.com\u002F",null,"TypeScript",115,6,53,2,0,46,138,83.14,"MIT License",false,"main",[24,25,26],"formal-verification","tlaplus","typescript","2026-11-01 00:16:58","# tla-ts\n\n[![version](https:\u002F\u002Fimg.shields.io\u002Fnpm\u002Fv\u002Ftla-ts?style=flat&colorA=000000&colorB=000000)](https:\u002F\u002Fnpmjs.com\u002Fpackage\u002Ftla-ts)\n[![downloads](https:\u002F\u002Fimg.shields.io\u002Fnpm\u002Fdt\u002Ftla-ts.svg?style=flat&colorA=000000&colorB=000000)](https:\u002F\u002Fnpmjs.com\u002Fpackage\u002Ftla-ts)\n\ntla-ts is a drop-in replacement for [TLC](https:\u002F\u002Fgithub.com\u002Ftlaplus\u002Ftlaplus) that's **2× faster**.\n\nTLA+ lets you write formal models of a system, and TLC model checks them. But TLC is written in Java and needs the JVM. tla-ts runs anywhere JavaScript runs, such as the browser, Node, and Bun. Try it in the [playground](https:\u002F\u002Ftla-ts.aidenybai.com).\n\n```ts\nimport { check } from \"tla-ts\";\n\nconst result = await check({\n  source: `---- MODULE Counter ----\nEXTENDS Naturals\nVARIABLE x\nInit == x = 0\nNext == x' = x + 1\nSmall == x \u003C 3\n====`,\n  config: \"INIT Init NEXT Next INVARIANT Small\",\n});\n\nresult.status; \u002F\u002F \"invariant-violation\"\n```\n\n## Install\n\n```shell\nnpm install tla-ts\n```\n\n## Command line\n\nThe `tla-ts` command takes TLC's options and prints TLC's output. `tla-ts prove` takes tlapm's options and prints tlapm's output.\n\n### Check a spec\n\nTo check a spec, pass its path:\n\n```shell\nnpx tla-ts Spec.tla\n```\n\ntla-ts reads the configuration from `Spec.cfg` next to the spec. It exits with the exit code TLC uses for the same result.\n\nYou can pass several paths, or a glob such as `\"specs\u002F*.tla\"`. tla-ts checks each spec in turn and exits with the exit code of the first spec that fails. A glob skips each module that has no `.cfg` next to it, so it doesn't check helper modules that other specs import. tla-ts never skips a path that you pass by name. If you pass a `.cfg` path, tla-ts checks the `.tla` file with the same name.\n\nThe options are:\n\n- `-config \u003CSpec.cfg>`: read the configuration from this file. You can use it only when you check one spec.\n- `-deadlock`: don't report deadlocks.\n- `-dump [dot[,colorize][,actionlabels][,snapshot]] \u003Cfile>`: write every reachable state to `\u003Cfile>.dump`, or with `dot`, the state graph to `\u003Cfile>.dot`. The output matches TLC run with `-fp 0`. tla-ts doesn't support the `constrained`, `stuttering`, or `strict` formats.\n- `-lncheck final`: check liveness once, after the search ends.\n- `-seed \u003Cnum>`: seed `RandomElement` and the `Randomization` module. The default is 0.\n- `-workers \u003Ccount|auto>`: search with this number of worker threads. `auto` uses one thread per core. The default is 1.\n\nTLC can replace a module's operators with Java methods, and tla-ts reads the same files. If the spec's directory has `Module.class`, tla-ts replaces each operator in `Module` with the public static method that has the same name and arity.\n\n### Generate proof obligations\n\nA proof obligation is one claim that a backend prover must prove. `tla-ts prove -N` prints the obligations of a module, as `tlapm -N` does. It doesn't run a prover. For example, this command prints every obligation in `Module.tla` with its text:\n\n```shell\nnpx tla-ts prove -N --toolbox 0 0 --printallobs Module.tla\n```\n\nWith `--toolbox` or `--line`, tla-ts writes the messages of the TLA+ Toolbox protocol to stderr, as tlapm does. If you pass a tlapm option that isn't in this list, tla-ts prints an error:\n\n- `--toolbox \u003Cstart> \u003Cend>`: print Toolbox messages for the proofs from line `start` to line `end`. `0 0` selects the whole module.\n- `--line \u003Cnum>`: print Toolbox messages for the proof at this line.\n- `--printallobs`: print the text of each obligation.\n- `--summary`: print the number of obligations in each module, and list its missing and omitted proofs. You don't need `-N` with `--summary`.\n- `--strict`: report missing proofs, omitted proofs and a selected range with no obligations as errors.\n- `-I \u003Cdirectory>`: search this directory for modules.\n\ntla-ts searches for modules in the same order as tlapm:\n\n1. The directory of each module you pass, the last one first.\n2. The current directory.\n3. The standard library of tlapm, which has the `TLAPS` module. tla-ts searches it only if `tlapm` is on your `PATH`.\n4. The `-I` directories, the last one first.\n\n### Prove with tlapm\n\ntla-ts doesn't include a prover. Without `-N` or `--summary`, `tla-ts prove` runs [tlapm](https:\u002F\u002Fgithub.com\u002Ftlaplus\u002Ftlapm) from your `PATH`:\n\n```shell\nnpx tla-ts prove Module.tla\n```\n\ntla-ts expands the globs and passes every argument to tlapm, so all of tlapm's options work. tlapm sends the obligations to its provers, and tla-ts exits with the exit code of tlapm. If `tlapm` isn't on your `PATH`, tla-ts prints an error and exits with code 1.\n\n## API reference\n\n### `check`\n\nChecks a spec against a TLC configuration and resolves to the result.\n\n```ts\nimport { check } from \"tla-ts\";\n\nconst result = await check({\n  source: specSource,\n  config: configSource,\n  loadModule: (name) => modules[name],\n  onPrint: (text) => console.log(text),\n});\n```\n\n| Option                  | Description                                                                              |\n| ----------------------- | ---------------------------------------------------------------------------------------- |\n| `source`                | The TLA+ module to check                                                                 |\n| `config`                | A TLC configuration, as text or as the result of `parseConfig`                           |\n| `loadModule`            | Returns the source of a module that isn't a standard module                              |\n| `loadClass`             | Returns a compiled Java class that overrides a module's operators with constants         |\n| `onPrint`               | Receives the output of `Print` and `PrintT`. Defaults to `console.log`                   |\n| `onPause`               | Runs when `TLCSet(\"pause\", TRUE)` pauses checking, which resumes when it returns         |\n| `readFile`, `writeFile` | Read and write files for the Json module and `dump`                                      |\n| `seed`                  | A `bigint` seed. Defaults to `0n`, and matches TLC run with the same `-seed` and `-fp 0` |\n| `workers`               | The number of worker threads. Defaults to 1                                              |\n| `dump`                  | Writes the reachable states or the state graph, as TLC's `-dump` does                    |\n\n`dump` takes the `path` that `check` passes to `writeFile` before it returns. Set `dot` to write the state graph in the DOT language of Graphviz, and `colorize`, `actionLabels`, or `snapshot` for TLC's formats of the same names. A dump checks the spec on the calling thread, as one TLC worker does.\n\nThe result has these fields:\n\n- `status`: `\"success\"`, `\"deadlock\"`, `\"assumption-violation\"`, `\"invariant-violation\"`, `\"property-violation\"`, `\"liveness-violation\"`, `\"postcondition-violation\"`, or `\"error\"`.\n- `violation`: the `name` of what failed and the `trace` that reaches it. `loopStart` marks where a liveness counterexample loops back.\n- `failure`: the message and trace when `status` is `\"error\"`.\n- `generatedStates`, `distinctStates`, and `depth`: TLC's state counts.\n\nWorkers run in Node, Bun, Deno, and cross-origin isolated pages in the browser. Like TLC's workers, they share one table of 64-bit fingerprints. `check` runs on the calling thread in these cases:\n\n- `SharedArrayBuffer` is unavailable, as on a page without cross-origin isolation.\n- The spec has liveness properties.\n- The spec uses impure operators such as `Print`.\n- The configuration has `VIEW`, `POSTCONDITION`, or `_POSSIBLE`.\n\nAfter a violation or an error, `check` reruns on the calling thread to return TLC's exact trace.\n\n`check` supports:\n\n- **Modules**: the standard modules, TLCExt, Json, and Randomization, plus `EXTENDS`, `INSTANCE`, and `LAMBDA`.\n- **Configuration**: `CONSTANTS`, `INIT`, `NEXT`, `SPECIFICATION`, invariants, properties, constraints, `SYMMETRY`, `VIEW`, `ALIAS`, `POSTCONDITION`, `CHECK_DEADLOCK`, and `_POSSIBLE`.\n- **Properties**: invariants and every temporal formula TLC accepts, checked through TLC's tableau construction.\n- **TLC semantics**: 32-bit integer overflow, `TLCGet` and `TLCSet`, subexpression references such as `Op!2`, and TLC's enumeration order for `CHOOSE` and quantifiers.\n\n### `parseModule`\n\nParses a TLA+ module into its syntax tree. Throws `TlaSyntaxError` on invalid input.\n\n```ts\nimport { parseModule } from \"tla-ts\";\n\nconst module = parseModule(specSource);\nmodule.name; \u002F\u002F \"Counter\"\n```\n\n### `parseConfig`\n\nParses a TLC configuration file into a `ModelConfig`. Pass the result to `check` to change it before checking.\n\n```ts\nimport { check, parseConfig } from \"tla-ts\";\n\nconst config = parseConfig(configSource);\nconfig.checkDeadlock = false;\nawait check({ source: specSource, config });\n```\n\n### `formatValue`\n\nPrints a value in TLA+ syntax, as TLC prints it in traces.\n\n```ts\nimport { formatValue } from \"tla-ts\";\n\nresult.violation?.trace.forEach((step) => {\n  Object.entries(step.state).forEach(([name, value]) => console.log(name, formatValue(value)));\n});\n```\n\n### Errors\n\nEvery error extends `TlaError`:\n\n- `TlaSyntaxError`: the module does not parse\n- `TlaConfigError`: the configuration is invalid or refers to an unknown name\n- `TlaEvaluationError`: evaluation failed, as when TLC reports an error\n- `TlaUnsupportedError`: the spec uses a feature tla-ts does not support yet\n\n## Benchmarks\n\nWall time on one worker, including JVM and Node startup. Both checkers report the same state counts on every model.\n\n| Spec                                                           | Distinct states |     TLC |  tla-ts | Speedup |\n| -------------------------------------------------------------- | --------------: | ------: | ------: | ------: |\n| [Two-phase commit](packages\u002Ftla-ts\u002Fbenchmarks\u002Fcommit)          |         282,251 |  4.32 s |  2.01 s |    2.2× |\n| [Dining philosophers](packages\u002Ftla-ts\u002Fbenchmarks\u002Fphilosophers) |         128,889 |  1.06 s |  0.71 s |    1.5× |\n| [Bounded queue](packages\u002Ftla-ts\u002Fbenchmarks\u002Fqueue)              |          44,044 |  0.37 s |  0.17 s |    2.2× |\n| 542 conformance models                                         |                 | 986.6 s | 403.3 s |    2.4× |\n\nWall time on 8 workers, also including startup. Each time is the median of 3 runs on an Apple M4 Pro.\n\n| Spec                                                                                                                  | Distinct states |     TLC | tla-ts | Speedup |\n| --------------------------------------------------------------------------------------------------------------------- | --------------: | ------: | -----: | ------: |\n| [Raft with reconfiguration](https:\u002F\u002Fgithub.com\u002Fwill62794\u002Ftla-web\u002Fblob\u002F8193eb0\u002Fspecs\u002FRaftWithReconfigSingleServer.tla) |         298,493 | 10.50 s | 8.96 s |    1.2× |\n| [Sailfish](https:\u002F\u002Fgithub.com\u002Ftlaplus\u002FExamples\u002Ftree\u002F0cab2b3\u002Fspecifications\u002Fdag-consensus)                             |         109,604 |  4.34 s | 4.07 s |    1.1× |\n| [Fast Paxos](https:\u002F\u002Fgithub.com\u002Ftlaplus\u002FExamples\u002Ftree\u002F0cab2b3\u002Fspecifications\u002FSimplifiedFastPaxos)                     |          25,617 |  3.91 s | 2.57 s |    1.5× |\n| [Buffered random access file](https:\u002F\u002Fgithub.com\u002Ftlaplus\u002FExamples\u002Ftree\u002F0cab2b3\u002Fspecifications\u002Fbraf)                   |           3,316 |  4.70 s | 3.61 s |    1.3× |\n\n## Development\n\n```shell\npnpm install\npnpm test\npnpm dev\n```\n\n`pnpm dev` starts the playground in `packages\u002Fwebsite`.\n\nRun the conformance suite against TLC's recorded results:\n\n```shell\npnpm --filter tla-ts conformance:fetch\npnpm --filter tla-ts conformance\n```\n\nRerun the benchmarks with `TLA2TOOLS_JAR` set to the path of `tla2tools.jar`:\n\n```shell\npnpm --filter tla-ts bench\npnpm --filter tla-ts bench:corpus\n```\n\n## License\n\nMIT\n","2026-10-31 04:26:48","CREATED_QUERY"]