Skip to content

feat: code-first editor (sca edit) and the agent landing path - #34

Merged
NiJingzhe merged 34 commits into
devfrom
feat/editor-runtime-integration
Oct 13, 2026
Merged

NiJingzhe merged 34 commits into
devfrom
feat/editor-runtime-integration

Conversation

@NiJingzhe

Copy link
Copy Markdown
Collaborator

What

The code-first editor and the agent landing path.

Editor (sca edit, now part of the SDK)

  • Runs a workspace's notebooks in a marimo kernel with the SDK's own cell executor; the editor, sca run and run_notebook share one runtime and one per-cell cache.
  • Parameters from # ---- params ---- cells with # ui: comments; local modules (shared dimensions) in a module view; reload on file change.
  • Live preview straight from the solids (simplecadapi.scene.preview, SCAPREV1) instead of building a package; entity details on demand. Solids no longer carry an eagerly built mesh (~20% faster modeling).
  • Viewport selection is written as a scad.ql selection cell; autosave; sca snapshot + viewport.png for coding agents; cell reference copy button.
  • Bottom log dock with re-evaluation progress; ordered notebook switching; kernel boots non-interactively for notebooks with inline dependencies.

Landing path

  • docs/landing.md: the script an agent follows (install via uv/pipx/pip, skill, sca init, explain, open the example).
  • sca example u_link [DIR], sca skill where; the wheel now carries the built editor UI, the skill and the demo notebooks (release workflow builds editor-web first and verifies the wheel's contents).
  • Skill: new references/domains/editor-collaboration.md, routed from SKILL.md.

Housekeeping: design-docs/, sandbox-envs/, .omp/, .claude/, .agents/, .marimo.toml are untracked and ignored.

Note for reviewers

Six older commits (the pcg_facade_tower example, pymupdf as an optional extra and two merges) are in this range because they are on local dev and not yet on github/dev.

Before this reaches users

  • The wheel with the editor needs a release; PyPI's latest stable (2.1.4) has no sca edit.
  • docs/landing.md must be on master for the physpace.dev/sca/landing.md route.

Verified

  • test_example_cli, test_skill_cli, test_skill_build, test_sca_cli, test_editor, test_addon_cli: 120 passed, 4 skipped; editor suite with SCA_EDITOR_E2E=1 41 passed.
  • Built the wheel, installed it into a clean environment with a temp HOME and a uv tool install, ran sca init, skill install, example, ls, edit; the assembly renders in the editor (checked in a browser).
  • Not exercised: Windows.

NiJingzhe and others added 30 commits October 9, 2026 18:31
pymupdf (AGPL-3.0 / commercial dual license) was on the eager package
import path via inspect.drawing, so 'import simplecadapi' hard-failed
without it — including inside the render worker subprocess. The drawing
modules now bind a lazy proxy (real module under TYPE_CHECKING); the
first attribute access performs the import and a missing pymupdf raises
an ImportError naming the new 'drawing' extra.

Core install drops pymupdf; the dev extra keeps it for the test suite.
Verified: fresh venv without pymupdf and py-slvs passes import, build,
STEP export, render, solver-backend resolution; full suite 1941 passed /
5 skipped; ty diagnostics on the drawing package unchanged vs dev.
PCG unitized-curtain-wall tower: one parametric code base, any plan
(rect/chamfer/l_shape), floor count and setback policy, generating a
manufacturable facade - 3,697 instances resolved onto 22-43 typed parts
with a hard quantization-error bound.

Pure-data layout engine (plan -> setback tiers -> per-edge subdivision ->
panel schedule with K-quantized fin wave and ordered-dithered WWR), type
part factories, band subassemblies, tower assembly, export (scadpkg +
AP242 STEP + panel-schedule CSV) and eight verify gates with known-bad
proofs. Imported as archived from the author's working stash; ported to
the current SDK in the following commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…time SDK

The example was written against the part-cache SDK removed in PR #17.
Port every gate to the current API without weakening a single geometry,
layout or validity check:

- s2/s3: drop the P7/K8 warm-cache-hit assertions (feature gone).
- s4: A2 becomes a pure determinism check (two builds carry the same
  definition content hash); the corrupt/dirty solve-report fields no
  longer exist.
- s4/s5 known-bad KB10: a tampered content_hash cannot be constructed
  (definitions self-validate), so the case now rebuilds a DIFFERENT
  design and requires A2 to fire.
- s7: the incremental-rebuild assertions died with the cache; the gate
  is now an honest full-rebuild timing report per edit step
  (out/incremental.json).
- panels/floor docstrings and the three Chinese design notes updated for
  the cache removal (dated era-notes, original text kept).

Also: example README (run commands, module map, known limitations),
examples/README.md table row, and SDK_DEFECTS.md D11 recording the
L_SHAPE reflex-corner profile vs V5 envelope conflict (open, contribution
welcome) — s6's plan geometry sweep covers RECT/CHAMFER; L_SHAPE is
layout-verified only.

Gates: s1 3s, s2 7s, s3 80s, s4 139s, s5 279s, s6 967s, s7 264s,
s8 377s - all PASS; s1-s3/s4/s5 known-bad all discriminate as designed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ndering

The DXF -> PNG path consumes pymupdf through ezdxf's drawing backend, so
the extra covers both drawing consumers, not just vector-PDF inspection.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
pcg_facade_tower example: parametric facade tower (pure-data layout
engine, typed part factories, band/tower assemblies, AP242 export) with
eight verify gates ported to the notebook-runtime SDK and known-bad
proofs; L_SHAPE full-tower verification is an open issue (SDK_DEFECTS
D11).
pymupdf becomes an optional 'drawing' extra: the engineering-drawing
family (vector-PDF inspection + DXF PNG rendering via ezdxf's backend)
is its only consumer; import, modeling, STEP export and VTK rendering
run without it. Drawing functions without pymupdf raise an ImportError
naming the extra.
Parameters are the top-level literals or scad.var of a '# ---- params ----'
cell, with an optional trailing '# ui: slider(min, max, ...)' comment for the
control. The editor kernel applies values an editor saved (params.json in the
notebook state dir) as the defining cell finishes; headless runs take only
explicit overrides. live_package/publish_live project the product from a
running marimo kernel. sca ls / sca params report workspaces and notebooks
from the files alone, with no change to existing examples.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…value

The editor kernel runs scratch cells the notebook does not contain; the
executor raised KeyError on them. params.commit_value writes a parameter's
value into the cell source, keeping the rest of the line.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The editor moves in from sca-web-editor as simplecadapi.editor (UI sources
in editor-web/, built into the package; 'editor' extra). It no longer
records anything itself: the kernel runs the notebook with the SDK cell
executor, the server asks it for the product (runtime.live.publish_live)
when marimo reports a completed run, and parameters are saved values the
executor applies, so marimo's dataflow reruns what reads them. Controls
come from '# ui:' comments; a workspace is any directory of notebooks.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s inside functions

code.edit stripped every line starting with 'return', including those inside
@app.function bodies, and rewrote the file even when the code was unchanged.
Now only the cell's own top-level return is stripped (by AST), unchanged code
just runs, and @app.function cells are not edited through code mode (marimo
would turn them into plain cells).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…w look

Picking in the viewport writes a selection cell (ql selectors from the picked
geometry, selected_<kind>[_<i>] and selected_item) and saves a snapshot
(.sca-editor/snapshot.json + viewport.png, sca snapshot) for coding agents.
The viewport gets a ground grid and an axis gizmo in a CAD (Z up) frame.
Cells fold to their step name, run everything above, autosave, and are
deleted with a trash button; the inspector shows a JSON tree; the chrome is
black and white with square 2px rules. Opening a notebook clears the model at
once. ql.vertices() now resolves through solids and faces.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Each cell header gets a copy button: the reference is the notebook path, the
cell's line range in the file, its number and name; Alt/Shift+click adds the
code. Line ranges come from the saved file, so they follow autosave.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…change

The workspace lists the local modules notebooks import (sca ls reports them
too) and opens one in a module view: autosaved source plus its dataclass
fields (and commented constants) as controls written into the file. A change,
from the editor or on disk, reloads the module in the kernel and reruns the
notebook; used notebooks are rerun from their files. Number boxes keep the
typed text until it is committed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…the kernel

The kernel runs scratch code one piece at a time, so a selection write queued
behind a long run (publishing a big assembly takes seconds) delayed the cell,
and fast picks piled up one thread each. The server now pushes the selection
cell from memory immediately and coalesces the kernel writes. SCA_EDITOR_TRACE=1
logs the time of every kernel call.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…rnel; faster packages

The cell cache is stored under a digest of the files each cell depends on
(modules reached through the names it reads, through the notebook functions it
calls, and through the cells it reads from; child notebooks; inputs) instead
of one digest for the notebook: a changed module recomputes what reads it and
restores the rest, and going back restores everything. The editor kernel runs
cells through the same cache (cells downstream of saved parameter values are
keyed by them; cells that run child notebooks are not cached there).

The render mesh of a face is computed with numpy in the profile's fixed
operation order: identical bytes, package builds about twice as fast.

The editor also watches the data files a notebook lists in 'inputs'.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
While a model is being made (kernel starting, notebook opening, module reload,
run all) a gray mask covers the panels: a square dot-matrix with a ripple
spreading from the middle, and a small retro window with a spinner, what is
going on and for how long. It shows after 250 ms, ends when the model
arrives or the work fails, and does not veil interactive rebuilds.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…veil

marimo interrupts the kernel when the client of /api/kernel/execute
disconnects. The bridge's scratch calls had client timeouts (the 5 s watchdog
ping: 10 s; the idle probe: 15 s), so any cell that ran longer than that - a
use() of a child notebook - was killed with KeyboardInterrupt and the
product was missing. Scratch calls now wait without a timeout and the
watchdog asks /api/sessions instead.

The loading veil's swell is one long wave and its dots are dimmer.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A cell's run button is a stop button while the kernel runs it (so is run-all in
the header); stopping interrupts the kernel and drops the work queued behind it.
The server forwards marimo's live cell states.

The editor remembers each notebook's last published package under a digest of
everything the model depends on (notebook, modules, children, data, saved
values, versions); switching back shows that model and the cells from the file
immediately while the kernel boots, and the kernel's own publish only reloads
the view if the model differs. Revisiting an assembly went from 16.5 s to 0.3 s.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
scene.preview makes what a viewer under edit needs, without a package: the
triangles, edge segments and vertices of each part, the index range of every
face and edge (so they can be highlighted and picked), each part once with its
instances' placements, and entity_info for one picked entity (worked out on
demand; the same properties the package sidecar holds). Geometry is kept per
(BREP content, tolerance), so a part that did not change previews for free even
if its object was rebuilt. Entity ids and properties match the package's.

Solids no longer build a mesh when created: nothing read it while modeling, and
every intermediate solid paid about 20% of the run for one.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…uilding a package

The kernel publishes a SCAPREV1 preview (triangles, edges, vertices, face/edge
groups) straight from the solids; the viewer loads it, and per-entity details
are fetched on demand (entity.info) before a selection cell is written.
Previews are cached per dependency signature for instant revisit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ine dependencies

marimo asks whether to sandbox such a notebook and waited on stdin forever
("marimo not ready after 60s"). Pass --no-sandbox and close stdin.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Edges and faces are tessellated separately, so a mesh chord can bulge past an
edge's polyline and break it into dashes. The edge shader now moves its depth
0.4 mm towards the camera (screen position unchanged).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…switching

- bottom dock: log of events/errors, progress of the cells being re-evaluated,
  running/queued/blocked on cells; errors leave the header
- opening notebooks is ordered (latest wins), a superseded open ends quietly,
  the list highlights the notebook being opened immediately
- boot waits for the instantiate run before publishing; a failing setup is
  reported as the cause; refreshed pages load an unchanged model; viewport
  redraws after resize

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
They are ignored now; the files stay on disk.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…emo in the wheel

- sca example u_link [DIR]: copy the bundled motor-mount workspace out, ready for sca edit
- sca skill where: print the install destination without writing
- release: build editor-web before uv build; the sdist carries the built UI and the
  five demo notebooks (the wheel is built from it); verify the wheel's contents
- skill: editor-collaboration domain (selection cell, snapshot, cell references,
  parameters), routed from SKILL.md; version metadata brought up to date
- fix a SyntaxWarning printed on every sca call

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
NiJingzhe and others added 4 commits October 12, 2026 23:25
Install (uv tool, pipx, else pip), skill install to ~/.agents/skills, sca init,
explain the SDK from the skill, open the u_link example in the editor and coach
the person through parameters, selection and handing work to the agent.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
CI syncs only the dev group; three drawing tests import pymupdf, which became an
optional extra, so collection failed. Putting it in the group keeps local
uv sync --group dev able to run the whole suite.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The editor's packages join the dev group so the main job no longer skips
test_editor.py, and a separate job runs it with SCA_EDITOR_E2E=1 to boot a real
marimo kernel.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@NiJingzhe
NiJingzhe merged commit 2f81fcd into dev Oct 13, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant