Skip to content

feat(template): rename lez-framework to spel; delegate scaffolding to spel init#199

Open
vpavlin wants to merge 7 commits into
masterfrom
feat/spel-template
Open

feat(template): rename lez-framework to spel; delegate scaffolding to spel init#199
vpavlin wants to merge 7 commits into
masterfrom
feat/spel-template

Conversation

@vpavlin

@vpavlin vpavlin commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • lgs new --template spel (new default for framework projects) calls spel init <name> --lez-tag <lez-tag>, then layers scaffold.toml and AI skills on top. Scaffold owns no SPEL template files.
  • lgs new --template lez-framework prints a deprecation warning and maps to spel. Existing scaffold.toml files with framework.kind = "lez-framework" continue to work.
  • FRAMEWORK_KIND_SPEL = "spel" added to constants.
  • lgs build idl on spel projects delegates to spel generate-idl (vendored binary).
  • lgs build client on spel projects delegates to spel ffi-gen.
  • Deploy-cache hashing now requires an IDL for both lez-framework and spel projects.
  • templates/lez-framework/ deleted — the template referenced jimmy-claw/lez-framework (broken) and duplicated logic that belongs in spel.
  • skills/lez-framework-template/ renamed → skills/spel-template/ with updated content (spel vocabulary: #[spel_program], spel.toml, make targets, spel CLI).

Why

The lez-framework template was broken (wrong repo, old macros) and maintained a parallel scaffolding path to what spel init already does correctly. This change makes scaffold's role minimal: version pinning, scaffold.toml, and AI skills — program scaffolding belongs to spel.

Closes logos-co/ecosystem#128 (scaffold now uses released spel for framework projects).

Test plan

  • lgs new my-project --template spel succeeds with spel on PATH and produces a buildable project
  • lgs new my-project --template lez-framework prints deprecation warning and produces same result
  • lgs new my-project (default) still uses the default template (bare LEZ, no change)
  • lgs build idl in a spel project calls spel generate-idl via the vendored binary
  • All 342 unit tests pass (cargo test --lib)

🤖 Generated with Claude Code

vpavlin and others added 2 commits June 2, 2026 09:41
Updates the two pinned defaults in `constants.rs`:
- DEFAULT_LEZ: v0.2.0-rc1 (35d8df0) → v0.1.2 (cf3639d), the first
  published LEZ release.
- DEFAULT_SPEL: v0.2.0-rc.5 (1db7c5f) → v0.5.0 (73fc462), released
  today and aligned with LEZ v0.1.2.

Circuits version (0.4.1) is unchanged — LEZ v0.1.2's flake.lock pins
the same circuits commit (d6cf41f) as before.

Closes logos-co/ecosystem#128 (upgrade spel + scaffold to pin LEZ v0.1.2).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…el init

## What changed

- `lgs new --template spel` (new) calls `spel init <name> --lez-tag
  <DEFAULT_LEZ.tag>` to scaffold the project, then layers scaffold.toml
  and AI skills on top. Scaffold no longer owns any SPEL template files.

- `lgs new --template lez-framework` prints a deprecation warning and
  maps to `spel`. Existing projects with `framework.kind = "lez-framework"`
  in scaffold.toml continue to work unchanged.

- `FRAMEWORK_KIND_SPEL = "spel"` added to constants.

- `lgs build idl` for spel projects delegates to the vendored spel binary
  (`spel generate-idl`) instead of scaffold's internal IDL pipeline.

- `lgs build client` for spel projects delegates to `spel ffi-gen`.

- Deploy-cache IDL hashing treats `spel` projects the same as
  `lez-framework` (IDL is a required deploy artifact).

- `templates/lez-framework/` removed entirely — spel init is the
  authoritative scaffolder for framework projects.

- `skills/lez-framework-template/` renamed to `skills/spel-template/`
  with updated content using spel vocabulary (#[spel_program], spel.toml,
  make targets, spel CLI commands).

## Why

The `lez-framework` template in scaffold was broken (still referenced
jimmy-claw/lez-framework) and duplicated template logic that belongs to
spel. Scaffold's role is now minimal: scaffold.toml, AI skills, and
version pinning — program scaffolding is owned by spel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vpavlin vpavlin requested review from a team and Copilot June 2, 2026 07:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Replaces the broken in-tree lez-framework template with a thin delegation to the external spel CLI for scaffolding framework projects. Scaffold now only owns version pinning, scaffold.toml, and AI skills; program scaffolding (Cargo workspace, IDL gen, FFI gen) is handled by spel init/spel generate-idl/spel ffi-gen. The legacy lez-framework template name remains accepted but emits a deprecation warning and is silently mapped to spel.

Changes:

  • New --template spel (and deprecation alias lez-framework) shells out to spel init and layers scaffold state on top; LEZ pin downgraded to v0.1.2, spel pin bumped to v0.5.0.
  • lgs build idl and lgs build client delegate to spel generate-idl / spel ffi-gen for spel projects; deploy-cache hashing now requires an IDL for both lez-framework and spel kinds.
  • Deleted the entire templates/lez-framework/ tree and renamed skills/lez-framework-template/skills/spel-template/ with rewritten content.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/commands/new.rs Splits cmd_new_inner into cmd_new_spel (delegates to spel init) and cmd_new_default; adds find_spel_on_path and build_scaffold_config helpers.
src/commands/build.rs Adds FRAMEWORK_KIND_SPEL branch that runs IDL gen but skips client gen (left to project Makefile).
src/commands/idl.rs Routes spel projects to spel generate-idl; updates error message to mention spel.
src/commands/client.rs Routes spel projects to spel ffi-gen and std::process::exit(0)s mid-helper; updates error message.
src/commands/run_state.rs Treats both lez-framework and spel projects as IDL-required when computing program hashes.
src/commands/init.rs Test updated to expect spel-template skill in place of lez-framework-template.
src/constants.rs Adds FRAMEWORK_KIND_SPEL; bumps DEFAULT_SPEL to v0.5.0 and changes DEFAULT_LEZ to v0.1.2.
src/template/project.rs Removes the lez-framework-specific overlay test and drops the variant from the no-self-patch test.
src/template/skills.rs Test updated for renamed skill directory.
templates/lez-framework/** Entire template tree deleted.
skills/lez-framework-template/SKILL.md Deleted.
skills/spel-template/SKILL.md New skill describing the spel-based workflow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/commands/client.rs Outdated
Comment on lines +49 to +54
FRAMEWORK_KIND_SPEL => {
// For spel projects, FFI/client gen is handled by `spel ffi-gen`
// (or the project Makefile's `make ffi`). Delegate directly.
cmd_spel(vec!["ffi-gen".to_string()])?;
std::process::exit(0);
}
vpavlin and others added 2 commits June 2, 2026 09:56
Addressed Copilot review comment: `std::process::exit(0)` inside a
helper returning `DynResult<Project>` was surprising and bypassed
caller cleanup. Spel dispatch now happens at call-site in
`build_clients_for_current_project` and `generate_clients_from_current_idl`
before reaching the lez-framework-only `require_lez_framework_project`
helper.

Also fixes two rustfmt failures flagged by CI on this branch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three CLI tests expected old `lez-framework`-only error strings and the
old `lez-framework-template` skill name. Updated to match the new error
messages (which now mention both `spel` and `lez-framework`) and the
renamed `spel-template` skill.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 2, 2026 08:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.

Comment thread src/commands/new.rs
Comment on lines +113 to +124
let cwd = env::current_dir()?;
let status = std::process::Command::new(&spel_bin)
.arg("init")
.arg(&cmd.name)
.arg("--lez-tag")
.arg(DEFAULT_LEZ.tag)
.current_dir(&cwd)
.status()
.context("failed to launch spel init")?;
if !status.success() {
anyhow::bail!("spel init failed");
}
Comment thread src/commands/new.rs
Comment on lines +299 to 308
fn find_spel_on_path() -> anyhow::Result<std::path::PathBuf> {
let path_var = std::env::var_os("PATH").unwrap_or_default();
for dir in std::env::split_paths(&path_var) {
let candidate = dir.join("spel");
if candidate.is_file() {
return Ok(candidate);
}
}

Ok(())
anyhow::bail!("spel not found on PATH")
}
Comment thread src/commands/new.rs
Comment on lines 44 to 46
other => {
bail!("unsupported template `{other}`. Expected `default` or `lez-framework`.")
bail!("unsupported template `{other}`. Expected `default` or `spel`.")
}
Comment thread src/commands/new.rs
Comment on lines +126 to +133
// spel init created `target/`; layer scaffold state on top.
fs::create_dir_all(target.join(".scaffold/state"))?;
fs::create_dir_all(target.join(".scaffold/logs"))?;

let cfg = build_scaffold_config(cmd, FRAMEWORK_KIND_SPEL, bootstrap_cache);
write_text(&target.join("scaffold.toml"), &serialize_config(&cfg)?)?;
ensure_scaffold_in_gitignore(target)?;
apply_skills(target)?;
vpavlin and others added 2 commits June 2, 2026 10:03
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Error message for unknown template now mentions the deprecated
  `lez-framework` alias so users know it exists.
- `--lez-path` combined with `--template spel` now fails with a clear
  message (was silently recorded in scaffold.toml but never forwarded
  to `spel init`).
- `--vendor-deps` combined with `--template spel` now fails with a clear
  message (was silently writing non-existent paths into scaffold.toml).
- `find_spel_on_path` now also probes `spel.exe` on Windows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 2, 2026 08:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.

Comment thread src/commands/new.rs
Comment on lines 35 to 49
let template_variant = match cmd.template.as_str() {
FRAMEWORK_KIND_DEFAULT | FRAMEWORK_KIND_LEZ_FRAMEWORK => cmd.template.clone(),
FRAMEWORK_KIND_DEFAULT => cmd.template.clone(),
FRAMEWORK_KIND_SPEL => cmd.template.clone(),
FRAMEWORK_KIND_LEZ_FRAMEWORK => {
eprintln!(
"warning: template `lez-framework` is deprecated; use `--template spel` instead."
);
FRAMEWORK_KIND_SPEL.to_string()
}
other => {
bail!("unsupported template `{other}`. Expected `default` or `lez-framework`.")
bail!(
"unsupported template `{other}`. \
Expected `default` or `spel` (or the deprecated alias `lez-framework`)."
)
}
Comment thread src/commands/new.rs Outdated
Comment on lines +106 to +110
let spel_bin = find_spel_on_path().context(
"spel binary not found on PATH.\n\
Install it first:\n \
cargo install --git https://github.com/logos-co/spel.git --tag v0.5.0 spel",
)?;
Comment thread src/commands/new.rs
Comment on lines +317 to +333
fn find_spel_on_path() -> anyhow::Result<std::path::PathBuf> {
let path_var = std::env::var_os("PATH").unwrap_or_default();
for dir in std::env::split_paths(&path_var) {
let candidate = dir.join("spel");
if candidate.is_file() {
return Ok(candidate);
}
// On Windows executables carry a .exe suffix.
#[cfg(target_os = "windows")]
{
let candidate_exe = dir.join("spel.exe");
if candidate_exe.is_file() {
return Ok(candidate_exe);
}
}
}

Ok(())
anyhow::bail!("spel not found on PATH")
Comment thread src/commands/run_state.rs
Comment on lines +88 to +92
// Both lez-framework and spel projects require an IDL file at deploy time.
let is_lez_framework = matches!(
project.config.framework.kind.as_str(),
FRAMEWORK_KIND_LEZ_FRAMEWORK | FRAMEWORK_KIND_SPEL
);
- Install hint in find_spel_on_path error now uses DEFAULT_SPEL.tag
  instead of a hard-coded version string that would drift on bumps.
- check_spel_version() warns when the installed spel version does not
  match DEFAULT_SPEL.tag, so mismatches surface before `lgs setup`.
- available_templates() now includes "spel" explicitly; after removing
  the lez-framework template directory it was no longer discoverable
  from disk, so --template help advertised only "default".
- Renamed is_lez_framework -> requires_idl in run_state.rs; the old
  name implied the flag only covered lez-framework, but it also matches
  spel. Updated the inline comment at the use site to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 3 comments.

Comment thread src/commands/new.rs
Comment on lines +332 to 342
let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.contains(DEFAULT_SPEL.tag) {
eprintln!(
"warning: installed spel version ({}) does not match the expected {} pinned by scaffold.\n\
This may cause unexpected behaviour. Install the pinned version with:\n \
cargo install --git https://github.com/logos-co/spel.git --tag {} spel",
stdout.trim(),
DEFAULT_SPEL.tag,
DEFAULT_SPEL.tag,
);
}
Comment thread src/commands/new.rs
Comment on lines +106 to +129
let spel_bin = find_spel_on_path().with_context(|| {
format!(
"spel binary not found on PATH.\n\
Install it first:\n \
cargo install --git https://github.com/logos-co/spel.git --tag {} spel",
DEFAULT_SPEL.tag
)
})?;
check_spel_version(&spel_bin);

if cmd.lez_path.is_some() {
anyhow::bail!(
"`--lez-path` is not supported with `--template spel`.\n\
`spel init` fetches LEZ via `--lez-tag`; a local path override is not forwarded.\n\
Use `--template default` if you need a local LEZ checkout."
);
}
if cmd.vendor_deps {
anyhow::bail!(
"`--vendor-deps` is not supported with `--template spel`.\n\
Vendoring is managed by `spel init` and `lgs setup`, not by scaffold directly.\n\
Use `--template default` if you need vendored deps."
);
}
Comment thread src/commands/new.rs
anyhow::bail!("spel init failed");
}

// spel init created `target/`; layer scaffold state on top.
@weboko

weboko commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

@vpavlin wow, copilot really tried hard to review your PR

@weboko

weboko commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

is it ready to review?
please, ensure to update dogfooding.md file

quickly tried:

  • lgs build idl / build client / deploy are broken for spel projects and seems due to IDL path & output mismatch
  • seems like circuits pin (0.4.1) needs to be updated, doesn't work with new spel pin for me

@weboko

weboko commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Review + hands-on dogfooding

Reviewed the diff and then actually ran the affected flows end-to-end (built the CLI, installed spel v0.5.0 from the pinned tag, created default + spel projects, ran build idl/build client). The rename/refactor itself is clean and well-commented, and the "scaffold owns pinning, spel owns scaffolding" direction is good. 342 unit tests pass. However, dogfooding surfaced two showstoppers that break the PR's own Test Plan, plus a few smaller issues. None of the new spel delegation path is covered by integration tests — which is exactly where the breakage is.


🔴 Blocker 1 — lgs build idl / build client / deploy are broken for spel projects (IDL path & output mismatch)

The IDL location contract between scaffold and spel doesn't line up:

Producer / consumer Path
scaffold scaffold.toml framework.idl.path idl/ → expects idl/<stem>.json
deploy-cache hashing (run_state.rs ~L118, tightened in this PR) reads idl/<stem>.json, bails if missing for spel
spel spel.toml / make idl <root>/spelproj-idl.json
spel generate-idl (what lgs build idl invokes) prints IDL to stdout, writes no file

Reproduced in a generated spel project (vendored spel binary in place):

  • lgs build idl → runs spel generate-idl, dumps JSON to stdout, creates no file, exits 0. src/commands/idl.rs returns cmd_spel(["generate-idl"]), and cmd_spel uses .status() (inherits stdout) — it never redirects to idl/<stem>.json the way the lez-framework branch writes its IDL.
  • lgs build clientspel ffi-genError reading IDL '…/spelproj-idl.json': No such file or directory, exit 1.
  • lgs deploy / lgs runcompute_program_hashes requires idl/<stem>.json → would bail: "expected IDL file …/idl/spelproj.json … is missing; run lgs build idl first" — and lgs build idl never produces it. Dead end.

So the Test Plan item "lgs build idl … calls spel generate-idl" is true but functionally useless: nothing is persisted, and the deploy gate this PR adds then makes deploy impossible. Fix: capture spel generate-idl stdout → write idl/<stem>.json (as the lez-framework branch does), or point framework.idl.path at spel's <root>/spelproj-idl.json convention and teach run_state to read that name.

🔴 Blocker 2 — circuits pin (0.4.1) is incompatible with the bumped spel/LEZ pins (they need 0.4.2)

constants.rs bumps DEFAULT_LEZ → v0.1.2 and DEFAULT_SPEL → v0.5.0 but leaves DEFAULT_CIRCUITS_VERSION = "0.4.1".

  • Both LEZ v0.1.2's and spel v0.5.0's Cargo.lock pull logos-blockchain rev 1da154c…, whose build script asserts circuits v0.4.2.
  • Reproduced: cargo install --git …/spel.git --tag v0.5.0 spel against circuits 0.4.1 → panic: "The logos-blockchain-circuits directory … is version 'v0.4.1', but version 'v0.4.2' is expected."
  • setup.rs provisions circuits at the 0.4.1 pin and uses it for the LEZ-sequencer, wallet and vendored-spel builds. lgs build was observed downloading …/v0.4.1/… before the (long) sequencer build — it hits the same assertion.

The doc comment derives 0.4.1 from LEZ's flake.lock (nix), but scaffold builds via Cargo, which needs 0.4.2. Net effect: lgs setup / lgs build fail on a clean machine for both default and spel projects. The comment even says "bump this in lock-step with DEFAULT_LB_PIN / DEFAULT_LEZ." Fix: DEFAULT_CIRCUITS_VERSION = "0.4.2" and verify a from-scratch lgs setup.


🟠 Medium

3. check_spel_version warns on every spel project, even when correct. spel --version (v0.5.0) prints usage to stderr and exits 1 with empty stdout; new.rs greps output.stdout for "v0.5.0" → always false. Live output during lgs new --template spel:

warning: installed spel version () does not match the expected v0.5.0 pinned by scaffold.

Note the empty (). Read stderr too (or call a real version subcommand) before deciding to warn.

4. cache_root portability regression — affects default too. The build_scaffold_config extraction changed the no---cache-root default from String::new() to the absolute bootstrap path (new.rs ~L292). Confirmed: a generated default project's scaffold.toml now contains cache_root = "/root/.cache/logos-scaffold". The deleted comment explicitly kept it empty "so scaffold.toml stays portable." This machine-specific path now ships in every committed config, not just spel.

🟡 Low

5. Flag-validation ordering. --vendor-deps / --lez-path with --template spel report "spel not found on PATH" instead of the intended "flag not supported" error, because find_spel_on_path() / check_spel_version run before the flag checks in cmd_new_spel. Validate args first (fail fast regardless of environment).

6. Generated project's spel deps don't match the recorded pin. spel init (called with only --lez-tag) emits spelproj_ffi → spel-framework-core tag="v0.4.0" and examples → branch="main", while scaffold.toml records spel v0.5.0. branch="main" is a moving target that defeats the reproducible pinning that's scaffold's job. Consider passing --spel-tag to match. (Partly upstream, but it's the seam this PR introduces.)

7. No test coverage for the new path. There are no new-command integration tests at all, and cmd_new_spel / the deprecation mapping / the flag-bail paths are untested; the removed lez_framework_overlay unit test wasn't replaced.

8. Doc/UX nits. skills/spel-template/SKILL.md L116-118 uses bare spel -- initialize … (the -- is the lgs passthrough separator), contradicting its own gotcha to use lgs spel -- …; L105 says "lgs build runs make build" (it runs scaffold's workspace build, not make). lgs new --template spel prints two separate "Next steps" blocks (spel's + scaffold's).


Flows exercised

new --template default ✅ (cache_root regression) · new --template spel ✅ delegates (warning #3, IDL #1, deps #6) · new --template lez-framework ✅ deprecation→spel · bad template ✅ correct error · spel + --vendor-deps/--lez-path ⚠️ wrong message (#5) · failure cleanup ✅ no leftover dir · help/available_templates ✅ default, spel · build idl 🔴 stdout, no file · build client 🔴 missing IDL · build/setup 🔴 circuits skew · deploy-cache requires IDL 🔴 would bail · init skills→spel-template ✅ · 342 unit + changed integration tests ✅.

Bottom line: the headline happy path (lgs new --template spel → buildable, deployable project) doesn't work today — it breaks at lgs setup (circuits 0.4.1 vs 0.4.2) and again at lgs build idl/deploy (IDL location). Both look like small, targeted fixes.

🤖 Reviewed via hands-on dogfooding in a fresh environment. Generated with Claude Code.

@danisharora099 danisharora099 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM on the direction - spel owns scaffolding, scaffold owns pins/orchestration. Agree with @weboko: IDL output doesn’t land where deploy expects, and circuits 0.4.1 vs 0.4.2 blocks setup on a clean box. Fix those two (+ cache_root / version warning if easy)

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.

Upgrade spel and scaffold to pin LEZ v0.1.2

4 participants