Skip to content

feat(wren): GenBI app build & deploy — semantic layer → shareable web app#2348

Merged
goldmedal merged 19 commits into
mainfrom
worktree-deploy-app
Jun 11, 2026
Merged

feat(wren): GenBI app build & deploy — semantic layer → shareable web app#2348
goldmedal merged 19 commits into
mainfrom
worktree-deploy-app

Conversation

@PaulChen79

@PaulChen79 PaulChen79 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

What

Adds a GenBI app build & deploy pipeline to the wren CLI: turn a Wren project's semantic layer into a shareable, browser-side GenBI web app and deploy it to the user's Vercel or Cloudflare account — from a natural-language request to a public URL in one conversation.

Design: CLI ↔ agent split

  • The CLI owns all deterministic state — the authoritative build instruction, the app index, verify, and deploy.
  • The agent authors the app code, following the CLI's build instruction. .wren/apps.yml is only ever written by the CLI, never hand-edited.

New CLI surface (wren genbi)

Command Purpose
wren genbi build <name> --prompt "…" [--data-mode snapshot|live] Print a project-hydrated build instruction (wasm wiring with pinned wren-core-wasm version, the project's model/column inventory, data-mode guidance, acceptance criteria, target folder). Writes nothing to disk.
wren genbi register / list / remove Machine-written app index.
wren genbi verify <name> Deterministic deploy preflight.
wren genbi open <name> Local preview.
wren genbi deploy <name> --provider vercel|cloudflare [--prod] Deploy and return a shareable URL.

Data modes

  • snapshot (default) — data is bundled with the app as parquet/duckdb and queried client-side. Fully serverless.
  • live — the app calls back to the user's warehouse/API at view time. Requires a CORS-enabled endpoint.

Security

  • Secret-leak gateverify fails the app if credentials are inlined into app files, and deploy refuses to ship it (the deploy target is a public static host).
  • No tokens on the command lineVERCEL_TOKEN / CLOUDFLARE_API_TOKEN (and CLOUDFLARE_ACCOUNT_ID) are discovered from the environment or .env, never passed as flags.
  • Production deploys are preview-by-default; --prod is explicit.

Skill

Ships a genbi-app agent workflow guide. Per main's new model (skills served from the CLI, with skills/wren/ as the only external discovery stub), the guide lives at core/wren/src/wren/skills_content/genbi-app/SKILL.md and is served via wren skills get genbi-app — no separate skills/ directory, no version drift.

Tests

  • Unit tests for build, deploy, index, and verify (core/wren/tests/unit/test_genbi_*.py).
  • End-to-end walkthrough script core/wren/scripts/genbi-e2e.sh.
  • The existing served-content guard and skill-stub guards pass with genbi-app added to the bundled set.

Notes

This branch also merges main (0.9.0) and aligns the GenBI skill with main's "skills served from the CLI" architecture (#2329).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a full wren genbi command suite: build (composes agent instructions), register/list/remove, verify, open (local HTTP preview), and deploy to Vercel or Cloudflare. Token lookup supports env/project .env fallbacks.
  • Bug Fixes / Safety

    • Strict app-name validation and structural/security preflight checks to prevent path traversal and inline-secret leakage.
  • Documentation

    • New GenBI workflow guide and updated skill/manifest entries.
  • Tests

    • Extensive unit tests covering build, index, verify, deploy, and provider flows.
Screen.Recording.2026-06-10.at.9.05.10.AM.mov
Screen.Recording.2026-06-10.at.9.06.39.AM.mov

PaulChen79 and others added 8 commits June 3, 2026 09:53
…poser

Slice 01 of the GenBI app build & deploy feature. `wren genbi build <name>
--prompt …` is a pure prompt composer: it prints an authoritative build
instruction (wasm wiring know-how + live project context + the user's
verbatim prompt) to stdout and writes nothing to disk. The agent authors
the app from scratch into apps/<name>/ following the instruction.

- BuildInstructionComposer: pure function; pinned wren-core-wasm version,
  CDN-load directive, model/column inventory, snapshot data guidance,
  register/verify final steps
- --prompt / --prompt-file / stdin ('-') prompt inputs
- implicit `context build` when target/mdl.json is missing
- behavior tests via CliRunner + scripts/genbi-e2e.sh (installs local CLI
  and asserts real CLI behavior end-to-end)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Slice 02 of the GenBI app build & deploy feature. A Wren project can hold
multiple GenBI apps, tracked in .wren/apps.yml — the deterministic input
contract for deploy. The index is machine-written via `wren genbi register`
(never hand-rolled YAML), mirroring the profiles.yml registry pattern.

- AppIndex module: load/save/register/remove, status state machine
  (scaffolded → built → deployed), no secrets ever stored
- register requires the app dir to exist on disk; idempotent updates
- list shows data mode / status / deploy URL; remove keeps files on disk
- behavior tests via CliRunner + e2e harness slice-02 section

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…preview

Slice 03 of the GenBI app build & deploy feature. `verify` is the quality
gate before deploy: structural checks (index.html present, mdl.json parses
and is non-empty, snapshot apps bundle a *.parquet/*.duckdb data asset)
with clear failure reasons; success flips index status scaffolded → built.
`open` serves a registered app on localhost for visual preview.

A browser-based wasm smoke query is deliberately deferred — the verifier
stays deterministic and CI-safe.

- AppVerifier returns structured pass/fail; status never flips on failure
- e2e: incomplete app rejected, completed app passes, `open` curl smoke

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…fy gate

Slice 04 of the GenBI app build & deploy feature. One command from a
verified app on disk to a shareable Vercel URL.

- TokenResolver: 3-tier discovery (env var → merged .env files → project
  .env); tokens are never accepted as CLI flags and never persisted
- DeployProvider protocol + provider registry; Vercel adapter uploads via
  the v13 REST API (inline base64 files, Authorization header only)
- deploy runs verify as preflight and aborts before any upload on failure
- preview by default, --prod for production; per-app deploy state
  (provider, project/org id, last URL, environment) persisted in the index
- mocked-transport tests assert request construction (endpoint, auth
  header, file set, target) and that no secret reaches apps.yml
- e2e: token-missing, unknown-provider, and verify-abort error paths

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Slice 05 of the GenBI app build & deploy feature. Second DeployProvider
adapter, proving the abstraction: no changes to the deploy command,
TokenResolver, or index logic — just a new adapter in the registry.

- Cloudflare Pages Direct Upload (ensure project, then create deployment)
- CLOUDFLARE_API_TOKEN via the shared 3-tier resolver; account_id from
  persisted link state or CLOUDFLARE_ACCOUNT_ID with an actionable error
- 403 responses surface a Pages:Edit scope hint
- mocked-transport tests assert account-scoped endpoint, bearer header,
  persisted account_id/url; e2e covers token/account-id error paths

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Slice 06 of the GenBI app build & deploy feature. Live mode becomes
usable end-to-end while a credential-leaking app can never reach a
public URL.

- composer live block: endpoint-only connection config, CORS requirement
  surfaced, hard rule — credentials MUST NEVER be inlined
- AppVerifier scans text files for inlined secrets (connection-string
  passwords, AWS access keys, password/secret/token assignments) and
  fails with the offending file; runs for every data mode since all
  GenBI apps ship to public static hosts
- live apps don't require a bundled data asset; deploy inherits the gate
  via its verify preflight
- e2e: clean live app passes, secret-bearing app blocked at verify and
  at deploy

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d & deploy

Slice 07 of the GenBI app build & deploy feature. The companion skill that
ties the flow together: a user asks for a dashboard in natural language and
the agent drives build → author → register → verify → deploy to a URL.

- SKILL.md mirrors the skills/ + cli split: the CLI owns the authoritative
  build instruction and all deterministic state; the skill encodes the
  workflow, app-name/data-mode resolution, fix-and-re-verify loop, and
  safety boundaries (no inlined secrets, no tokens on argv, confirm --prod,
  never hand-edit .wren/apps.yml)
- registered in skills/index.json
- e2e: validates every quick-ref command against the real CLI and runs the
  full documented walkthrough to a verified app

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sync the 0.9.0 line from main, whose headline change (#2329) moves the
agent skills out of skills/wren-*/ and serves them from the CLI
(`wren skills get <name>`), leaving skills/wren/ as the only external
discovery stub.

Conflict resolution + architecture alignment:
- skills/index.json: take main's version (only the `wren` discovery stub;
  guard test requires names == ["wren"]).
- core/wren/src/wren/cli.py: auto-merged — genbi sub-app registration kept
  alongside main's new docs/ask/cube/utils/skills sub-apps.
- Migrate the worktree's wren-genbi-app skill into the CLI-served model:
  skills/wren-genbi-app/SKILL.md -> core/wren/src/wren/skills_content/genbi-app/SKILL.md
  (frontmatter name genbi-app, drop version field per served-skill convention).
- skills/wren/SKILL.md: list `wren skills get genbi-app` in the stub.
- test_skills_cli.py: add genbi-app to ALL_SKILLS.
- genbi-e2e.sh: verify the guide via `wren skills get genbi-app` instead of
  the removed skills/ path.
- uv.lock: editable wren version reconciled 0.8.0 -> 0.9.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file python Pull requests that update Python code core skills labels Jun 8, 2026
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR introduces the complete GenBI feature for building and deploying LLM-generated web applications from Wren semantic layers. It adds a wren genbi CLI subcommand group with build, register, list, remove, verify, open, and deploy commands; implements Vercel and Cloudflare deployment adapters; manages app state in .wren/apps.yml; composes build instructions for LLM agents; validates apps with security gates; and includes comprehensive unit tests and skill documentation.

Changes

GenBI Build & Deployment Feature

Layer / File(s) Summary
Deployment provider interface and implementations
core/wren/src/wren/genbi/providers/base.py, core/wren/src/wren/genbi/providers/vercel.py, core/wren/src/wren/genbi/providers/cloudflare.py, core/wren/src/wren/genbi/providers/__init__.py
Defines the DeployProvider protocol, Deployment and DeployError types; implements Vercel adapter (v13 Deployments API with file collection and bearer auth) and Cloudflare adapter (Pages via wrangler CLI with account scoping); provides a factory to instantiate providers by name.
App index and state management
core/wren/src/wren/genbi/index.py
Implements YAML-based app registry at .wren/apps.yml with CRUD operations: register_app, get_app, update_app, remove_app; handles schema versioning, status transitions (scaffolded/built/deployed), and error handling for malformed YAML.
Build instruction composition
core/wren/src/wren/genbi/composer.py
Generates markdown build instructions for LLM agents, embedding MDL/target paths, wren-core-wasm pinned version, data-mode-specific guidance (snapshot vs. live), model inventory from project metadata, acceptance criteria and next CLI steps.
App verification and security gates
core/wren/src/wren/genbi/verify.py
Implements structural validation: checks app directory, index.html, and mdl.json existence/validity; enforces snapshot-mode data asset requirements; scans files for inlined credentials/secrets using regex patterns; returns VerifyResult with pass/fail and failure details.
Token discovery and resolution
core/wren/src/wren/genbi/tokens.py
Implements 3-tier token lookup: process environment → standard .env sources via profile module → explicit project .env file; returns None when absent and gracefully handles missing python-dotenv.
GenBI command suite
core/wren/src/wren/genbi/cli.py
Defines genbi_app Typer sub-application with commands: build, register, list, remove, verify, open, and deploy; includes helpers for project discovery, prompt resolution, app name validation (slug regex), and registered app lookup.
CLI main entry point integration
core/wren/src/wren/cli.py
Registers genbi_app into the main Wren CLI via app.add_typer(genbi_app), making wren genbi subcommand group available.
Build command unit tests
core/wren/tests/unit/test_genbi_build.py
Tests wren genbi build: instruction composition without side effects, model inventory inclusion, WASM/CDN guidance, data-mode output (snapshot vs. live), prompt handling (file/stdin), implicit MDL compilation, unknown data-mode rejection, and path-traversal name validation.
Index management unit tests
core/wren/tests/unit/test_genbi_index.py
Tests wren genbi register, list, remove: .wren/apps.yml persistence, listing with metadata, missing index handling, entry deletion, YAML validation errors, and path-traversal security.
Verification and local preview unit tests
core/wren/tests/unit/test_genbi_verify.py
Tests wren genbi verify and open: successful verification with status flipping (scaffolded→built), preflight failures (missing/invalid artifacts, missing data assets), security rejection of inlined secrets (config.js, settings.json, index.html), live-mode exemptions, and unregistered app errors.
Deployment provider unit tests
core/wren/tests/unit/test_genbi_deploy.py
Tests wren genbi deploy: token resolution tiering (env → project .env), Vercel/Cloudflare request construction and state persistence, missing token errors with guidance, verification abort on broken artifacts, missing URL validation, and unknown provider errors.
GenBI skill guide and bundled content
core/wren/src/wren/skills_content/genbi/SKILL.md, skills/index.json, skills/wren/SKILL.md, core/wren/tests/unit/test_skills_cli.py, core/wren/src/wren/skills_content/dlt-connector/SKILL.md
Adds end-to-end GenBI workflow guide covering CLI-driven process, data modes, app conventions, deployment prerequisites, Vercel/Cloudflare token handling, safety boundaries; updates skill discovery metadata and integrates GenBI as follow-up from dlt-connector; updates bundled skills test to include genbi.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant GenbiCLI
  participant Verifier
  participant Provider
  participant AppIndex
  User->>GenbiCLI: wren genbi deploy <name> --provider <p> --prod?
  GenbiCLI->>Verifier: verify_app(app_dir, data_mode)
  Verifier-->>GenbiCLI: VerifyResult (passed/fail)
  GenbiCLI->>Provider: deploy(build_dir, app_name, token, prod, link)
  Provider-->>GenbiCLI: Deployment(url, environment, ids)
  GenbiCLI->>AppIndex: update_app(name, deployment metadata)
  GenbiCLI-->>User: prints deployed URL or error
Loading

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • goldmedal

"🐰 I stitched the build and deploy trail,
With Vercel stamps and Wrangler's sail,
I scanned for secrets, kept tokens out of sight,
Verified the app before it took flight,
Hop, deploy — the dashboard shines tonight!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title directly and specifically describes the main feature being added: the GenBI app build and deploy pipeline that transforms a Wren semantic layer into a shareable web app.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-deploy-app

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 10

🤖 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 `@core/wren/scripts/genbi-e2e.sh`:
- Around line 161-169: The test currently background-launches the server via the
genbi "open" command and then blindly sleeps 2s (see the genbi open ... &
snippet and OPEN_PID, WORK/open.out, URL variables); replace that sleep with a
bounded readiness loop that repeatedly extracts the URL from WORK/open.out (same
grep used to set URL) and attempts a lightweight HTTP probe (curl -sf) until
success or a configurable timeout (e.g., 30s) with a short sleep interval (e.g.,
0.5–1s) between attempts; on timeout, kill OPEN_PID and fail the test, and on
success continue as before. Ensure you update references to URL after each grep
attempt inside the loop so the probe uses the freshly discovered port.

In `@core/wren/src/wren/genbi/cli.py`:
- Around line 42-63: User-supplied app names can contain path traversal (e.g.,
"../") and are being path-joined directly in
build/register/verify/open_app/deploy, allowing escapes from the project's apps
directory; replace those joins by calling a central resolver (e.g.,
_resolve_app_dir(project_path, name)) that constructs project_apps =
project_path / "apps", resolves the resulting path, verifies it is a child of
project_apps (path.resolve().startswith(project_apps.resolve())), and raises a
typer.BadParameter (or ValueError caught and re-raised as typer.BadParameter)
for invalid or empty names; update build, register, verify, open_app, and deploy
to use _resolve_app_dir(project_path, name) instead of direct joins and ensure
all callers handle the raised error appropriately.

In `@core/wren/src/wren/genbi/index.py`:
- Around line 28-36: load_index currently assumes the YAML file is a mapping and
will crash on malformed `.wren/apps.yml`; wrap the yaml.safe_load call in a
try/except that catches yaml.YAMLError (and other parsing exceptions) and
validate that the returned data is a dict before calling setdefault; if parsing
fails or data is not a mapping, raise a clear, user-actionable ValueError (or a
custom error) that mentions the offending path (use index_path(project_path))
and advises the file is malformed, otherwise proceed to set default
"schema_version" and "apps" and return the dict; keep references to load_index,
index_path, and INDEX_SCHEMA_VERSION when implementing this.

In `@core/wren/src/wren/genbi/providers/cloudflare.py`:
- Around line 92-97: The code currently fabricates a deployment URL with
f"https://{app_name}.pages.dev" when result["url"] is missing; stop this by
removing the fallback and propagate the missing URL instead (e.g., set url =
result.get("url") or None) so upstream can detect/fail on missing data; update
the Deployment construction in the same block (the usage of url, environment,
account_id) and ensure any callers of Deployment (or code that expects a
non-empty url) handle a None/empty url rather than relying on a fabricated
pages.dev address.
- Around line 34-38: The dict comprehension that reads file bytes from build_dir
must skip symlinks and ensure resolved paths stay inside build_dir to prevent
exfiltration; update the comprehension/filter around rglob("*") to only include
entries where p.is_file() and not p.is_symlink() and where p.resolve() is under
build_dir (e.g., use p.resolve().is_relative_to(build_dir) or fall back to a
safe prefix compare of str(p.resolve()) against str(build_dir.resolve()) +
os.sep), then call p.read_bytes() only for those validated paths so
base64.b64encode(...) never reads files outside build_dir.

In `@core/wren/src/wren/genbi/providers/vercel.py`:
- Around line 70-73: The code currently defaults raw_url = data.get("url", "")
which leads to producing "https://" when the URL is missing; update the provider
code that constructs raw_url (the variable raw_url in vercel.py) to validate
presence and format of data["url"] before returning the Deployment: if
data.get("url") is missing or empty, raise an explicit error (e.g.,
ValueError/RuntimeError) or return a clear failure instead of defaulting to "",
and only build the Deployment(url=...) with the https:// prefix when raw_url is
non-empty and does not already start with "http"; ensure this check happens
right before the Deployment(...) call so the code never persists or returns
"https://".
- Around line 30-37: The file-collection loop in vercel.py allows symlink
traversal because path.is_file() and path.read_bytes() follow symlinks; prevent
exfiltration by skipping symlinks or verifying resolved targets are inside the
build_dir. In the for path in sorted(build_dir.rglob("*")) loop (the block that
appends to files), add a check to skip path if path.is_symlink() (or resolve the
path and ensure path.resolve().relative_to(build_dir.resolve()) succeeds inside
a try/except) before calling read_bytes(), so only regular files under build_dir
are read and encoded.

In `@core/wren/src/wren/genbi/verify.py`:
- Around line 68-100: verify_app currently ignores unknown data_mode values; add
an explicit validation of the data_mode parameter (in the verify_app function)
against the supported set (at minimum the existing "snapshot" mode) and treat
any other value as a verification failure: append a clear failure like
"unsupported data_mode: {data_mode}" to failures and return VerifyResult(False,
failures) early. Ensure you reference the same VerifyResult return type and
place the check after the app_dir existence checks (before the existing if
data_mode == "snapshot": block) so unsupported modes are rejected
deterministically.

In `@core/wren/src/wren/skills_content/genbi-app/SKILL.md`:
- Around line 51-55: The sentence in SKILL.md that currently says the build
"writes nothing to disk" conflicts with earlier text that the tool may
implicitly compile target/mdl.json; update the wording to scope the side-effect
(e.g., state that the command performs no writes to the app/index or app bundle
but may implicitly generate/compile target/mdl.json when missing). Edit the
paragraph around the long-prompt instructions to explicitly mention the implicit
target/mdl.json compilation behavior and clarify that only that metadata file
may be created, while no application bundle/app index files are written.

In `@core/wren/tests/unit/test_genbi_deploy.py`:
- Around line 54-57: The test assumes no external dotenv/profile fallbacks but
only deletes the VERCEL_TOKEN env var; make it hermetic by also isolating
filesystem and disabling dotenv/profile loaders: in
test_token_absent_returns_none (and the other affected tests) unset VERCEL_TOKEN
via monkeypatch.delenv, then set HOME and XDG_CONFIG_HOME to tmp_path with
monkeypatch.setenv(str(tmp_path)), and monkeypatch any dotenv/profile loader to
a no-op (e.g., monkeypatch.setattr("dotenv.load_dotenv", lambda *a, **k: False,
raising=False)) so resolve_token is forced to consult only the controlled
environment; apply the same pattern around resolve_token calls in the other test
blocks.
🪄 Autofix (Beta)

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

Run ID: 1643c895-5504-4554-bdeb-7f3a91c5e17c

📥 Commits

Reviewing files that changed from the base of the PR and between 5fd8870 and 9bd7196.

⛔ Files ignored due to path filters (1)
  • core/wren/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (19)
  • core/wren/scripts/genbi-e2e.sh
  • core/wren/src/wren/cli.py
  • core/wren/src/wren/genbi/__init__.py
  • core/wren/src/wren/genbi/cli.py
  • core/wren/src/wren/genbi/composer.py
  • core/wren/src/wren/genbi/index.py
  • core/wren/src/wren/genbi/providers/__init__.py
  • core/wren/src/wren/genbi/providers/base.py
  • core/wren/src/wren/genbi/providers/cloudflare.py
  • core/wren/src/wren/genbi/providers/vercel.py
  • core/wren/src/wren/genbi/tokens.py
  • core/wren/src/wren/genbi/verify.py
  • core/wren/src/wren/skills_content/genbi-app/SKILL.md
  • core/wren/tests/unit/test_genbi_build.py
  • core/wren/tests/unit/test_genbi_deploy.py
  • core/wren/tests/unit/test_genbi_index.py
  • core/wren/tests/unit/test_genbi_verify.py
  • core/wren/tests/unit/test_skills_cli.py
  • skills/wren/SKILL.md

Comment thread core/wren/scripts/genbi-e2e.sh Outdated
Comment thread core/wren/src/wren/genbi/cli.py Outdated
Comment thread core/wren/src/wren/genbi/index.py
Comment thread core/wren/src/wren/genbi/providers/cloudflare.py Outdated
Comment thread core/wren/src/wren/genbi/providers/cloudflare.py Outdated
Comment thread core/wren/src/wren/genbi/providers/vercel.py Outdated
Comment thread core/wren/src/wren/genbi/providers/vercel.py Outdated
Comment thread core/wren/src/wren/genbi/verify.py
Comment thread core/wren/src/wren/skills_content/genbi/SKILL.md Outdated
Comment thread core/wren/tests/unit/test_genbi_deploy.py
PaulChen79 and others added 2 commits June 8, 2026 16:44
…t handoff

Adjustments to make the GenBI workflow agent-drivable from natural language:

- Rename the served skill genbi-app → genbi (`wren skills get genbi`):
  skills_content/genbi-app/ → genbi/, frontmatter name, ALL_SKILLS,
  discovery-stub guide line, and the e2e walkthrough.
- Discovery stub (skills/wren/SKILL.md + index.json): add genbi/dashboard/
  app/deploy trigger words (incl. zh) to the `description` so an agent loads
  the wren skill on "build a dashboard / 把語意層變成 app" intents, and lists
  `wren skills get genbi`.
- genbi guide: document the Vercel Deployment Protection 401 trap (default-on
  Vercel Authentication; disable at Settings → Deployment Protection) and tell
  the agent to verify the deployed URL actually loads before calling it
  shareable.
- genbi guide: add a "Snapshot data export" section with a DuckDB→parquet
  recipe and clarify the data-origin handoff — SaaS data comes via the
  dlt-connector skill (its .duckdb output is the snapshot source).
- dlt-connector guide: bidirectional handoff — point to `wren skills get
  genbi` as the next step to share the loaded data as an app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Not wired into CI (wren-ci.yml runs pytest only), so it provided no
automated protection — only ad-hoc value when run by hand. The genbi
unit tests (test_genbi_*.py) cover the logic; dropping the unmaintained
manual e2e walkthrough rather than letting it rot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot 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.

♻️ Duplicate comments (1)
core/wren/src/wren/skills_content/genbi/SKILL.md (1)

51-55: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

The disk-write statement still contradicts earlier text.

Lines 26-27 state that wren genbi build "compiles it implicitly" when target/mdl.json is missing, but lines 54-55 claim it "writes nothing to disk." This past review concern remains unaddressed.

📝 Suggested clarification
-For long or multi-line prompts use `--prompt-file <file>` or pipe to
-`--prompt -`. The command prints the authoritative build instruction —
-wasm wiring (pinned version, CDN load), the project's model/column inventory,
-data-mode guidance, acceptance criteria, and the target folder. It writes
-nothing to disk.
+For long or multi-line prompts use `--prompt-file <file>` or pipe to
+`--prompt -`. The command prints the authoritative build instruction —
+wasm wiring (pinned version, CDN load), the project's model/column inventory,
+data-mode guidance, acceptance criteria, and the target folder. It does not
+write app files or `.wren/apps.yml` (it may compile `target/mdl.json` if missing).
🤖 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 `@core/wren/src/wren/skills_content/genbi/SKILL.md` around lines 51 - 55, The
documentation contradicts itself: the section describing "wren genbi build" must
be clarified so it consistently states whether the command writes files when it
"compiles it implicitly" due to a missing target/mdl.json; update SKILL.md to
either (A) state that "wren genbi build" will perform an implicit compile and
write the compiled artifacts (e.g., target/mdl.json and wasm wiring) to disk, or
(B) state that it only compiles in-memory and prints the authoritative build
instruction to stdout without writing any files; ensure the phrasing around
"wren genbi build", "target/mdl.json", and the sentence "It writes nothing to
disk." is made consistent and unambiguous.
🤖 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.

Duplicate comments:
In `@core/wren/src/wren/skills_content/genbi/SKILL.md`:
- Around line 51-55: The documentation contradicts itself: the section
describing "wren genbi build" must be clarified so it consistently states
whether the command writes files when it "compiles it implicitly" due to a
missing target/mdl.json; update SKILL.md to either (A) state that "wren genbi
build" will perform an implicit compile and write the compiled artifacts (e.g.,
target/mdl.json and wasm wiring) to disk, or (B) state that it only compiles
in-memory and prints the authoritative build instruction to stdout without
writing any files; ensure the phrasing around "wren genbi build",
"target/mdl.json", and the sentence "It writes nothing to disk." is made
consistent and unambiguous.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f98e824d-9653-4d2c-a321-16bd7ec114ca

📥 Commits

Reviewing files that changed from the base of the PR and between 9bd7196 and 5b8a766.

📒 Files selected for processing (6)
  • core/wren/scripts/genbi-e2e.sh
  • core/wren/src/wren/skills_content/dlt-connector/SKILL.md
  • core/wren/src/wren/skills_content/genbi/SKILL.md
  • core/wren/tests/unit/test_skills_cli.py
  • skills/index.json
  • skills/wren/SKILL.md
✅ Files skipped from review due to trivial changes (1)
  • skills/index.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • core/wren/tests/unit/test_skills_cli.py
  • core/wren/scripts/genbi-e2e.sh

PaulChen79 and others added 2 commits June 8, 2026 17:47
… silent failures

Resolve CodeRabbit findings on #2348 (each with a regression test):

- cli.py: validate app names as slugs via _resolve_app_dir() and route
  build/register/verify/open/deploy through it, so a crafted name
  ("../../etc") can't escape <project>/apps/.
- vercel.py / cloudflare.py: skip symlinks and entries resolving outside
  build_dir when collecting files — a stray symlink must never exfiltrate
  on-disk files to a public static host.
- vercel.py / cloudflare.py: raise DeployError instead of fabricating a URL
  ("https://", "{app}.pages.dev") when the provider response omits one —
  never report an unverifiable link as a successful deploy.
- index.py: load_index() raises MalformedIndexError (with the path) on
  invalid/non-mapping .wren/apps.yml instead of crashing opaquely.
- verify.py: fail closed on an unknown data_mode (a typo like "snapsho"
  no longer silently skips the snapshot data-asset check).
- genbi SKILL.md + build docstring: fix the "writes nothing to disk"
  self-contradiction (build compiles target/mdl.json if missing).
- test_genbi_deploy.py: autouse fixture neutralizes tier-2 ~/.wren/.env
  loading so token tests are hermetic (previously failed / could trigger a
  real provider call when a real VERCEL_TOKEN was present).

The stale comment on the (now-removed) genbi-e2e.sh sleep loop is moot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@PaulChen79 PaulChen79 self-assigned this Jun 10, 2026
PaulChen79 and others added 2 commits June 10, 2026 09:25
The previous adapter POSTed {"branch", "files": {path: base64}} as JSON to the
Pages deployments endpoint — a shape Cloudflare never accepts (→ 400). Pages
has no single inline-upload REST endpoint like Vercel; Direct Upload is a
multi-step, partially-undocumented protocol (manifest → upload token →
multipart asset upload → completion token → create deployment). Cloudflare's
own guidance is to use `wrangler pages deploy`, so shell out to it:

- Detect `wrangler` (or `npx wrangler`); clear DeployError if absent.
- `wrangler pages project create` (tolerate "already exists"), then
  `wrangler pages deploy . --project-name <n> --branch <main|preview>`,
  run with cwd=app_dir so a stray wrangler.toml can't be picked up.
- Token + account id travel via the subprocess env, never argv.
- Parse the *.pages.dev URL from wrangler output; DeployError if none
  (never fabricate a URL).

Rewrites the Cloudflare tests to mock the subprocess (the old tests mocked
the JSON transport and asserted our wrong shape — green but never exercised
the real protocol). Vercel is unchanged. Skill deploy section notes the
wrangler requirement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@goldmedal

Copy link
Copy Markdown
Collaborator

Review — GenBI app build & deploy

Verdict: Approve with one security follow-up. Clean CLI↔agent split, deterministic state owned by the CLI, and strong behavior-test coverage across build/index/verify/deploy. The prior review round already hardened path traversal, symlink exfiltration, URL fabrication, malformed-index handling, and fail-closed verify — each with a regression test. One gap below is worth fixing before verify is leaned on as a real safety boundary.

Scope & CI

  • Entirely core/wren/** + skills/ — no Rust/PyO3/connector/MDL surfaces, so no connector-regression or schema risk.
  • wren-ci.yml covers core/wren/** and runs pytest tests/unit/ -v -m unit; all new tests carry pytestmark = pytest.mark.unit, so they run.
  • Verified @wrenai/wren-core-wasm@0.4.1 matches core/wren-core-wasm/package.json exactly (name + version) — no CDN drift.

🟠 Medium — secret-leak gate has a suffix blind spot (reproduced)

verify._scan_for_secrets scans an allowlist of suffixes only: .css .htm .html .js .json .md .mjs .txt. Everything else is skipped — including the two most likely secret carriers an LLM will create:

  • .env — the canonical secret file; agents write these reflexively.
  • .ts / .tsx / .jsx / .vue — very plausible for a "web app"; none are scanned.

Meanwhile vercel._collect_files uploads every regular file under the app dir (only symlinks / outside-root skipped), and wrangler pages deploy . ships the whole folder. I reproduced this: a live app carrying a .env (postgres connection string) and a config.ts with the same secret passes verify cleanly and would be uploaded to the public host — defeating the gate's stated purpose ("a credential-leaking app can never reach a public URL").

Recommendation: invert to default-deny — scan every file except a small set of known-binary/data suffixes (.parquet, .duckdb, images, fonts, .wasm) — rather than allowlisting text types. As belt-and-suspenders, also refuse to upload dotfiles like .env* in _collect_files. At minimum add .env*, .ts, .tsx, .jsx, .vue, .yaml, .yml, .toml — but the allowlist will keep losing this race against whatever extension the agent picks next; default-deny is the durable fix.

🟡 Low — don't oversell the gate

The patterns are deliberately narrow (good for false positives) but miss GCP service-account JSON (private_key), bare bearer tokens, and generic high-entropy keys. The composer/SKILL text presents verify as the thing that catches inlined credentials, which invites over-trust. Worth one sentence noting it's best-effort defense-in-depth, not a guarantee — the real rule (already stated) is "never inline secrets."

Nits

  • CI lint runs ruff … src/ only, so the new test files aren't lint-gated (pre-existing behavior).
  • open/remove take name without routing through _resolve_app_dir, but they only touch index dict keys / serve an already-validated dir, and register (the only index writer) validates the slug — no traversal risk. Fine as-is.

Done well

  • Token discipline is textbook: env → .env tiers, never argv, never persisted — asserted on both providers and on apps.yml.
  • The autouse _isolate_env_loading fixture is the right call — without it the missing-token tests could pass spuriously or fire a real API call on a dev machine with a live VERCEL_TOKEN.
  • "Never fabricate a URL" + fail-closed-on-unknown-mode + MalformedIndexError are each small, exactly-right robustness choices with tests.

The Medium finding is the only thing I'd want addressed before merge, given security is the headline feature.

@goldmedal goldmedal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should also write the doc for the genBi command.

Comment thread skills/wren/SKILL.md Outdated
PaulChen79 and others added 4 commits June 10, 2026 13:14
…, en-only

- verify: invert the secret scan to DEFAULT-DENY. Previously an allowlist of
  web suffixes (.html/.js/.json/.css/.txt/.md) meant .env, .ts/.tsx/.jsx/.vue,
  .yaml/.toml were never scanned — exactly the files most likely to carry an
  inlined credential, and they all ship to the public host. Now scan every
  file except known binary/data formats (.parquet/.duckdb/.wasm/images/fonts…).
- verify: a `.env*` file fails the gate on presence alone (independent of the
  narrow content patterns; `wrangler pages deploy .` would otherwise ship it).
- vercel: belt-and-suspenders — never include `.env*` in the uploaded file set.
- Soften the "verify catches secrets" wording in composer + SKILL to
  best-effort defense-in-depth (not a guarantee); the rule is never inline.
- docs: add a `wren genbi` section to docs/core/reference/cli.md (build/
  register/list/remove/verify/open/deploy, tokens, wrangler, Vercel protection).
- Drop all Chinese trigger strings from skills/wren/SKILL.md and the genbi
  guide — English-only descriptions.

Regression tests: non-weblike files (.ts/.yaml) are scanned, .env fails by
presence, binary data assets aren't scanned (no false positives).

goldmedal nits left as-is (per review): test files not lint-gated
(pre-existing), open/remove don't route through _resolve_app_dir (no
traversal risk — index keys / already-validated dir).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- reference/skills.md: add a `genbi` row to the Available skills table and a
  full `## genbi` section (CLI↔agent split, workflow, data modes, deploy
  notes incl. wrangler + Vercel protection, dlt handoff) — it was the only
  served skill missing from the enumeration.
- core/wren/README.md: add an optional "Build a shareable GenBI app"
  quick-start step alongside cube/memory.
- docs/core/guides/genbi.md: new how-to guide with the conversational flow,
  data export recipe, verify/secret-gate caveats, and the Vercel 401 trap;
  linked from the docs index.

Docs only — no code change. (cli.md genbi reference landed in a prior commit.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… copy

Reframe the GenBI-specific wording to "context layer" (positioning), across
the genbi docs/skill/CLI text: skills.md (table + section), cli.md, the genbi
guide, core/wren/README.md step 7, the genbi SKILL.md, the wren discovery
stub's genbi clause, and the genbi composer/CLI help text.

Leaves unrelated pre-existing uses untouched — the "semantic SQL layer"
product tagline and "semantic layer" in the onboarding/usage skill sections.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@goldmedal

Copy link
Copy Markdown
Collaborator

Follow-up note: update the project-structure doc

The default-deny secret-scan fix looks good (verified: the .env + config.ts case that previously slipped now fails verify, with regression tests). One minor doc-completeness gap worth folding into this PR's docs commit:

GenBI introduces two new project-local artifacts — <project>/apps/<name>/ (the generated app) and <project>/.wren/apps.yml (the app index) — but the canonical "what lives in the project vs. globally in ~/.wren/" reference, docs/core/guides/manage_project.md, isn't updated and lists neither. It already documents target/mdl.json and .wren/memory/, so adding apps/ and placing .wren/apps.yml next to .wren/memory/ keeps the overview complete. The genbi guide/cli reference mention apps/<name>/ inline, but the structure overview doesn't.

Not a blocker — genbi.md covers the layout for genbi users; this is just to keep the central structure doc in sync with the directories this PR adds.

(Unrelated, pre-existing: docs/core/README.md links to guides/modeling/wren_project.md, which doesn't exist yet — leave for a separate PR.)

Address goldmedal's follow-up: the canonical "what lives in the project vs.
~/.wren/" reference didn't mention the two project-local artifacts GenBI
adds. Add a "Project layout" tree section that includes `apps/<name>/` (the
generated app) and `.wren/apps.yml` (the app index, beside `.wren/memory/`),
keeping the structure overview in sync with the directories this PR adds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@goldmedal goldmedal merged commit 67257bf into main Jun 11, 2026
9 checks passed
@goldmedal goldmedal deleted the worktree-deploy-app branch June 11, 2026 05:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation python Pull requests that update Python code skills

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants