Skip to content

fix(templates): make a scaffolded project clean, and publishable as one artifact - #3594

Merged
kojiwakayama merged 12 commits into
mainfrom
fix/scaffold-parity-475
Aug 11, 2026
Merged

fix(templates): make a scaffolded project clean, and publishable as one artifact#3594
kojiwakayama merged 12 commits into
mainfrom
fix/scaffold-parity-475

Conversation

@kojiwakayama

@kojiwakayama kojiwakayama commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Closes the veryfront-code half of veryfront-issue-inbox #475.

What was actually broken

The issue asks that a new project install, run and build with zero errors, zero
lint errors and zero warnings. Four of the seven starters failed that on main,
reproducibly:

template npx tsc --noEmit veryfront lint
agentic-workflow 6 errors 5 errors
coding-agent 4 errors clean
multi-agent-system 1 error 1 error
saas-starter clean 3 errors

The worst is agentic-workflow. Its publish step passed an execute
callback, which StepOptions does not accept:

step("publish", {
  execute: async ({ previous }) => { /* ... */ },   // TS2353
});

tsc rejects the object literal, and step() throws
Step "publish" must specify either 'agent' or 'tool' the moment the workflow
runs — the template's headline feature could never execute. The same page also
mapped run.steps, a field WorkflowRun does not have (only the template's own
demo API invented it).

multi-agent-system was broken the same way, one level down. Its orchestrator
built delegate tools with a top-level getAgentsAsTools(), but agent()
registers on call and discovery loads agents/orchestrator.ts before
researcher.ts and writer.ts - so the call ran against an empty registry and
the coordinator shipped with no one to coordinate, in the template whose entire
subject is delegation. It now uses delegates: ["researcher", "writer"], which
the runtime resolves when a run starts, so load order cannot matter. The
multi-agent guide taught the same broken shape and now teaches this one.

The rest were ordinary defects that nothing in this repo was looking for:
readDir streams entries but list-files filtered it like an array; four
async callbacks never awaited anything; three <button>s had no type.

Why nothing caught them

The starter templates are real files under templates/files/, but they are
outside the workspace lint and typecheck, so a template could ship anything.
templates/scaffold-quality.test.ts closes that hole. Scaffolding to a temp
directory escapes the exclusion, so the gate can run both halves against a real
project: the same deno lint that veryfront lint shells out to, and a
deno check of the scaffold's agents, tools and workflows against the
framework's own declarations. On the pre-fix templates it fails six ways -
lint for agentic-workflow, multi-agent-system, saas-starter; types for
agentic-workflow, multi-agent-system, coding-agent. After the fix all
seven templates pass both. The whole gate runs in ~24s.

The parity half

The issue's other requirement — a project created in Studio must be identical to
one created by the CLI — could not hold, because the hosted flow copies a stored
project row: no repo, no PR, no lint gate, no link to the release train. It froze
at the pages-router era while these templates moved to the app router.

This adds the artifact that makes one source possible. veryfront/scaffold
exports materializeScaffold(), which returns the complete contents of a new
project (template files, AGENTS.md, package.json, .env, .gitignore, and
deno.json on the Deno runtime) without touching a disk, and resolves Studio's blank slug onto
the CLI's minimal starter. createProject now assembles through the same
function it exposes, so the two paths cannot disagree.

templates/scaffold-parity.test.ts asserts the agreement by construction: it
really scaffolds each template to a temp directory, reads it back, and diffs it
against materializeScaffold() for the same request — no snapshot for a future
template change to invalidate silently.

One export, not two

An earlier revision of this branch also declared
./cli/templates/manifest, a wrapper publishing manifest.json as data. It is
gone.

The manifest is data; materializeScaffold() is the behaviour. A consumer that
reads the manifest still has to reimplement package.json generation, AGENTS.md
injection and .gitignore for itself — a second scaffolder fed from one data
source, which is issue #475 one level down, in the PR whose subject is not
having two implementations. veryfront-api will call materializeScaffold(), and
no code in this repository or its siblings reads the raw manifest, so the export
had no consumer to keep. Nothing is published yet, so no name was burned; if a
real raw-manifest consumer turns up it can be declared then, under a name that
matches the current layout.

./scaffold keeps its name across the cli/templates/templates/ move
(#3596). It names the capability, not the directory, so the move only repoints
its source.

How the export is held

A declared export with nothing asserting it is how the coupling breaks silently —
this branch proved that itself: the directory move would have dropped the entry
with every in-repo test still green, because they all import through relative
paths that moved with it.

  • templates/scaffold-export.test.ts fails if ./scaffold stops being declared,
    if it points at a file that no longer exists, or if the module stops exporting
    the behaviour a caller imports it for.
  • npm-install-smoke.sh step 6 imports the bare specifier from a clean-room
    install and materializes a project through it, so Node resolves it against the
    published exports map. The deep node_modules/veryfront/esm/... paths the
    other steps use bypass that map, so this is the only step that can catch the
    export going missing; without the entry it fails with
    ERR_PACKAGE_PATH_NOT_EXPORTED.

Verification

  • deno lint on a fresh scaffold: clean for all 7 templates (was 9 errors across 3).
  • npm install && npx tsc --noEmit on a fresh scaffold: clean for all 7 (was 11 errors across 3).
  • veryfront build on the rewritten agentic-workflow scaffold succeeds, and the
    workflow module now loads and resolves its steps.
  • A real deno task build:npm emits
    "./scaffold": { "import": "./esm/templates/scaffold.js", "types": "./esm/templates/scaffold.d.ts" },
    the same shape as its siblings, and carries no manifest entry. Deleting that
    entry and re-running the smoke step fails with ERR_PACKAGE_PATH_NOT_EXPORTED,
    so the step is load-bearing.
  • deno task typecheck, deno task lint, deno task fmt:check,
    docs:api-reference:check, the templates/ suite and the CLI unit suite all pass.

Deliberately not done

The investigation suggested dropping the @9.0.3 suffix from the chat starters'
react-markdown / remark-gfm imports on the grounds that "package.json already
pins them, so the suffix buys nothing". Re-checking the pipeline says otherwise:
browser imports are resolved from the specifier, not from package.json
(src/transforms/import-rewriter/strategies/bare-strategy.ts), and package.json
pins only apply behind the dependency-pinning flag, which defaults to a 0%
rollout. Removing the suffix would send every scaffold back to an unversioned
esm.sh URL and re-introduce the per-request "Unversioned import may cause
reproducibility issues" warning that #3438 fixed. I also could not reproduce the
reported no-sloppy-imports error on that specifier with Deno 2.7.12 or the
CI-pinned 2.7.7, in either runtime, before or after install. The scaffold lint
gate added here will now catch it in CI if a future Deno starts flagging it.

Follow-up, in veryfront-api: consume veryfront/scaffold from
create-project.ts and retire the DB blank row as a scaffold source.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kojiwakayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 34d7e4fd-2a75-44c1-b64d-9c385592a929

📥 Commits

Reviewing files that changed from the base of the PR and between 64d6850 and 6a5af54.

📒 Files selected for processing (39)
  • cli/commands/init/config-generator.ts
  • cli/commands/init/deno-config-generator.ts
  • cli/shared/project-creation.ts
  • deno.json
  • docs/api-reference/index.md
  • docs/api-reference/veryfront/scaffold.md
  • docs/api-reference/veryfront/schedule.md
  • docs/api-reference/veryfront/schemas.md
  • docs/api-reference/veryfront/security.md
  • docs/api-reference/veryfront/server.md
  • docs/api-reference/veryfront/skill.md
  • docs/api-reference/veryfront/task.md
  • docs/api-reference/veryfront/testing.md
  • docs/api-reference/veryfront/tool.md
  • docs/api-reference/veryfront/trigger.md
  • docs/api-reference/veryfront/ui.md
  • docs/api-reference/veryfront/utils.md
  • docs/api-reference/veryfront/webhook.md
  • docs/api-reference/veryfront/workflow.md
  • docs/guides/multi-agent.md
  • scripts/docs/generate-api-reference.test.ts
  • scripts/test/npm-install-smoke.sh
  • templates/files/agentic-workflow/app/api/workflows/sample-runs.ts
  • templates/files/agentic-workflow/app/page.tsx
  • templates/files/agentic-workflow/app/workflows/[id]/page.tsx
  • templates/files/agentic-workflow/tools/publish.ts
  • templates/files/agentic-workflow/workflows/content-pipeline.ts
  • templates/files/coding-agent/tools/list-files.ts
  • templates/files/multi-agent-system/README.md
  • templates/files/multi-agent-system/agents/orchestrator.ts
  • templates/files/multi-agent-system/tools/web-search.ts
  • templates/files/saas-starter/app/dashboard/page.tsx
  • templates/files/saas-starter/tools/search.ts
  • templates/manifest.json
  • templates/multi-agent-delegation.test.ts
  • templates/scaffold-export.test.ts
  • templates/scaffold-parity.test.ts
  • templates/scaffold-quality.test.ts
  • templates/scaffold.ts
📝 Walkthrough

Walkthrough

The change centralizes scaffold generation, adds disk-free materialization and public manifest exports, updates starter templates, and expands parity, quality, export, smoke, API-reference, and documentation coverage.

Changes

Scaffold materialization

Layer / File(s) Summary
Centralized scaffold assembly and serialization
cli/commands/init/..., cli/shared/project-creation.ts
Project creation now shares scaffold assembly. Pure builders generate package and Deno configuration.
Public scaffold API and validation
cli/templates/scaffold.ts, cli/templates/scaffold-*.test.ts, docs/api-reference/...
The scaffold API exposes template resolution and in-memory materialization. Tests compare CLI output with materialized output and check template quality.
Manifest exports and reference generation
cli/templates/public-manifest.ts, cli/templates/loader.ts, deno.json, tsconfig.json, cli/templates/manifest-export.test.ts, scripts/docs/..., scripts/test/npm-install-smoke.sh
The typed manifest is published through package mappings. Export, smoke, and API-reference tests cover default imports and manifest contents.
Typed agentic workflow sample
cli/templates/files/agentic-workflow/..., cli/templates/manifest.json
Workflow fixtures and pages now use typed node states. Publishing uses a standalone tool, and workflow input handling narrows unknown values safely.
Other starter template updates
cli/templates/files/coding-agent/..., cli/templates/files/multi-agent-system/..., cli/templates/files/saas-starter/..., cli/templates/manifest.json
Templates update asynchronous directory iteration, declarative agent delegation, synchronous placeholder tools, and explicit button types.
Reference documentation updates
docs/api-reference/index.md, docs/api-reference/veryfront/*.md
The scaffold module is documented, and API reference ordering metadata is incremented for subsequent pages.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant materializeScaffold
  participant ScaffoldAssembly
  participant GeneratedFiles
  Caller->>materializeScaffold: submit template and project options
  materializeScaffold->>ScaffoldAssembly: resolve template and assemble files
  ScaffoldAssembly->>GeneratedFiles: add source, metadata, environment, and .gitignore files
  materializeScaffold-->>Caller: return sorted in-memory files
Loading

Possibly related PRs

Suggested reviewers: kwakayama

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: fixing scaffolded templates and producing a publishable scaffold artifact.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/scaffold-parity-475

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae240152ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cli/shared/project-creation.ts Outdated
Comment thread docs/api-reference/veryfront/scaffold.md Outdated
Comment thread docs/api-reference/veryfront/scaffold.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cli/templates/files/agentic-workflow/app/api/workflows/sample-runs.ts (1)

1-20: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Align DemoWorkflowRun.status with WorkflowStatus.

useWorkflow() exposes nodeStates with the expected NodeState fields. However, the framework uses "waiting", not "waiting_for_approval". Replace that literal and add "cancelled" if this type represents production runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cli/templates/files/agentic-workflow/app/api/workflows/sample-runs.ts` around
lines 1 - 20, Update the DemoWorkflowRun.status union to match WorkflowStatus:
replace "waiting_for_approval" with "waiting" and add "cancelled" so production
run statuses are represented. Leave the DemoNodeStatus and DemoNodeState
definitions unchanged.
🧹 Nitpick comments (1)
cli/templates/scaffold-parity.test.ts (1)

130-133: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the rejection reason for the unknown slug.

assertRejects without an error class or message passes for any rejection. A future unrelated failure inside materializeScaffold would keep this test green. Assert the TEMPLATE_NOT_FOUND error, or at least match the message text.

♻️ Proposed change
-      await assertRejects(() => materializeScaffold({ template: "nope" }));
+      await assertRejects(
+        () => materializeScaffold({ template: "nope" }),
+        Error,
+        'Unknown template "nope"',
+      );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cli/templates/scaffold-parity.test.ts` around lines 130 - 133, Strengthen the
unknown-slug test by updating the assertRejects call in “rejects an unknown slug
instead of scaffolding something else” to verify the TEMPLATE_NOT_FOUND error or
match its expected message, while preserving the existing
resolveScaffoldTemplate assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cli/commands/init/config-generator.ts`:
- Line 78: Validate request.projectName with validateProjectName() at the start
of materializeScaffold(), before assembling the scaffold or assigning the name
metadata, while preserving valid-name behavior. Add a focused test that verifies
materialization rejects an invalid project name before implementation.

In `@cli/shared/project-creation.ts`:
- Around line 656-682: The materializeScaffold flow can append duplicate
generated paths, while the parity test hides them by converting files to a Map.
In cli/shared/project-creation.ts:656-682, update materializeScaffold to remove
or merge existing entries for package.json, .gitignore, .env, and .env.example
before appending generated content, consistent with createPackageJson and
writeGitignore; in cli/templates/scaffold-parity.test.ts:69-85, assert that
materialized files have unique path values before constructing the Map.

In `@cli/templates/manifest.json`:
- Line 90: Update the generated orchestrator setup around getAgentsAsTools so
researcher and writer are registered before the orchestrator module creates its
tools. Preserve the existing delegation descriptions and orchestrator behavior,
while ensuring discovery order cannot leave the delegate-tools registry empty.

In `@docs/api-reference/veryfront/scaffold.md`:
- Around line 49-51: Document the exported types MaterializedScaffold,
MaterializeScaffoldRequest, and TemplateFile in the API reference table with
concise descriptions of their roles and usage, so callers can understand the
scaffold API without consulting implementation files.
- Line 3: Replace the scaffold description in the front matter of
docs/api-reference/veryfront/scaffold.md at lines 3-3 with the concise public
behavior: generate the same project files as veryfront init without writing to
disk. Update the corresponding API index description in
docs/api-reference/index.md at lines 41-41 to use the identical wording; remove
implementation paths and the internal issue reference from both locations.

---

Outside diff comments:
In `@cli/templates/files/agentic-workflow/app/api/workflows/sample-runs.ts`:
- Around line 1-20: Update the DemoWorkflowRun.status union to match
WorkflowStatus: replace "waiting_for_approval" with "waiting" and add
"cancelled" so production run statuses are represented. Leave the DemoNodeStatus
and DemoNodeState definitions unchanged.

---

Nitpick comments:
In `@cli/templates/scaffold-parity.test.ts`:
- Around line 130-133: Strengthen the unknown-slug test by updating the
assertRejects call in “rejects an unknown slug instead of scaffolding something
else” to verify the TEMPLATE_NOT_FOUND error or match its expected message,
while preserving the existing resolveScaffoldTemplate assertion.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3e9c22fb-c2e6-4059-af7f-9c15e2ecc252

📥 Commits

Reviewing files that changed from the base of the PR and between 07683f1 and ae24015.

📒 Files selected for processing (33)
  • cli/commands/init/config-generator.ts
  • cli/commands/init/deno-config-generator.ts
  • cli/shared/project-creation.ts
  • cli/templates/files/agentic-workflow/app/api/workflows/sample-runs.ts
  • cli/templates/files/agentic-workflow/app/page.tsx
  • cli/templates/files/agentic-workflow/app/workflows/[id]/page.tsx
  • cli/templates/files/agentic-workflow/tools/publish.ts
  • cli/templates/files/agentic-workflow/workflows/content-pipeline.ts
  • cli/templates/files/coding-agent/tools/list-files.ts
  • cli/templates/files/multi-agent-system/agents/orchestrator.ts
  • cli/templates/files/multi-agent-system/tools/web-search.ts
  • cli/templates/files/saas-starter/app/dashboard/page.tsx
  • cli/templates/files/saas-starter/tools/search.ts
  • cli/templates/manifest.json
  • cli/templates/scaffold-parity.test.ts
  • cli/templates/scaffold-quality.test.ts
  • cli/templates/scaffold.ts
  • deno.json
  • docs/api-reference/index.md
  • docs/api-reference/veryfront/scaffold.md
  • docs/api-reference/veryfront/schedule.md
  • docs/api-reference/veryfront/schemas.md
  • docs/api-reference/veryfront/security.md
  • docs/api-reference/veryfront/server.md
  • docs/api-reference/veryfront/skill.md
  • docs/api-reference/veryfront/task.md
  • docs/api-reference/veryfront/testing.md
  • docs/api-reference/veryfront/tool.md
  • docs/api-reference/veryfront/trigger.md
  • docs/api-reference/veryfront/ui.md
  • docs/api-reference/veryfront/utils.md
  • docs/api-reference/veryfront/webhook.md
  • docs/api-reference/veryfront/workflow.md

Comment thread cli/commands/init/config-generator.ts
Comment thread cli/shared/project-creation.ts Outdated
Comment thread cli/templates/manifest.json Outdated
Comment thread docs/api-reference/veryfront/scaffold.md Outdated
Comment thread docs/api-reference/veryfront/scaffold.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cli/templates/files/multi-agent-system/agents/orchestrator.ts`:
- Around line 11-13: Add a focused runtime test for the generated
multi-agent-system template in scaffold-quality.test.ts: scaffold and load the
generated agents, stub their execution, then invoke both agent_researcher and
agent_writer and verify delegation wiring works. Keep the existing type-check
and lint coverage unchanged.

In `@cli/templates/scaffold-quality.test.ts`:
- Line 94: Update the REPO_CONFIG initialization to convert the file URL with
fromFileUrl instead of using URL.pathname, then pass the resulting
platform-native path to runCommand.

In `@docs/rfcs/0001-ui-primitive-adapters.md`:
- Line 560: Update the example command in section 6.6 from the unsupported “add”
verb to the documented “generate adapter react-aria” command, while preserving
the existing adapter path and context.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9b71a18f-2857-4a23-a39a-15a291ae3bd9

📥 Commits

Reviewing files that changed from the base of the PR and between ae24015 and cd3f438.

📒 Files selected for processing (11)
  • cli/shared/project-creation.ts
  • cli/templates/files/multi-agent-system/agents/orchestrator.ts
  • cli/templates/manifest.json
  • cli/templates/scaffold-parity.test.ts
  • cli/templates/scaffold-quality.test.ts
  • cli/templates/scaffold.ts
  • docs/api-reference/index.md
  • docs/api-reference/veryfront/scaffold.md
  • docs/guides/head-and-seo.md
  • docs/guides/index.md
  • docs/rfcs/0001-ui-primitive-adapters.md
🚧 Files skipped from review as they are similar to previous changes (5)
  • docs/api-reference/veryfront/scaffold.md
  • docs/api-reference/index.md
  • cli/shared/project-creation.ts
  • cli/templates/manifest.json
  • cli/templates/scaffold.ts

Comment thread templates/files/multi-agent-system/agents/orchestrator.ts
Comment thread cli/templates/scaffold-quality.test.ts Outdated
Comment thread docs/rfcs/0001-ui-primitive-adapters.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/docs/generate-api-reference.test.ts`:
- Around line 373-380: Update the imports in the test containing the
cliReference assertions to use the required assertions from
`#veryfront/testing/assert.ts` instead of `#std/assert`, while preserving the
existing assertStringIncludes and assertEquals checks.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ebc7bea1-8416-4379-91fe-3c29ce205654

📥 Commits

Reviewing files that changed from the base of the PR and between cd3f438 and 6763784.

📒 Files selected for processing (12)
  • cli/templates/files/multi-agent-system/README.md
  • cli/templates/loader.ts
  • cli/templates/manifest-export.test.ts
  • cli/templates/manifest.json
  • cli/templates/public-manifest.ts
  • deno.json
  • docs/api-reference/veryfront/cli.md
  • docs/guides/multi-agent.md
  • scripts/docs/generate-api-reference.test.ts
  • scripts/docs/generate-api-reference.ts
  • scripts/test/npm-install-smoke.sh
  • tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • deno.json
  • cli/templates/manifest.json

Comment thread scripts/docs/generate-api-reference.test.ts Outdated
@kwakayama
kwakayama added this pull request to the merge queue Aug 11, 2026
@kojiwakayama

Copy link
Copy Markdown
Contributor Author

Added: the template manifest is now an exported subpath

While wiring the API side to this PR's scaffold work, a second undeclared
coupling turned up — smaller than #475, but the same shape.

The starter templates ship as data at esm/cli/templates/manifest.js, and
that path was not in the package's exports. The only way to reach it
from outside was to resolve veryfront/cli and hop a relative file URL to
./templates/manifest.js, routing around the exports map that exists to
stop precisely that. Verified against the published veryfront@0.1.1229
tarball: the file is there, the export entry is not.

The undeclared part is what bites. If this repository changed its build
output layout, the consumer would break at runtime and nothing here would
fail, because nothing here knew anyone depended on the path — an unversioned,
unenforced dependency between two repos, which is issue #475's own defect one
size down.

The export

veryfront/cli/templates/manifestcli/templates/public-manifest.ts,
declared in deno.json exports (the source the npm build derives
package.json exports from) plus the matching imports and
tsconfig.json paths entries.

It is a thin re-export, so the manifest is still emitted once — the wrapper
is 3 lines of runtime code. It also replaces the 26KB literal type dnt infers
from the JSON with a declared TemplateManifest, and loader.ts now reads
the manifest through the same module so the CLI and external consumers cannot
end up with different views of it.

It cannot be named manifest.ts: dnt compiles manifest.json to
manifest.js in the same directory and the two would emit over each other.
That is pinned by a test rather than left as a comment.

The enforcement, which is the actual point

  • cli/templates/manifest-export.test.ts — fails if the subpath stops
    being declared, if it starts compiling over the JSON module, or if the
    manifest stops carrying every starter with a non-empty files map. Written
    first; confirmed red with ./cli/templates/manifest is not exported.
  • scripts/test/npm-install-smoke.sh step 6 — imports the bare
    specifier
    from a clean-room install, so Node resolves it through the
    published exports map. The deep node_modules/veryfront/esm/... paths the
    other steps use bypass that map, so this is the only step that can catch the
    export going missing.

Both were checked as real gates, not passing assertions. With the entry
removed from a built package, the smoke check fails with
ERR_PACKAGE_PATH_NOT_EXPORTED: Package subpath './cli/templates/manifest' is not defined by "exports" — the exact failure a consumer relying on the
relative hop would never have produced here.

Proven end-to-end against a real deno task build:npm: the emitted
package.json carries
"./cli/templates/manifest": {"import": "./esm/cli/templates/public-manifest.js", "types": ".../public-manifest.d.ts"},
the same shape as ./cli; manifest.js (994KB) and the 1.6KB wrapper coexist
with no collision; and the full npm-install-smoke.sh passes all 7 checks.
tests (npm install smoke) is green in CI here.

Also in this push

  • cli/templates/multi-agent-delegation.test.ts — the runtime gate
    CodeRabbit asked for on the orchestrator. It loads the template's own agent
    modules coordinator-first (the order that broke it) and asserts the delegate
    tools exist and resolve. Verified against the pre-fix orchestrator: fails
    with [] against ["agent_researcher", "agent_writer"].
  • fromFileUrl for the scaffold gate's repo-config path (Windows).
  • Assertions in generate-api-reference.test.ts moved to the repo's testing
    module per AGENTS.md:251.
  • The API-reference generator emitted import { default } from ... for the
    new default export, which does not compile. It now renders a default export
    as a default binding, covered by a test.

Out of scope, worth its own issue

manifest.js is ~992KB and ships in every install of veryfront for
something only the scaffold path uses. That is pre-existing — 0.1.1228 and
0.1.1229 both unpack to ~27MB — so I have deliberately not touched it here.
Making it lazy or moving it behind a separate package is a real win but a
separate change with its own risk.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 11, 2026
…ne artifact

A new project is supposed to install, run and build with zero errors and zero
lint errors (veryfront-issue-inbox #475). Three of the seven starters did not:

  agentic-workflow    6 tsc errors, 5 lint errors
  coding-agent        4 tsc errors
  multi-agent-system  1 tsc error, 1 lint error
  saas-starter        3 lint errors

The worst was `agentic-workflow`. Its `publish` step passed an `execute`
callback, which `StepOptions` does not accept: `tsc` rejected the object
literal and `step()` throws "must specify either 'agent' or 'tool'" the moment
the workflow runs, so the template's headline feature could never execute.
That step now calls a real `tools/publish.ts`, and the run view renders
`run.nodeStates` — the field `WorkflowRun` actually has — instead of a
`steps` array that only the demo API invented.

The rest were ordinary defects nobody could see: `readDir` streams entries but
`list-files` filtered it like an array; `getAgentsAsTools` takes a description
map, not a list of ids; four `async` callbacks never awaited anything; three
`<button>`s had no `type`.

None of this was caught because the templates are real files that the repo's
own lint and typecheck never look at. `cli/templates/scaffold-quality.test.ts`
closes that: it scaffolds every starter the way `veryfront init` does and runs
the same `deno lint` that `veryfront lint` shells out to, expecting silence.
It fails on the three templates above before this change.

The second half of #475 is that a project created in Studio must be identical
to one created by the CLI. It could not be: the hosted flow copies a stored
project row, which has no repo, no lint gate and no link to the release train,
so it froze at the pages-router era while these templates moved on. This adds
the artifact that makes one source possible — `veryfront/scaffold` exports
`materializeScaffold()`, which returns the complete contents of a new project
without touching a disk, and maps Studio's `blank` slug onto the CLI's
`minimal` starter. `createProject` now assembles through the same function it
exposes, so the two cannot disagree, and `scaffold-parity.test.ts` proves it
by diffing a really-scaffolded directory against the materializer's output for
every template rather than against a snapshot a future template change would
silently invalidate.

Consuming it from veryfront-api, and retiring the DB 'blank' row, is the
follow-up this unblocks.
The lint gate would not have caught the worst of what shipped: `step()`
handed an `execute` callback `StepOptions` does not accept,
`getAgentsAsTools` a list of ids where it takes a description map, and
`readDir`'s async iterable filtered like an array. All three are type
errors a user meets on their first `npm run typecheck`, and all three
were invisible because `cli/templates/files/` is excluded from the
workspace so the repo never type-checks it either.

Scaffolding to a temp directory escapes that exclusion, so the gate now
also `deno check`s each scaffold's agents, tools and workflows against
the framework's own declarations. It fails for agentic-workflow,
multi-agent-system and coding-agent before the template fixes.
…r its users

Review follow-ups on the new `veryfront/scaffold` export.

`createProject()` rejects an empty or path-bearing project name through
`validateProjectName()`; `materializeScaffold()` passed the same value
straight into `package.json#name`. Two creation paths that disagree about
what a valid project is are exactly the drift this surface exists to
prevent, so the materializer now runs the same validation.

The published module description also read like an internal changelog -
source-tree paths and an issue number - and its example called an
undefined `store()`. Both now say what the module does for the person
importing it, with an example that runs as written.
Review follow-ups.

multi-agent-system's orchestrator built its delegate tools with a
top-level `getAgentsAsTools()`. Discovery loads `agents/orchestrator.ts`
before `researcher.ts` and `writer.ts`, so that call ran against an
empty registry and the coordinator shipped with no one to coordinate -
in the template whose whole subject is delegation. `delegates` is the
API for this: each id becomes an `agent_<id>` tool resolved when the run
happens, so load order cannot matter.

`materializeScaffold()` also appended `package.json` and `.gitignore`
without looking at what the template already had at those paths. No
template ships either today, but one that did would have produced two
entries for one path while the CLI merged them - and the parity test
could not see it, because it collapsed the array into a Map first. The
materializer now keys by path and merges exactly where the CLI merges,
and the test rejects a repeated path instead of hiding it.
The generated reference listed `MaterializeScaffoldRequest` and
`MaterializedScaffold` with empty descriptions, so a caller had to open
the implementation to learn what either one is.
The multi-agent guide showed the same broken shape the template had: an
`agents/orchestrator.ts` whose `tools` came from a top-level
`getAgentsAsTools()`. Under discovery that call runs before the agents it
is meant to wrap exist, so anyone following the guide built a
coordinator with no delegates - and had no way to see it except an agent
that never delegates.

The example now names its delegates, and the paragraph after it says why,
so the trap is documented rather than reproduced. `agentAsTool()` keeps
its section, where the caller registers the agents and owns the order.
A `deno fmt docs/` reflowed three files this branch never touched. The
repo's format gate covers src/, cli/ and react/, not docs/, so the churn
was mine and not the gate's.
`URL.pathname` yields `/C:/repo/deno.json` on Windows, which `deno check`
and `deno lint` cannot open, so the scaffold quality gate would fail there
for a reason unrelated to the templates it grades. `fromFileUrl` gives the
platform-native path.
The multi-agent template's headline defect was that its coordinator shipped
with no one to coordinate, and nothing in the repo could see it: `deno check`
and `deno lint` in scaffold-quality.test.ts grade syntax and types, and both
were happy with a coordinator wired to nothing, while the delegation tests
under src/agent use synthetic agents and never touch this template.

This loads the template's own agent modules in the order discovery uses -
orchestrator first, which is what broke it - and asserts the delegate tools
exist, that each resolves to the specialist the template registers, and that
a delegate run hands that agent to the executor. Execution is stubbed; the
wiring is the subject.

Checked against the pre-fix orchestrator: the first case fails with `[]`
against `["agent_researcher", "agent_writer"]`, which is exactly the
empty-registry bug.
AGENTS.md asks for assertions from `#veryfront/testing/assert.ts`; this file
predated that and pulled them from `#std/assert`. `#veryfront/` resolves to
`../src/` under scripts/test.deno.json, so the same three assertions come
from the repo's own module with no other change.
…olds it

Rebased onto the `cli/templates/` -> `templates/` move (#3596). `./scaffold`
keeps its name - it names the capability, not the directory - and now points
at `./templates/scaffold.ts`.

The second export this branch declared, `./cli/templates/manifest`, is gone.
The manifest is data; `materializeScaffold()` is the behaviour. A consumer
reading the manifest has to reimplement package.json generation, AGENTS.md
injection and .gitignore for itself - a second scaffolder fed from one data
source, which is issue #475 one level down. veryfront-api will call
`materializeScaffold()`, and nothing in this repository or its siblings reads
the raw manifest, so the export had no consumer to keep. Nothing is published
yet, so no name was burned.

The enforcement stays, retargeted:

- `templates/scaffold-export.test.ts` fails if `./scaffold` stops being
  declared, if it points at a file that no longer exists - the exact failure
  the directory move would have caused - or if the module stops exporting the
  behaviour a caller imports it for.
- `npm-install-smoke.sh` step 6 imports the bare specifier from a clean-room
  install and materializes a project through it, so Node resolves it against
  the published `exports` map. The deep `node_modules/veryfront/esm/...` paths
  the other steps use bypass that map, so this is the only step that can catch
  the export going missing; without the entry it fails with
  ERR_PACKAGE_PATH_NOT_EXPORTED.

`scaffold-quality.test.ts` reached the repo config through `../../deno.json`,
which resolves above the repository now that the file sits one level higher;
every template's type-check step failed on the missing config until it was
repointed at `../deno.json`.
@kojiwakayama
kojiwakayama force-pushed the fix/scaffold-parity-475 branch from 8ee0362 to f1d5ba6 Compare August 11, 2026 20:48
`exports` is indexed under `noUncheckedIndexedAccess`, so the subpath lookup
is `string | undefined` and `deno check` rejected the `.replace()` on it. The
assertion that follows already had to exist for the failure message to name
the missing subpath rather than report a null dereference.
@kojiwakayama
kojiwakayama added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit 49c5246 Aug 11, 2026
35 checks passed
@kojiwakayama
kojiwakayama deleted the fix/scaffold-parity-475 branch August 11, 2026 22:14
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