Skip to content

feat: Framework-agnostic build pipeline for CNB/Buildpack support#1334

Open
Huijiro wants to merge 8 commits intov3from
feat/buildpack-build
Open

feat: Framework-agnostic build pipeline for CNB/Buildpack support#1334
Huijiro wants to merge 8 commits intov3from
feat/buildpack-build

Conversation

@Huijiro
Copy link
Copy Markdown
Member

@Huijiro Huijiro commented Apr 2, 2026

Summary

Reworks agentuity build and agentuity deploy from 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 build and agentuity deploy now follow a detect → build → package pipeline:

agentuity build / deploy
    │
    ├─ 1. Detect framework (what is this project?)
    │     ├─ Agentuity native? (app.ts + @agentuity/runtime)
    │     ├─ Known framework? (25 frameworks in database)
    │     └─ Generic fallback? (package.json with build/start scripts)
    │
    ├─ 2. Build with adapter (run the framework's own build)
    │     ├─ Agentuity adapter → delegates to existing viteBundle pipeline
    │     ├─ Next.js adapter → standalone mode, asset packaging
    │     └─ Generic adapter → install deps, run build script, copy output
    │
    ├─ 3. Package output (make it deployable)
    │     ├─ launch.json → machine-readable process definitions
    │     ├─ Procfile → Heroku/Railway/Render compatible
    │     └─ .agentuity-build → build marker with framework metadata
    │
    └─ 4. Deploy (agentuity deploy only)
          ├─ Send BuildMetadata + launch info to API
          ├─ Zip build output dir → encrypt → upload
          └─ Upload static assets to CDN

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 evaluates detectors.every (all must match) and detectors.some (at least one must match) rules against a real project directory.

Supported frameworks (first match wins, ordered by specificity):

Category 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
Special Agentuity native (highest priority), Generic fallback (lowest)

Build Adapters

Adapters know how to build a specific framework:

  • agentuity — Delegates to the existing viteBundle() 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 assets
  • generic — 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.ts now uses the same detect→adapt→package pipeline as build. Key changes:

  • Agentuity native: Loads agentuity.metadata.json (from viteBundle) and attaches launch metadata
  • Other frameworks: Generates BuildMetadata from BuildResult with empty routes/agents, assets from staticDir, and launch info
  • Zip/upload: Uses BuildResult.outputDir instead of hardcoded .agentuity/
  • CDN assets: Resolved from BuildResult.outputDir for any framework

API Contract Changes

BuildMetadataSchema (in @agentuity/core):

  • routes and agents now default to [] — non-Agentuity frameworks don't have them
  • New launch field (optional) containing LaunchMetadataSchema:
{
  "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 timestamp
  • Procfile — Standard type: command format for broad PaaS compatibility
  • .agentuity-build — Marker file with version, framework, runtime

Dev Command

agentuity dev is now a framework-agnostic passthrough — detects the package manager and runs <pm> run dev with PORT set.

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 in launch.json.

Backwards Compatibility

Existing Agentuity native apps (app.ts + @agentuity/runtime) are detected first and routed to the agentuity adapter, which delegates to the unchanged viteBundle() pipeline. Zero behavior change for current users.

What the backend needs to do

  1. Read launch.json from the deployment bundle — After extracting the zip, look for launch.json in the root. Use processes[0].command as the start command instead of hardcoding bun run app.js. Fall back to old behavior if launch.json is absent (old CLI).

  2. Use runtime.name to select the runtime binarybun for Agentuity native, node for everything else.

  3. Use runtime.port for health check — Port the app listens on (defaults to 3000).

  4. Don't require agentuity.metadata.json — Non-Agentuity frameworks won't produce it. The routes and agents arrays in BuildMetadata will be empty.

Tests

248 tests passing across 18 files:

File Tests Coverage
detect/framework-detection.test.ts 30 All framework detectors, priority ordering, combined API
detect/util.test.ts 29 File finding, dep checking, package manager detection, JSON parsing
adapters/registry.test.ts 10 Adapter lookup for all frameworks, generic fallback
package/launch.test.ts 14 Launch metadata generation, Procfile writing, build marker
buildpack-contract.test.ts 11 End-to-end: creates real projects, runs full pipeline, validates output structure

Contract tests verify static file server injection, consistent metadata across output files, and that every build produces a valid web process.

New / Modified files

packages/core/src/services/project/
└── deploy.ts              # LaunchMetadataSchema, routes/agents .default([]), launch field

packages/cli/src/
├── deploy-metadata.ts     # BuildMetadata generator for non-Agentuity frameworks
└── cmd/
    ├── build/
    │   ├── detect/
    │   │   ├── agentuity.ts      # Agentuity native detector
    │   │   ├── engine.ts          # Rule evaluation engine
    │   │   ├── frameworks.ts      # 25-framework detection database
    │   │   ├── generic.ts         # Generic fallback detector
    │   │   ├── index.ts           # Detection orchestrator
    │   │   ├── types.ts           # DetectedFramework, PackageJsonData types
    │   │   └── util.ts            # Shared utilities
    │   ├── adapters/
    │   │   ├── agentuity.ts       # Bridge to existing viteBundle pipeline
    │   │   ├── generic.ts         # Install → build → copy for any framework
    │   │   ├── nextjs.ts          # Next.js standalone mode handling
    │   │   ├── static-server.ts   # Injected file server for static builds
    │   │   ├── index.ts           # Adapter registry
    │   │   └── types.ts           # BuildAdapter, BuildResult, BuildAdapterOptions
    │   ├── package/
    │   │   ├── launch.ts          # launch.json + Procfile generation
    │   │   └── index.ts           # Output packaging orchestrator
    │   └── index.ts               # Build command (uses pipeline)
    ├── cloud/
    │   └── deploy.ts              # Deploy command (uses pipeline)
    └── dev/
        └── index.ts               # Framework-agnostic dev passthrough

Huijiro added 3 commits April 2, 2026 17:21
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).
@agentuity-agent
Copy link
Copy Markdown

agentuity-agent bot commented Apr 2, 2026

The latest Agentuity deployment details.

Project Deployment Preview Updated (UTC)
docs 🔴 Failed (deploy_43ac8471f9bb9201e2784fb0526d6a1b) - 2026-04-06T21:18:31Z

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 919be507-56d5-412a-a388-594940f97cce

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

Huijiro added 2 commits April 2, 2026 17:43
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.).
Huijiro added 3 commits April 6, 2026 17:33
… 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
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