# Spark IDE

Honest 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.

**Honesty:** not Electron / not PyQt / not a full IDE product chrome.
Verified ops only — no invented menus or debugger.

| 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 | **Works** — `11ab006` |
| `ide keys` / `ide key` | Keymap loop (quit/save/run/open/show) | **Works** — §1b |
| Paint bind | status path strip + gutter + AI strip → PPM | **Works** — `b029a4a` |
| Cursor workspace | `make ide` interim editor host | **Works** — not the product |
| CLI `./spark --dry-run` / `--live` | Primary runtime today | **Works** |
| Electron / VS Code fork | — | **Not the product** |
| PyQt IDE shell | — | **Not built** |
| 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 —
not a claim that GAS is the permanent VM.

| 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`. No Electron.

**Paint wire (status strip `b029a4a` + AI panel):** core exports
`ide_buf` / `ide_buf_len`. 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). Paint
owns `ide_cursor`, `ide_status_set`, and `ide_ai_set`. Standalone
`make test-ide-paint` / `ide_status_strip_ppm` prove the paint ELF.
There is **no** `ide paint` language statement.

**Dry-run safe:** parent `--dry-run` → child always `./spark --dry-run <file>`.
Parent `--live` → child `--live`. No network invented by `ide` itself.

**E2E dry (usable now):**

```bash
./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`).

```bash
./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
```

**Proven script tokens (real — do not invent others):**

| 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 mouse GUI in this lane.

---

## 2. Open the Cursor workspace (editor host)

```bash
cd /home/mike/workspaces/spark
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). 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 / `:8010` / PRO 6000.
Public Bifrost probes use Infisical `$VK_PROBE` only — [ASK_LIVE.md](ASK_LIVE.md).

---

## 3. CLI workflow (always the runtime SoT)

```bash
cd /home/mike/workspaces/spark
make
./spark --dry-run examples/hello.spark
./spark --dry-run examples/ide_hello.spark
make test
```

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

```bash
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)

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

Same ops as `examples/review_builder.spark`. Static review only — never
`eval`s JS.

---

## 5. What is not built

- Electron / Code-OSS wrapper marketed as Spark IDE
- PyQt IDE chrome
- Project wizards, debugger UIs, invented menus
- Full self-host compiler (A seeds + lex goldens only — SELF_HOST.md)

---

## 6. Related

- [PROGRAMMING_GUIDE.md](PROGRAMMING_GUIDE.md)
- [SELF_HOST.md](SELF_HOST.md) (A+B+C)
- [AGENTS.md](../AGENTS.md)
- [LANGUAGE.md](LANGUAGE.md)
- [ASK_LIVE.md](ASK_LIVE.md)
- Reports (local): `spark-ide-ask-20260831.md` (`dc54d92`),
  `spark-ide-show-20260831.md` (`efa2d90`),
  `spark-ide-ask-show-20260831.md` (`b58ab9f`),
  `spark-ide-status-strip-20260831.md` (`b029a4a`),
  `spark-ide-save-reopen-20260831.md` (`11ab006`)
