feat: Framework-agnostic build pipeline for CNB/Buildpack support#1334
Open
feat: Framework-agnostic build pipeline for CNB/Buildpack support#1334
Conversation
Rework the build command to detect and build ANY JS framework, not just Agentuity native apps. This is the foundation for Cloud Native Buildpack (CNB) support. New architecture: - detect/ — Framework detection (Next.js, Vite, SvelteKit, Astro, Nuxt, Remix, generic) - adapters/ — Framework-specific build logic (delegates to framework's own build) - package/ — Launch metadata generation (Procfile, launch.json) The build command now follows: detect → install → build → package Existing Agentuity native apps (app.ts + @agentuity/runtime) continue to work via the 'agentuity' adapter which delegates to the existing viteBundle pipeline. Framework detection checks (in priority order): 1. Agentuity native (app.ts + @agentuity/runtime) 2. Next.js (next.config.* or 'next' dep) 3. Nuxt (nuxt.config.* or 'nuxt' dep) 4. Remix (@remix-run/* deps) 5. SvelteKit (svelte.config.* or @sveltejs/kit) 6. Astro (astro.config.* or 'astro' dep) 7. Vite (vite.config.* — SPA or SSR) 8. Generic fallback (package.json with build/start scripts) Output includes: - launch.json — Machine-readable launch metadata - Procfile — Heroku/Railway/Render compatible - .agentuity-build — Build marker with framework info Tests: 93 tests across 4 files (all passing): - detect/framework-detection.test.ts — 34 tests for all detectors + priority - detect/util.test.ts — 29 tests for utility functions - adapters/registry.test.ts — 9 tests for adapter lookup - package/launch.test.ts — 21 tests for launch metadata + packaging
Add 11 end-to-end contract tests that create real minimal projects, run them through the full detect → build → package pipeline, and validate the output meets the buildpack contract: - launch.json exists with valid schema (processes, framework, runtime, build) - Procfile exists and follows standard 'type: command' format - .agentuity-build marker exists with correct metadata - Server apps have a 'web' process with non-empty command - Procfile and launch.json agree on start commands - Framework name/runtime/mode consistent across all output files - Build failure propagates as error - Static builds don't copy node_modules - Build duration is non-zero Fix: infinite recursion in generic adapter's cpSync When buildOutput is '.' (project root) and outputDir is inside it (e.g., '.agentuity'), cpSync would recursively copy .agentuity into itself infinitely. Fixed by resolving paths and checking containment before copying, plus adding a filter to exclude the output dir.
Replace 6 individual detector files (nextjs.ts, nuxt.ts, remix.ts, sveltekit.ts, astro.ts, vite.ts) with a single framework database (frameworks.ts) and generic detection engine (engine.ts). Detection rules are informed by @vercel/frameworks v3.22.0 (Apache-2.0). All Vercel-specific properties (logos, CDN URLs, runtime config, routing rules, deploy targets) have been stripped — only generic framework facts remain: package names, config filenames, default build commands, and output directories as documented by each framework's own docs. The database covers 25 JS/TS frameworks: - Meta-frameworks: Next.js, Nuxt, Remix, React Router, SvelteKit, Astro, SolidStart, TanStack Start, RedwoodJS - Static generators: Gatsby, Eleventy, VitePress, VuePress, Docusaurus, Hexo - UI frameworks: Angular, Vue.js, Create React App, Preact - Server: Nitro - Bundlers: Vite, Parcel The detection engine evaluates detectors.every (all must match) and detectors.some (at least one must match) rules against project files and package.json dependencies. This fixes several wrong assumptions from the hand-rolled approach: - Remix: now uses @remix-run/dev (not @remix-run/node) for detection - Nuxt: uses package match (not config file) as primary detector - SvelteKit: uses package.json content regex (matches Vercel's approach) - Vite: uses package match (not config file) as primary detector Tests updated: 102 passing (was 104 — removed tests for features we no longer implement per-framework like static/SSR mode detection).
|
The latest Agentuity deployment details.
|
Contributor
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Replace the 1000+ line Agentuity-specific dev command with a simple passthrough that runs the project's own dev script. The new dev command: 1. Detects the package manager (bun/npm/pnpm/yarn) from lockfiles 2. Runs `<pm> run dev` (or a custom script via --script flag) 3. Passes PORT env var for port configuration 4. Inherits stdio for full interactivity 5. Forwards SIGINT/SIGTERM for clean shutdown Removed (2,831 lines of Agentuity-specific dev infrastructure): - agents.ts — Agent sync during dev - api.ts — Devmode API client - dev-lock.ts — Process lock management - download.ts — Gravity binary download - file-watcher.ts — File watcher with rebuild - process-manager.ts — Multi-process orchestration - sync.ts — Cloud sync service - templates.ts — Agent/route template generation These will not return — v3 eliminates the Agentuity runtime dependency, so the dev command becomes a thin wrapper around the framework's own dev server. No hardcoded runtime (works with bun, node, deno, etc.).
This was referenced Apr 2, 2026
… contract - Replace viteBundle() in deploy.ts with detect→adapt→package pipeline - Add LaunchMetadataSchema to BuildMetadata (processes, framework, runtime) - Make routes/agents optional with .default([]) for non-Agentuity frameworks - Use BuildResult.outputDir for zip/upload instead of hardcoded .agentuity - Generate deploy metadata from BuildResult for non-Agentuity frameworks - Remove AppMode (static/server) — every deploy produces a web process - Inject static file server (_serve.js) when framework has no start command - Pass deployment options (id, git info, config) through adapter pipeline - Update all tests (248 pass, 0 new failures)
…tterns Delete apps that are deeply tied to createApp(), agent discovery, and the Agentuity runtime model being deprecated in v3: - auth-package-app: @agentuity/auth demo with createApp + agents - cloud-deployment: CLI deploy smoke tests (backend not ready for buildpack deploys) - webrtc-test: WebRTC demo (@agentuity/frontend under review for v3) - svelte-app: empty/duplicate of svelte-web Also removes: - cloud-deployment-test CI workflow job - test:ci:cloud and test:cloud root scripts - scripts/test-cloud-deployment.sh
Rewrite all testing apps to be plain framework apps with no Agentuity runtime, createApp(), or agent dependencies. Each app is now what a real user would build — a standard framework app that deploys on Agentuity. Rewritten apps: - standalone-backend: bare Hono server (was standalone-agent with createAgent) - oauth: plain Hono + @agentuity/core/oauth (was createApp + runtime) - e2e-web: Hono server with HTML + API (was createApp + agents + analytics) - integration-suite: Hono backend testing Agentuity services (was createApp + agents + evals) - nextjs-app: plain Next.js App Router (was Next.js + agentuity/ subdir with agents) - svelte-web: plain SvelteKit with adapter-node (was createApp + agents + workbench) - tanstack-start: plain TanStack Start (was dual frontend + agentuity/ subdir) - vite-react-app: plain Vite React (was vite-rsc-app with agentuity/ subdir) Test approach: - Local tests (pass): route handlers, project structure, config validation - Deploy tests (skip): marked with describe.skip, ready for when backend supports launch.json - Service integration tests (skip): KV, vector, queue stubs ready for real implementation CI updates: - Consolidated standalone-agent-test + integration-test into testing-apps-test job - Disabled playwright-e2e-test and framework-demo-test (apps need rebuild for v3) - Updated root package.json scripts for renamed apps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reworks
agentuity buildandagentuity deployfrom a single-framework bundler (Agentuity native only) into a framework-agnostic build and deploy system. Any JS/TS project can now be built and deployed through Agentuity.How it works
Both
agentuity buildandagentuity deploynow follow a detect → build → package pipeline:Framework Detection
Detection uses a database + engine approach:
detect/frameworks.ts— Database of 25 JS/TS framework definitions with detection rules (which packages and config files identify each framework). Rules are informed by@vercel/frameworks(Apache-2.0) but contain zero Vercel-specific properties — only generic framework facts (package names, config filenames, build commands, output directories).detect/engine.ts— Generic engine that evaluatesdetectors.every(all must match) anddetectors.some(at least one must match) rules against a real project directory.Supported frameworks (first match wins, ordered by specificity):
Build Adapters
Adapters know how to build a specific framework:
agentuity— Delegates to the existingviteBundle()pipeline (zero behavior change for current users). Passes deployment options (ID, git info, config) through for metadata generation.nextjs— Enables standalone mode, packages server + static assetsgeneric— Works for any framework: install deps → run build script → copy output. Injects a static file server (_serve.js) when no start command exists, so every build always produces a runnable web process.Deploy Integration
deploy.tsnow uses the same detect→adapt→package pipeline asbuild. Key changes:agentuity.metadata.json(from viteBundle) and attacheslaunchmetadataBuildMetadatafromBuildResultwith empty routes/agents, assets fromstaticDir, and launch infoBuildResult.outputDirinstead of hardcoded.agentuity/BuildResult.outputDirfor any frameworkAPI Contract Changes
BuildMetadataSchema(in@agentuity/core):routesandagentsnow default to[]— non-Agentuity frameworks don't have themlaunchfield (optional) containingLaunchMetadataSchema:{ "launch": { "processes": [ { "type": "web", "command": "node server.js", "default": true } ], "framework": { "name": "nextjs", "version": "15.3.0" }, "runtime": { "name": "node", "port": 3000 }, "build": { "date": "2026-04-06T...", "duration": 12345 } } }Buildpack Output
Every build produces a deployment-ready directory with:
launch.json— Process definitions (type, command, default flag), framework info, runtime info, build timestampProcfile— Standardtype: commandformat for broad PaaS compatibility.agentuity-build— Marker file with version, framework, runtimeDev Command
agentuity devis now a framework-agnostic passthrough — detects the package manager and runs<pm> run devwithPORTset.Design Decisions
No static/server mode distinction
Every Agentuity deployment runs a process in a sandbox — there's no CDN-only tier. The
mode: 'static' | 'server'concept (borrowed from Vercel's model) was removed. When a framework has no start command, the generic adapter injects a minimal Node.js static file server (_serve.js). Every build always produces a web process inlaunch.json.Backwards Compatibility
Existing Agentuity native apps (
app.ts+@agentuity/runtime) are detected first and routed to theagentuityadapter, which delegates to the unchangedviteBundle()pipeline. Zero behavior change for current users.What the backend needs to do
Read
launch.jsonfrom the deployment bundle — After extracting the zip, look forlaunch.jsonin the root. Useprocesses[0].commandas the start command instead of hardcodingbun run app.js. Fall back to old behavior iflaunch.jsonis absent (old CLI).Use
runtime.nameto select the runtime binary —bunfor Agentuity native,nodefor everything else.Use
runtime.portfor health check — Port the app listens on (defaults to 3000).Don't require
agentuity.metadata.json— Non-Agentuity frameworks won't produce it. Theroutesandagentsarrays inBuildMetadatawill be empty.Tests
248 tests passing across 18 files:
detect/framework-detection.test.tsdetect/util.test.tsadapters/registry.test.tspackage/launch.test.tsbuildpack-contract.test.tsContract tests verify static file server injection, consistent metadata across output files, and that every build produces a valid web process.
New / Modified files