{"id":16538354,"url":"https://github.com/japgolly/tla2json","last_synced_at":"2025-10-28T14:31:07.542Z","repository":{"id":49762171,"uuid":"319865691","full_name":"japgolly/tla2json","owner":"japgolly","description":"Convert TLA+ output (and values) into JSON","archived":false,"fork":false,"pushed_at":"2021-03-03T00:22:36.000Z","size":90,"stargazers_count":21,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2023-06-30T18:05:27.279Z","etag":null,"topics":["json","tla","tla-plus","tlaplus","tlc"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/japgolly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"patreon":"japgolly"}},"created_at":"2020-12-09T06:37:47.000Z","updated_at":"2023-06-30T18:05:27.280Z","dependencies_parsed_at":"2022-08-26T09:41:08.380Z","dependency_job_id":null,"html_url":"https://github.com/japgolly/tla2json","commit_stats":null,"previous_names":[],"tags_count":2,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japgolly%2Ftla2json","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japgolly%2Ftla2json/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japgolly%2Ftla2json/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japgolly%2Ftla2json/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/japgolly","download_url":"https://codeload.github.com/japgolly/tla2json/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219859515,"owners_count":16556036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","tla","tla-plus","tlaplus","tlc"],"created_at":"2024-10-11T18:45:12.505Z","updated_at":"2025-10-28T14:31:02.210Z","avatar_url":"https://github.com/japgolly.png","language":"Scala","funding_links":["https://patreon.com/japgolly","https://www.patreon.com/japgolly)!"],"categories":[],"sub_categories":[],"readme":"# tla2json: Convert TLA+ output to JSON\n\n```\ntla2json v1.0.1\n\nUsage: tla2json [options] [\u003cinput file\u003e]\n\n  -D, --dump            Parse input as a dump\n  -T, --trace           Parse input as a trace (default)\n  -S, --state           Parse input as a state\n  -V, --value           Parse input as a value\n  -d, --diff            Convert a full trace into a diff-trace\n  -f, --full            Convert a diff-trace back into a full trace\n  -l, --full-last-step  Convert the last step of a diff-trace back into a full trace\n  -i, --indent          Indent and pretty-print JSON output\n  -s, --sort            Output the fields of each object with the keys in sorted order\n  \u003cinput file\u003e          File to parse\n```\n\n## Why/how is this useful?\n\nThe simplest and most common example is you checking your (non-trivial) model\nand TLC finds a counter-example. Trying to make sense of a trace with many steps and/or\na large state space is immensely time-consuming and difficult. By converting the trace\nto a widely-used format such as JSON, you can easily transform and/or query the data using\nubiquitous tools like [`jq`](https://stedolan.github.io/jq/), and get a sense of your data much faster.\n\nA personal anecdote is me spending over 10 minutes trying to comprehend hundreds of lines of\nTLA+ state, vs looking at a summary as a single-page table and comprehending the situation in under 10 seconds.\n\n### Example 1: A concise summary\n\nInstead of trying to read [something like this](https://gist.github.com/japgolly/19ee59f884bc13cefa9401b1f57c49cc),\nusing `tla2json`, `jq` and `column` can pretty easily turn it into a concise table like this:\n\n```\n\u003e tla2json -s output.log | jq -rf summary.jq | column -t -s$'\\t'\n\n#   Step                       Target        Remote  Tabs                     Workers            Network\n=   ====                       ======        ======  ====                     =======            =======\n1   Initial predicate          []            []      {t1:-, t2:-}             {w1:-, w2:-}       []                                                          \n2   TabNew                     -             -       {t1:[], t2:-}            {w1:[], w2:-}      -                                                           \n3   TabLoad                    -             -       {t1:[], t2:-}            -                  -                                                           \n4   TabNew                     -             -       {t1:[], t2:[]}           -                  -                                                           \n5   TabLoad                    -             -       {t1:[], t2:[]}           -                  -                                                           \n6   TabStart                   -             -       {t1:-, t2:[]}            -                  -                                                           \n7   TabStart                   -             -       {t1:-, t2:-}             -                  -                                                           \n8   UserEditClean              []→{t1:e1}    -       {t1:[], t2:-}            -                  -                                                           \n9   UserAbort                  []→{t1:e1d}   -       {t1:[]A, t2:-}           -                  -                                                           \n10  TabSendChangesToWorker     -             -       {t1:[]A, t2:-}           -                  [sync(t1→w1):[]+]                                           \n11  WorkerRecvChanges          []←{t1:1.1d}  -       -                        {w1:[1.1], w2:-}   [sync(w1→t1):[1.1]+, sync(w1→t2):[1.1]]                     \n12  TabRecvDraftsFromWorker    -             -       {t1:[]A, t2:[1.1]}       -                  [sync(w1→t1):[1.1]+]                                        \n13  TabRecvDraftsFromWorker    [1.1d]        -       {t1:-[1.1d], t2:[1.1]}   -                  []                                                          \n14  TabSendTombstonesToWorker  -             -       {t1:-, t2:[1.1]}         -                  [sync(t1→w1):[1.1d]]                                        \n15  WorkerSendRemoteStoreCmd   -             -       -                        {w1:[1.1], w2:-}   [rcmd(w1→t2):[1.1], sync(t1→w1):[1.1d]]                     \n16  TabRecvRemoteStoreCmd      -             -       -                        -                  [sync(t1→w1):[1.1d], sync(t2→R):[1.1]]                      \n17  RemoteRecvDrafts           -             [1.1]   -                        -                  [sync(R→t1):[1.1], sync(t1→w1):[1.1d]]                      \n18  WorkerRecvChanges          -             -       -                        {w1:[1.1d], w2:-}  [sync(R→t1):[1.1], sync(w1→t1):[1.1d], sync(w1→t2):[1.1d]]  \n19  TabRecvDraftsFromWorker    -             -       {t1:-, t2:[1.1d]}        -                  [sync(R→t1):[1.1], sync(w1→t1):[1.1d]]                      \n20  TabRecvDraftsFromWorker    -             -       {t1:-[1.1d], t2:[1.1d]}  -                  [sync(R→t1):[1.1]]                                          \n21  TabRecvRemoteAck           -             -       -                        -                  [sync(R→t1):[1.1]]                                          \n22  TabSendTombstonesToWorker  -             -       {t1:-, t2:[1.1d]}        -                  [sync(R→t1):[1.1], sync(t1→w1):[1.1d]]                      \n23  WorkerRecvChanges          -             -       -                        -                  [sync(R→t1):[1.1]]                                          \n24  WorkerRecvRemoteAck        -             -       -                        {w1:[1.1d], w2:-}  [sync(R→t1):[1.1]]                                          \n25  WorkerSendRemoteStoreCmd   -             -       -                        {w1:[1.1d], w2:-}  [rcmd(w1→t1):[1.1d], sync(R→t1):[1.1]]                      \n26  TabRecvRemoteStoreCmd      -             -       -                        -                  [sync(R→t1):[1.1], sync(t1→R):[1.1d]]                       \n27  RemoteRecvDrafts           -             [1.1d]  -                        -                  [sync(R→t1):[1.1], sync(R→t2):[1.1d]]                       \n28  TabRecvDraftsFromRemote    -             -       {t1:[1.1], t2:[1.1d]}    -                  [sync(R→t2):[1.1d], sync(t1→w1):[1.1]]                      \n29  TabRecvDraftsFromRemote    -             -       -                        -                  [sync(t1→w1):[1.1], sync(t2→w1):[1.1d]]                     \n30  TabRecvRemoteAck           -             -       -                        -                  [sync(t1→w1):[1.1], sync(t2→w1):[1.1d]]                     \n31  WorkerRecvChanges          -             -       -                        {w1:[1.1d], w2:-}  [sync(t2→w1):[1.1d]]                                        \n32  WorkerRecvChanges          -             -       -                        -                  […]                                                         \n33  WorkerRecvRemoteAck        -             -       -                        {w1:[], w2:-}      []                                                          \n34  WorkerSendRemoteStoreCmd   [1.1d]        [1.1d]  {t1:[1.1], t2:[1.1d]}    {w1:[], w2:-}      []                                                          \n```\n\n*(It doesn't look great in this width-contrained README but it's made for my wider terminal.)*\n\nObviously this is only concise and quickly-comprehensible to me because I understand the domain of my spec.\nYou have to write your own `jq` transformations that make sense for your spec.\nThere's no one-size-fits-all way to summarise your state, but now you have the tools.\n\n### Example 2: Querying your data\n\nTaking the above example, let's say I'm only interested in knowing how the `.tabs[*].status`\nvalues change. No problem! I'll write a new `jq` transformation on the fly to extract this data.\n\nI'll even pass a `-f` flag to `tla2json` to convert my diff-trace into a full trace (so that\neven if the `tabs` state didn't change on a step, it still shows me what the state is).\n\n```\n\u003e tla2json -f \u003coutput.log | jq -c '.[] | {no, tabs: [.state.tabs[].status]}'\n\n{\"no\":1,\"tabs\":[\"-\",\"-\"]}\n{\"no\":2,\"tabs\":[\"loading\",\"-\"]}\n{\"no\":3,\"tabs\":[\"loading\",\"-\"]}\n{\"no\":4,\"tabs\":[\"loading\",\"loading\"]}\n{\"no\":5,\"tabs\":[\"loading\",\"loading\"]}\n{\"no\":6,\"tabs\":[\"clean\",\"loading\"]}\n{\"no\":7,\"tabs\":[\"clean\",\"clean\"]}\n{\"no\":8,\"tabs\":[\"dirty\",\"clean\"]}\n{\"no\":9,\"tabs\":[\"dirty\",\"clean\"]}\n{\"no\":10,\"tabs\":[\"dirty\",\"clean\"]}\n{\"no\":11,\"tabs\":[\"dirty\",\"clean\"]}\n{\"no\":12,\"tabs\":[\"dirty\",\"dirty\"]}\n{\"no\":13,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":14,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":15,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":16,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":17,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":18,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":19,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":20,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":21,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":22,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":23,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":24,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":25,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":26,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":27,\"tabs\":[\"clean\",\"dirty\"]}\n{\"no\":28,\"tabs\":[\"dirty\",\"dirty\"]}\n{\"no\":29,\"tabs\":[\"dirty\",\"dirty\"]}\n{\"no\":30,\"tabs\":[\"dirty\",\"dirty\"]}\n{\"no\":31,\"tabs\":[\"dirty\",\"dirty\"]}\n{\"no\":32,\"tabs\":[\"dirty\",\"dirty\"]}\n{\"no\":33,\"tabs\":[\"dirty\",\"dirty\"]}\n{\"no\":34,\"tabs\":[\"dirty\",\"dirty\"]}\n```\n\n## Installation\n\n* Arch Linux: `tla2json` is in the [AUR](https://aur.archlinux.org/packages/tla2json/)\n\n    ```sh\n    yay -S tla2json\n    tla2json --help\n    ```\n\n* Everything else:\n\n    ```sh\n    ver=1.0.1\n    wget https://github.com/japgolly/tla2json/releases/download/v$ver/tla2json-$ver.jar -O tla2json.jar\n    java -jar tla2json.jar --help\n    ```\n\n\n## Support\n\nIf you like what I do\n—my OSS libraries, my contributions to other OSS libs, [my programming blog](https://japgolly.blogspot.com)—\nand you'd like to support me, more content, more lib maintenance, [please become a patron](https://www.patreon.com/japgolly)!\nI do all my OSS work unpaid so showing your support will make a big difference.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjapgolly%2Ftla2json","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjapgolly%2Ftla2json","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjapgolly%2Ftla2json/lists"}