Bloom is a TypeScript full-stack framework designed for the era where developers and AI coding agents ship software together. UIKit (React components) + AppKit (Node backend) + a tiny scaffolding CLI — cover web, desktop (Electron), mobile (Capacitor), and browser extensions from one codebase. Every package ships llms.txt + AGENTS.md machine-readable specs so AI agents generate correct code, and developers review work they actually understand.
npm install -g @bloomneo/bloom
# Web app (React + Express, FBCA routing)
bloom create my-app
# Auth + user management + admin panel
bloom create my-app userapp
# Admin console (userapp + audit log, settings dashboard, 3-tier roles)
bloom create my-app adminapp
# Desktop app (Electron, SQLite, cross-platform)
bloom create my-app desktop-basicapp
bloom create my-app desktop-userapp
# Mobile app (iOS + Android via Capacitor 7)
bloom create my-app mobile-basicapp
This page is written for humans. Agents should fetch /bloom/llms.txt and /bloom/AGENTS.md for the authoritative CLI + template reference. Inside a scaffolded project, read the project's root AGENTS.md first, then docs/appkit-agents.md + docs/uikit-agents.md (auto-populated by npm install) for library-specific rules.
Bloom isn't monolithic. Install the full stack with bloom create, or pull any pillar into an existing project. They're designed to compose but work standalone.
Node.js toolkit with 12 typed modules — JWT auth, Prisma multi-tenancy, Redis cache & queue, S3 storage, SMTP/Resend email, structured logging, CSRF & rate limiting, semantic HTTP errors, typed config. Auto-scales memory → Redis → cloud without a rewrite.
45+ typed React components, 5 OKLCH themes, 6 production layouts. Forms, tables, dialogs, toasts, confirms, permission gates, responsive hooks — all wired on Radix + Tailwind. Web, Electron desktop, Capacitor mobile, browser-extension popups.
5 templates (web / auth+users / desktop / desktop+auth / mobile). Feature-Based Component Architecture — add a route by adding a folder. Every scaffold ships docs/ + .claude/skills/ auto-populated from installed packages, kept version-matched on every npm install.
Bloom has one load-bearing convention across every template: Feature-Based Component Architecture. Backend endpoints and frontend pages are auto-discovered by scanning feature folders. No router config to edit, no import list to maintain, no manual registration. Adding functionality = creating files.
# Backend — drop a folder → auto-mounted API route
src/api/features/
└── invoice/
├── invoice.route.ts → /api/invoice
├── invoice.service.ts (business logic; uses appkit)
└── invoice.types.ts (shared with frontend)
# Frontend — drop a folder → auto-routed page
src/web/features/
└── invoice/
├── pages/
│ ├── index.tsx → /invoice
│ ├── [id].tsx → /invoice/:id (dynamic segment)
│ └── [...path].tsx → /invoice/* (catch-all)
├── components/ (local to this feature)
└── services/ (API calls; uses uikit useApi)
Route pattern rules — how file paths become URLs:
| File path | Becomes route |
|---|---|
features/main/pages/index.tsx | / (root) |
features/blog/pages/index.tsx | /blog |
features/blog/pages/[slug].tsx | /blog/:slug |
features/docs/pages/[...path].tsx | /docs/* (catch-all) |
features/invoice/invoice.route.ts | /api/invoice |
Under the hood: the web router uses import.meta.glob('../features/*/pages/**/*.tsx'); the API router scans src/api/features/ at boot. Both are re-discovered on hot reload — no server restart required when you add a feature.
Most frameworks were built for humans, then retro-fitted with an LLM integration post-ChatGPT. Bloom is engineered from day one around the assumption that Claude, Cursor, Copilot and Windsurf are your teammates. Nine concrete places that plays out:
| What Bloom ships | Why it matters for agents |
|---|---|
llms.txt in every package | Single machine-readable API reference. Auto-regenerated on every build — never drifts from source. |
AGENTS.md with always-do / never-do rules | Prescriptive guardrails that prevent the most common LLM failure modes (wrong prop names, double providers, undefined data). |
| Claude Code skills bundled | 13 skills ship inside the packages. Copy .claude/skills/ into your repo — auto-triggered by import patterns. |
@llm-rule WHEN / AVOID / NOTE JSDoc on every UI component | Agents reading source code get usage rules inline. 44 of 44 uikit components annotated. |
| Postinstall doc hydration | Scaffolded projects auto-copy appkit + uikit docs into docs/ on every npm install. Agents always read docs matching the installed version. |
| Drift-checked public surface (CI) | Every package fails CI if docs, types, or template pins drift from source. Agents can't be taught a hallucinated method — CI rejects the teaching material first. |
| Enforced naming policy | get<Thing> nullable, require<Thing> middleware, has/is/can booleans, no synonym drift. Agents pattern-match one rule across 12 modules. |
Typed errors with module + code + docsUrl | Error messages embed the exact docs anchor. Agents reading an error can fetch the fix — no guessing. |
| Single canonical API pattern | xxxClass.get() across all 12 appkit modules. One flat import for uikit. Two commands for bloom. No decorators, no DI, no factory variants. |
Closest in scope to T3 Stack or RedwoodJS — not Laravel or NestJS directly. Bloom's differentiator is agentic-first design + cross-platform coverage; its weakness is ecosystem age.
| Dimension | Bloom | Laravel | NestJS | T3 Stack | Next.js |
|---|---|---|---|---|---|
| Backend | ✓ AppKit | ✓ (PHP) | ✓ core | Next API | Partial |
| Frontend | ✓ UIKit | Blade | — | ✓ Next | ✓ |
| Desktop (Electron) | ✓ | — | — | — | — |
| Mobile native (Capacitor) | ✓ | — | — | — | — |
| Browser extensions | ✓ | — | — | — | — |
| Auth built-in | ✓ JWT + roles | ✓ | via Passport | NextAuth | — |
| Queue / background jobs | ✓ memory→Redis | ✓ Horizon | ✓ Bull | — | — |
Ships llms.txt | ✓ | — | — | — | — |
Ships AGENTS.md | ✓ | — | — | — | — |
| Claude Code skills | ✓ 13 | — | — | — | — |
| Drift-checked docs (CI) | ✓ | — | — | — | — |
| Postinstall doc hydration | ✓ | — | — | — | — |
| Ecosystem maturity | New | 14 yrs | 7 yrs | 3 yrs | 8 yrs |
| LLM training-data familiarity | Low | High | High | Medium | Very high |
Bloom's bet: runtime llms.txt fetching closes the training-data gap. Agents don't need to have seen Bloom before — the docs ship with the code, version-matched, ready to load into context.
Best fit today: solo developers and small teams (≤10) shipping SaaS with heavy Claude Code / Cursor / Copilot usage, and anyone building cross-platform products (web + desktop + mobile) who doesn't want to stitch three stacks.
Not yet the right fit: 100-engineer enterprise teams where hiring pool and 10-year ecosystem matter more than agentic ergonomics. Use Laravel or NestJS for those.
Bloom is the scaffolder teams reach for when they need a working stack — not an evening evaluating starters.
userapp and ship MVP in a weekend.adminapp out of the box. Add a feature folder and ship.userapp template.desktop-basicapp / desktop-userapp ship Electron + embedded Express + SQLite. Packages to Windows, macOS, Linux.mobile-basicapp via Capacitor 7. Same React codebase, same UIKit components, native builds on both stores.PageLayout + themes. Swap the default template's pages for yours.docs/ and .claude/skills/ are populated on install so agents extend your app correctly.userapp + a few feature folders, no router config to manage.These are the only ways to silently break a Bloom project. Memorise them — or point your AI agent at AGENTS.md where they're spelled out line by line.
import { ... } from '@bloomneo/bloom'. Bloom is a CLI, not a runtime library. Nothing ships in node_modules for your app to import. If you're writing that import, you're off the canonical path.features/<name>/pages/index.tsx. Don't touch the router file.docs/appkit.md / docs/uikit.md. They're regenerated from node_modules on every npm install. Edit the upstream package's llms.txt, not the copy.bloom create into a non-empty directory. Exits 1 with a conflict error. Use . for the current directory only if it's empty (other than dotfiles).latest. Templates pin @bloomneo/appkit@^4.0.0 and @bloomneo/uikit@^2.0.1 for a reason — coordinated majors need a new bloom release.cd my-app
npm install # installs dependencies AND copies appkit/uikit docs into docs/
npm run dev # starts frontend + backend concurrently
| App type | Frontend | Backend |
|---|---|---|
| Web app | http://localhost:5173 (Vite + React) | http://localhost:3000 (Express + AppKit) |
| Desktop app | Electron window at http://localhost:5183 | http://localhost:3000 (Express + AppKit) |
| Mobile app | Capacitor native shell | External API (configure VITE_API_URL) |
bloom create my-app
bloom create my-app userapp
bloom create my-app adminapp
bloom create my-app desktop-basicapp
bloom create my-app desktop-userapp
bloom create my-app mobile-basicapp
my-app/
├── src/
│ ├── api/ # Express backend (AppKit)
│ │ ├── features/
│ │ │ └── welcome/
│ │ │ ├── welcome.route.ts # Auto-mounts at /api/welcome
│ │ │ └── welcome.service.ts
│ │ ├── lib/
│ │ │ └── api-router.ts # FBCA auto-discovery for routes
│ │ └── server.ts
│ └── web/ # React frontend (UIKit)
│ ├── features/
│ │ ├── main/pages/index.tsx # → /
│ │ ├── gallery/pages/index.tsx
│ │ └── welcome/pages/index.tsx
│ ├── shared/
│ │ └── components/
│ └── main.tsx
├── docs/ # Auto-populated after npm install
│ ├── appkit.md # ← node_modules/@bloomneo/appkit/llms.txt
│ ├── appkit-agents.md # ← node_modules/@bloomneo/appkit/AGENTS.md
│ └── uikit.md # ← node_modules/@bloomneo/uikit/llms.txt
├── AGENTS.md # Project-level AI agent conventions
├── .env.example # Environment variable template
├── package.json
└── tsconfig.json
my-app/
├── src/
│ ├── api/features/
│ │ ├── auth/ # Registration, login, email verify, password reset
│ │ │ ├── auth.route.ts
│ │ │ └── auth.service.ts
│ │ ├── users/ # User CRUD, profile, role management
│ │ │ ├── users.route.ts
│ │ │ └── users.service.ts
│ │ └── admin/ # Admin panel APIs
│ │ ├── admin.route.ts
│ │ └── admin.service.ts
│ └── web/features/
│ ├── auth/pages/ # Login, register, forgot-password pages
│ ├── dashboard/pages/ # Main dashboard
│ └── admin/pages/ # Admin user management UI
├── prisma/
│ ├── schema.prisma # User, Role, Session models
│ └── seed.ts # Default admin user
└── .env.example # DATABASE_URL, BLOOM_AUTH_SECRET, etc.
bloom create my-app userapp
cd my-app
npm install
# Configure your .env (copy from .env.example)
# Set DATABASE_URL, BLOOM_AUTH_SECRET, etc.
npx prisma db push # create tables
npm run db:seed # create default admin user
npm run dev # start frontend + backend
my-desktop-app/
├── src/
│ └── desktop/
│ ├── main/ # Electron main process (AppKit + Express backend)
│ │ ├── features/
│ │ │ └── welcome/
│ │ │ ├── welcome.route.ts
│ │ │ └── welcome.service.ts
│ │ ├── lib/
│ │ └── server.ts
│ └── renderer/ # React frontend (UIKit)
│ ├── features/
│ ├── shared/
│ └── main.tsx
├── electron/
│ └── main.js # Electron main process entry
└── package.json
npm run dev # Electron window + Vite hot reload + Express backend
npm run build # production build
npm run preview # preview production build in Electron
# electron-builder packages for your platform automatically:
# macOS → .dmg, Windows → .exe installer, Linux → .AppImage
my-mobile-app/
├── src/
│ └── web/ # React frontend (UIKit)
│ ├── features/
│ │ ├── home/pages/index.tsx
│ │ └── profile/pages/profile.tsx
│ ├── shared/
│ │ └── components/
│ │ └── MobileNav.tsx # Uses UIKit TabBar + MobileLayout
│ └── main.tsx
├── ios/ # Generated Xcode project
├── android/ # Generated Android Studio project
└── capacitor.config.ts
cd my-mobile-app
npm install
npm run dev # Vite dev server (browser preview)
# iOS
npm run mobile:run:ios # iOS Simulator
npm run mobile:build:ios # Build for Xcode
# Android
npm run mobile:run:android # Android Emulator
npm run android:build # Build APK
Every new feature lives in its own folder. No imports to add, no routing files to edit.
# 1. Create the backend feature
mkdir -p src/api/features/invoice
# Add invoice.route.ts (auto-mounts at /api/invoice)
# Add invoice.service.ts (business logic)
# 2. Create the frontend feature
mkdir -p src/web/features/invoice/pages
# Add index.tsx → routes to /invoice
# Add [id].tsx → routes to /invoice/:id
# That's it. Restart the server — no config needed.
// src/api/features/invoice/invoice.route.ts
import { Router } from 'express';
import { authClass, errorClass } from '@bloomneo/appkit';
import { InvoiceService } from './invoice.service';
const router = Router();
const auth = authClass.get();
const error = errorClass.get();
router.get('/', auth.requireLoginToken(), error.asyncRoute(async (req, res) => {
const invoices = await InvoiceService.list(req.user!.userId);
res.json({ invoices });
}));
router.post('/', auth.requireLoginToken(), error.asyncRoute(async (req, res) => {
const invoice = await InvoiceService.create(req.user!.userId, req.body);
res.status(201).json({ invoice });
}));
export default router;
docs/ foldernpm install automatically copies the latest llms.txt and AGENTS.md from installed packages into docs/appkit.md, docs/uikit.md.
AGENTS.mdProject-level AI instructions at the root: feature structure, env vars, always/never rules, and where to look for APIs.
AI coding agents read docs/appkit.md first and never guess method names. LLMs.txt coverage means the first suggestion is usually the correct one.
.env| Template | Required env vars |
|---|---|
basicapp |
BLOOM_AUTH_SECRET |
userapp |
BLOOM_AUTH_SECRET, DATABASE_URL, BLOOM_SECURITY_CSRF_SECRET, optionally RESEND_API_KEY for email |
desktop-basicapp / desktop-userapp |
BLOOM_AUTH_SECRET — SQLite path is auto-configured |
mobile-basicapp |
VITE_API_URL — points to your backend API |
llms.txt + AGENTS.md machine-readable specs so AI coding agents generate correct code on the first try.
llms.txt + AGENTS.md + Claude Code skills from node_modules into the project on every npm install — so docs never drift from installed versions. The CLI itself is tiny: bloom create and bloom start, nothing else.
src/api/features/<name>/*.route.ts auto-mounts at /api/<name>. Frontend: src/web/features/<name>/pages/*.tsx auto-routes via import.meta.glob. Add a feature = create a folder. No manual route registration, no router config to edit. Dynamic segments use [param], catch-all uses [...path].
bloom create, run npm install. The postinstall hook copies appkit + uikit llms.txt + AGENTS.md into docs/, and every Claude Code skill into .claude/skills/. Point your agent at the project root; it will find AGENTS.md first, then docs/appkit-agents.md + docs/uikit-agents.md for library-specific rules. No extra configuration.
desktop-basicapp and desktop-userapp scaffold Electron apps with an embedded Express backend (and SQLite for userapp). mobile-basicapp scaffolds a Capacitor 7 iOS + Android project that connects to a separate backend. Same UIKit components, same themes, same API across surfaces.
userapp and desktop-userapp templates require a database (Prisma with Postgres or SQLite). basicapp, desktop-basicapp, and mobile-basicapp run without one.
package.json — so agents never read stale guidance.
src/api/features/<name>/<name>.route.ts. For a page, add src/web/features/<name>/pages/index.tsx. FBCA auto-discovers both. There is no bloom add feature command; features are just folders.
llms.txtCanonical CLI + template reference. Commands, templates, exit codes, flags, FBCA rules. View →
AGENTS.mdAlways-do, never-do rules: what Bloom IS / IS NOT, template decision tree, FBCA conventions. View →
docs/Every scaffold's postinstall copies appkit + uikit llms.txt + AGENTS.md into docs/ on every npm install. Agents always read version-matched docs.