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
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
- Live playground (no install): https://stzifkas.github.io/pluto-ecss/playground/ — write PLUTO and compile/run it entirely in your browser via Pyodide.
- Docs: https://stzifkas.github.io/pluto-ecss/
- Repo: https://github.com/stzifkas/pluto-ecss
-
Install:
pip install pluto-ecss
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
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 andsave 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)