DEV Community

Cover image for Pluto-ecss: A transpiler and runtime for PLUTO procedure language
Sokratis Tzifkas
Sokratis Tzifkas

Posted on

Pluto-ecss: A transpiler and runtime for PLUTO procedure language

GitHub “Finish-Up-A-Thon” Challenge Submission

This is a submission for the GitHub Finish-Up-A-Thon Challenge

What I Built

pluto-ecss is a transpiler and
runtime for PLUTO — the procedure language standardised by ECSS
(ECSS-E-ST-70-32C)
for spacecraft testing and operations. It's the DSL ground operators write to
bring up a star tracker, run a parallel safety sequence, or react to an on-board
event.

You hand it a PLUTO procedure and it gives you back readable, runnable Python
— plus a small runtime library, a CLI, a live TUI, and a browser playground.

$ pluto-ecss run examples/01_original.pluto
[ACTIVITY] Switch on Star Tracker2
[ACTIVITY] Switch on Reaction Wheel3 of AOC of Satellite
[ACTIVITY] Switch on Star Tracker1
Enter fullscreen mode Exit fullscreen mode

It started life in 2019 as a Google Summer of Code work product: a sample
parser that built a tree from one hard-coded script and "ran" it by walking the
tree. It never grew past that one file, and it sat dormant for nearly seven
years. Finishing it means closing a loop I'd quietly written off — turning a
"sample for a proposal" into something you can actually pip install and use.

Demo

A friendly parse error

A compiled output

The TUI demo (pluto-ecss demo SCRIPT) lights up a fake satellite as the
procedure executes:

╭──────────────── Procedure: 05_full_bringup.pluto ────────────────╮
│                            EXECUTING                             │
╰──────────────────────────────────────────────────────────────────╯
                     🛰  Satellite (AOC subsystem)
  Component             │        Status
  ─────────────────────┼─────────────────
  Reaction Wheel3       │          ON
  Star Tracker1         │          ON
  Star Tracker2         │          OFF
📡 Activity feed: ▶ Switch on Reaction Wheel3 …   ⚡ Events: declared: boom
Enter fullscreen mode Exit fullscreen mode

The Comeback Story

Before — the 2019 GSoC snapshot (still browsable on the
legacy/gsoc-2019
branch): two .py files, a ~30-line grammar covering five constructs, a
tree-walking interpreter tangled into the parser, zero tests, no CLI, no
packaging — and real bugs (setExecutionSatus typo, super.__init__ with no
parens, types never imported). It ran exactly one script and NameError'd on
anything else.

After — main today: a proper transpiler (PLUTO → parse tree → readable
Python), a standalone runtime, and a real toolchain.

2019 2026
Grammar ~30 lines 168 lines
Tests 0 164 passing
Examples 1 16
Package LOC ~600 ~3,600
CLI none parse / compile / run / demo / fmt / gen
Runtimes inline tree walker threaded + asyncio
Output formats side effects only Python (sync / async / class / no-runtime) + JSON
Docs one README mkdocs site + Pygments lexer
Playground none browser-based (Pyodide)
ECSS coverage a handful of constructs most of Annex A.1 and A.3

What I added/fixed to finish it:

  • Rebuilt the grammar with proper keyword-priority handling (the old one used brittle negative-lookahead patterns that broke on common words).
  • Replaced the interpreter with a transpiler that emits self-contained Python.
  • Implemented most of the ECSS spec: steps and sub-bodies (A.1.7), object property requests (A.3.9.8), in the context of … (A.3.9.10), reporting data and save context (A.3.9.5/.25), refer by (A.3.9.26/.27), record/array activity arguments (A.3.9.28), and continuation tests with all seven actions and A.2.5 defaults (A.3.9.33).
  • Added the everyday language layer (if/case/while/for/repeat, wait until, expressions), a runtime with concurrency primitives, friendly parse errors with file:line:column carets, a CLI, an mkdocs docs site, and the playground.

My Experience with GitHub Copilot

Copilot is genuinely visible in the history — several release commits are
co-authored by it. Where it helped most:

  • The grammar's keyword-priority resolution. Earley grammars for a DSL full of multi-word identifiers (Star Tracker2, Reaction Wheel3 of AOC of Satellite) are finicky. Copilot helped me reason through lexer priorities and surfaced an Earley lexer-priority bug that would have cost me hours to chase down alone.
  • The transpiler's parse-tree walker — a lot of repetitive _stmt_* emit methods where Copilot's suggestions removed most of the typing.
  • The runtime's threading/concurrency primitives (parallel_until_all, wait_for_event, watchdogs) — boilerplate it could draft and I could refine.

The architectural calls were mine — choosing a transpiler over an interpreter,
the src/ layout, the multiple compile targets, the test design. What Copilot
changed most was the psychology of returning to old code: the 2019 version was
full of bugs and missing imports that, back then, felt like cliff-edges. With
Copilot at hand, fixing those and then doing the real spec work felt like one
continuous flow instead of three separate undertakings. That's largely why this
finally got finished.

Top comments (0)