Spark

Spark IDE

Status of programming Spark in an IDE today.

Today’s ./spark ELF is the GAS scaffold for IDE ops (asm/). Authoring SoT DECIDED (A+B+C): destination self-host in Spark (A); thin C bootstrap (B); Spark-native assembler (C). GAS is disposable — not forever SoT. Do not start a Rust/Python VM from this lane.

Verified ops only — buffer, keymap, ask, show, and paint wire.

Path What it is Status
ide language ops ide new\|open\|save\|run\|buffer\|ask\|show Works — §1
open→save→reopen examples/ide_save_reopen.spark + sha256 Works11ab006
ide keys / ide key Keymap loop (quit/save/run/open/show) Works — §1b
Paint bind status path strip + gutter + AI strip → PPM Worksb029a4a
Cursor workspace make ide interim editor host Works — not the product
CLI ./spark --dry-run / --live Primary runtime today Works
Runtime rewrite A+B+C DECIDED; GAS scaffold In progress — see SELF_HOST.md

1. IDE core ops (real on today’s scaffold)

Implemented in asm/ide_ops.s on the current ./spark binary (kw_ide → keys lane first, else ide_ops_dispatch). Scaffold path on today’s ./spark binary.

Op Behavior
ide new Clear in-memory buffer (+ optional "path" sets path, empty body)
ide open "path" Load file into buffer; remember path
ide save / ide save "path" Write buffer to path (out/ide/ mkdir as needed)
ide buffer Terminal dump of buffer (display SoT for core)
ide run Flush buffer to path or out/ide/buffer.spark; fork/exec ./spark
ide ask ["instruction"] Buffer (+ optional quote) → real ask_run_prompt
ide show ["path.ppm"] After paint: engine_window_show → dry validate / live ./spark-engine-show

ide ask (AI strip): dry uses the same fixture picker as language ask (pick_ask_reply_ptr — e.g. Gravity). Live forks ./spark-ask-http. Updates paint AI panel via ide_ai_set, then rewrites out/ide/editor.ppm. Example: examples/ide_ask.spark.

ide show (display window): reuses the real engine B path (asm/engine_window.s + companion tools/browser/spark_engine_show.c). Default PPM is out/ide/editor.ppm (after open/ask paint). Dry-run validates P6 and writes out/browser/show.json (no X11). --live forks ./spark-engine-show --ppm …. Optional quote must be a .ppm / .rgb. Example: examples/ide_show.spark.

Paint wire (status strip b029a4a + dirty * + AI panel): core exports ide_buf / ide_buf_len / ide_dirty. After new/open/ save, core binds paint and writes out/ide/editor.ppm (top status path bar via ide_status_set + gutter + glyphs + cursor + bottom AI strip). Buffer edit (ide new) sets dirty → status appends * (also out/ide/status_dirty.txt); open/save clear dirty. Paint owns ide_cursor, ide_status_set, and ide_ai_set. Standalone make test-ide-paint / ide_status_strip_ppm prove the paint ELF. Paint runs via the paint wire (make test-ide-paint), not as an ide paint statement. Proven keymap tokens are listed below.

Dry-run safe: parent --dry-run → child always ./spark --dry-run <file>. Parent --live → child --live. The ide path does not open its own network connections.

E2E dry (usable now):

./spark --dry-run examples/ide_hello.spark
        # ide.open → out/ide/editor.ppm (P6)
        # ide.run  → child ./spark --dry-run … + Gravity

        ./spark --dry-run examples/ide_ask.spark
        # ide.open → editor.ppm; ide ask → fixture (Gravity) + AI strip
        # live: ./spark --live examples/ide_ask.spark → spark-ask-http

        ./spark --dry-run examples/ide_show.spark
        # ide.open → editor.ppm; ide show → engine validate + show.json
        # live: ./spark --live examples/ide_show.spark → spark-engine-show

        ./spark --dry-run examples/ide_run_show.spark
        # ide.open → editor.ppm; ide run → child; ide show → show.json
        # live: ./spark --live examples/ide_run_show.spark → run + spark-engine-show

        ./spark --dry-run examples/ide_ask_show.spark
        # ide.open → editor.ppm; ide ask → fixture + AI strip; ide show → show.json
        # live: ./spark --live examples/ide_ask_show.spark → ask-http + spark-engine-show

        ./spark --dry-run examples/ide_save_reopen.spark
        # ide.open → save → reopen; out/ide/ide_saved_rt.spark sha256==hello.spark
        

1b. Keymap / command loop (asm/ide_keys.s)

Dispatched before core when the line is ide keys or ide key ….

Op Behavior
ide keys "script" Read command file list; run quit/save/run/open/show
ide key quit\|save\|run\|open\|show ["path"] Single keymap command
Script tokens q/quit, s/save, r/run, o path/open path, w/show

Dry-run: prints {"op":"ide.keys",…} traces (and appends out/ide/keys_trace.jsonl). Open still uses real open+read into shared ide_buf, then paints out/ide/editor.ppm. Show dry-validates via engine_window_show (live: ./spark-engine-show). Save/run do not write/fork under dry-run (live: write + fork ./spark --dry-run).

./spark --dry-run examples/ide_keys.spark
        # wire proof: ide key open … then ide key show → editor.ppm + show.json

        ./spark --dry-run examples/ide_keys_save.spark
        # proven keys: script `s` → {"cmd":"save"} + path; dry no write

        ./spark --dry-run examples/ide_keys_run.spark
        # proven keys: script `r` → {"cmd":"run"} + path; dry no fork
        # landing `ff7b545` (example + cmds_run.txt + report stamp)

        ./spark --dry-run examples/ide_dirty_status.spark
        # open clean → new dirty (*) → save clean; status_dirty.txt ends *
        

Proven script tokens:

Token Cmd Dry Live
o path / open open real read + paint same
s / save save JSON trace only write buffer
r / run run JSON trace only fork ./spark --dry-run
w / show show validate PPM ./spark-engine-show
q / quit quit end loop end loop

No n/new keymap token (core ide new only). No mouse GUI in this lane.


2. Open the Cursor workspace (editor host)

make ide
        # equivalent:
        ./tools/open-spark-ide.sh
        

This opens Cursor on spark.code-workspace with .spark grammar + Bifrost. It is not a substitute for the ide ops above.

Workspace folders

  1. Spark (language) — this repo
  2. Spark Browser — ../spark-browser

Tasks

Label Command
spark: make make
spark: test make test
spark: dry-run hello ./spark --dry-run examples/hello.spark
spark: machine-proof make machine-proof
spark: live ask ./spark --live examples/ask_live.spark

Agent card: AGENTS.md (../AGENTS.md in repo). Rules: .cursor/rules/spark-ide-ai-coding.mdc, spark-language.mdc.

AI coding (gateway)

Surface Endpoint Models
Cursor Override (when ON) http://127.0.0.1:4010/cursor/v1 Bifrost aliases fast / code / code-bulk / code-max / best
Terminal live ask AI_GATEWAY_URL=http://127.0.0.1:4000 + Bearer sk-bf-* model in .spark

Never commit keys. Never route coding to voice GPU aliases. Public Bifrost probes use Infisical $VK_PROBE only — ASK_LIVE.md (ASK_LIVE.md in repo).


3. CLI workflow (always the runtime SoT)

make
        ./spark --dry-run examples/hello.spark
        ./spark --dry-run examples/ide_hello.spark
        make test
        

Live ask (only when you intend network + gateway):

export AI_GATEWAY_URL=http://127.0.0.1:4000
        export OPENAI_API_KEY=…
        ./spark --live examples/ask_live.spark
        

ELF flags (from ./spark with no args): --dry-run, --live, --allow-net, --allow-net-capture, --pstn-live, --version only.


4. Language coding loop (codegen — not buffer IDE)

./spark --dry-run examples/ide.spark
        # writes out/program.spark via implement
        

Same ops as examples/review_builder.spark. Static review only — never evals JS.