Skip to content

Commit 6c55d57

Browse files
jesseouecursoragent
andcommitted
feat: add AI chatbot building blocks
Add Vercel AI SDK, AI Elements, and Cloudflare Kumo UI modules so teams can install chatbot and UI building blocks as owned source. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 149fe66 commit 6c55d57

829 files changed

Lines changed: 2102 additions & 16851 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/ISSUE_TEMPLATE/module_request.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ body:
2626
id: readiness
2727
attributes:
2828
label: Expected readiness
29-
description: Is this a roadmap stub or an installable source module?
29+
description: Is this a proposal or an installable source module?
3030
options:
31-
- stub
31+
- proposal
3232
- experimental
3333
- ready
3434
- stable

.github/ISSUE_TEMPLATE/provider_request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ body:
4343
attributes:
4444
label: Expected readiness
4545
options:
46-
- stub
46+
- proposal
4747
- experimental
4848
- ready
4949
- stable

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
## Registry Changes
1313

14-
- [ ] Module status is honest (`ready` has files, `stub` has no source payload)
14+
- [ ] Module status is honest (`ready` has installable source; source-empty ideas stay as proposals)
1515
- [ ] Recipe or preset install order updated if this changes a workflow
1616
- [ ] Shared provider skill referenced when provider SDK/API behavior is involved
1717
- [ ] Generated registry output updated if manifests changed

AGENTS.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@ StackFoundry is a public source registry for production SaaS modules.
44

55
## Product Rules
66

7-
1. The registry is the product. Presets are only bundles of modules.
8-
2. Every module must include source files, docs, env notes, tests/checklist, and maintenance instructions.
7+
1. The registry is the product. Modules are source-delivered capabilities; presets install bundles; recipes explain complete workflow paths and install order.
8+
2. Published modules must include source files, docs, env notes when needed, tests/checklist, and maintenance skills. Proposal ideas belong in requests or roadmap docs until source exists.
99
3. Base scaffolds must stay small. Optional providers are adapters, not hard dependencies.
1010
4. Do not introduce public-facing references to how the project was authored.
1111
5. Never commit secrets, `.env.local`, provider credentials, private customer data, local caches, or generated machine metadata.
1212

13-
## Initial Modules
13+
## Core Registry Concepts
1414

15-
- `drizzle-postgres`
16-
- `api-keys`
17-
- `stripe-billing`
15+
- Readiness statuses: `ready`, `planned`, `experimental`, `stable`, `deprecated`.
16+
- Current source shape: `registry/modules`, `registry/presets`, `registry/recipes`, and `registry/skills`.
17+
- Public generated output lives in `public/r` and `apps/web/public/r`; never edit generated registry output by hand.
18+
- Shared provider/framework/database/platform guidance belongs in `registry/skills/<name>/SKILL.md` and is installed to `.stackfoundry/skills/<name>/SKILL.md`.
19+
- The hosted web app is Next.js on Vercel. Cloudflare support is an installable registry starter for consuming apps, not this repo's default deployment path.
1820

1921
## Quality Gates
2022

@@ -23,8 +25,10 @@ Before moving to a new phase:
2325
- `git status` is clean except intentional changes.
2426
- Docs are updated.
2527
- Module manifests validate.
26-
- The demo path works from a fresh checkout.
27-
- Changed modules include skill guidance.
28+
- Generated registry output is rebuilt when source registry files change.
29+
- Recipes, presets, and install order are updated when a workflow changes.
30+
- Changed modules include maintenance skills and checklist updates.
31+
- `pnpm check` passes before release or handoff.
2832

2933
## Public Voice
3034

CHANGELOG.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,34 @@
22

33
## Unreleased
44

5+
### Added
6+
7+
- Added SaaS recipes, readiness statuses, stricter validation, and a proposal path for future complete product workflows.
8+
- Added recipe commands and install paths, including `api-saas-starter`, `enterprise-saas`, `ai-saas-starter`, `cloudflare-saas`, `support-ops`, `security-center`, `integration-marketplace`, and `customer-intelligence`.
9+
- Added an installable `cloudflare-next-starter` module for consuming apps while keeping StackFoundry itself on the standard Next.js/Vercel path.
10+
- Added Vercel AI building blocks: `ai-sdk`, `ai-elements`, and `ai-chatbot-sdk`.
11+
- Added `cloudflare-kumo-ui` as an optional Cloudflare UI building-block module.
12+
- Added docs for recipes, install order, readiness, conventions, and a mirrored docs changelog.
13+
- Added OpenSSF Scorecard scanning and private vulnerability reporting links.
14+
15+
### Changed
16+
517
- Pointed module maintenance skills to installed shared provider, framework, database, SDK, and platform skills.
618
- Standardized provider adapter registry language and replaced legacy provider wording/paths.
719
- Renamed public command examples to `stackfoundry`.
8-
- Added SaaS recipes, readiness statuses, stricter validation, and high-priority stub modules for complete product workflows.
9-
- Polished registry docs for recipes, readiness, install order, conventions, and current registry scale.
10-
- Added an installable Cloudflare Next.js starter module for consuming apps while keeping StackFoundry hosted on Vercel.
11-
- Improved README badges, contribution controls, provider request templates, and repo topics for public discovery.
12-
- Hardened public repository security posture with private vulnerability reporting, safer checkout settings, OpenSSF Scorecard, dependency review, CodeQL, and clearer public-safety rules.
20+
- Updated AGENTS.md to match the current recipes, readiness, generated-output, and maintenance-skill model.
21+
- Improved README badges, contribution controls, provider request templates, repo topics, and docs navigation for public discovery.
1322
- Updated GitHub Actions dependencies for checkout, Node setup, pnpm setup, and dependency review.
1423

24+
### Security
25+
26+
- Hardened public repository security posture with private vulnerability reporting, safer checkout settings, OpenSSF Scorecard, dependency review, CodeQL, Dependabot vulnerability alerts, and clearer public-safety rules.
27+
28+
### Fixed
29+
30+
- Fixed GitHub integration private-key newline handling in the installable source template.
31+
- Resolved the `next-saas` module/preset ambiguity by renaming the source shell module to `next-saas-shell`.
32+
1533
## 1.0.0
1634

1735
- Released StackFoundry as a public source registry for production SaaS modules.

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ A module should include:
3232
- `skill/SKILL.md`
3333
- `tests/checklist.md`
3434

35-
Use `stub` for modules that document a real SaaS capability but do not install source yet. Use `ready` only when the module has installable source files and passes registry validation.
35+
Use GitHub module/provider requests for proposed capabilities that do not install source yet. Use `ready` only when the module has installable source files and passes registry validation.
3636

3737
## Provider Adapters
3838

@@ -55,7 +55,7 @@ Good public PR shapes:
5555

5656
- one new provider adapter
5757
- one ready module implementation
58-
- one stub-to-ready promotion
58+
- one proposal-to-ready module promotion
5959
- one recipe/preset update with generated registry output
6060
- one docs-only clarification
6161

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Install production SaaS modules as editable source code.
99
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
1010
![Next.js](https://img.shields.io/badge/Next.js-16-black)
1111
![Vercel](https://img.shields.io/badge/deploy-Vercel-black)
12-
![Modules](https://img.shields.io/badge/modules-294-orange)
12+
![Modules](https://img.shields.io/badge/modules-155-orange)
1313
![Recipes](https://img.shields.io/badge/recipes-9-purple)
1414
![Presets](https://img.shields.io/badge/presets-13-teal)
1515
![Inspired by shadcn](https://img.shields.io/badge/inspired%20by-shadcn-111111)
@@ -85,12 +85,12 @@ Current source registry coverage:
8585
| Docs and SEO | `docs-fumadocs`, `docs-mintlify`, `docs-help-center`, `seo`, `ai-seo` |
8686
| Security | `arcjet-security`, `security-headers`, `csrf-protection`, `input-validation`, `secrets-management` |
8787
| Storage and infra | `vercel-blob`, `vercel-edge-config`, `cloudflare-r2`, `upstash-redis`, `docker-compose-local` |
88-
| Optional AI | `ai-chat`, `model-router`, `ai-tools`, `rag-starter`, `evals`, `cloudflare-agents-sdk` |
88+
| Optional AI | `ai-sdk`, `ai-elements`, `ai-chat`, `ai-chatbot-sdk`, `cloudflare-agents-sdk`, `cloudflare-kumo-ui` |
8989

9090
<details>
9191
<summary>Current scale</summary>
9292

93-
- 294 module manifests
93+
- 155 ready module manifests
9494
- 36 canonical categories
9595
- 13 preset bundles
9696
- 9 architecture recipes
@@ -105,15 +105,15 @@ Current source registry coverage:
105105
| `next-saas` | Broad app foundation with database, billing, account surfaces, docs, ops, security, and growth modules |
106106
| `b2b-saas` | Team workspaces, tenant controls, RBAC, auditability, SSO, and SCIM |
107107
| `developer-platform` | API keys, public APIs, webhooks, docs, SDK snippets, and developer portal modules |
108-
| `ai-saas` | Optional AI product modules for chat, model routing, prompts, quotas, RAG, and metering |
108+
| `ai-saas` | Optional AI product modules for Vercel AI SDK chat, AI Elements, quotas, Cloudflare AI building blocks, and metering |
109109
| `internal-admin` | Operator consoles, support, health, incidents, jobs, backup, and maintenance controls |
110110
| `free-tier-saas` | Practical baseline for a free-tier product launch |
111111
| `vercel-native` | Vercel deployment, storage, workflows, edge config, and observability path |
112112
| `cloudflare-native` | Workers, D1, R2, KV, Queues, Workflows, Turnstile, and Cloudflare-native adapters |
113113
| `provider-adapters` | Concrete optional provider adapter examples |
114114
| `api-saas-starter` | API-first SaaS workflow with keys, usage, rate limits, billing, webhooks, docs, and observability |
115115
| `enterprise-saas` | Enterprise layer with SSO, SCIM, audit, access review, security, SLA, and support workflows |
116-
| `ai-saas-starter` | AI SaaS workflow with chat, model routing, prompts, evals, RAG, usage metering, and billing |
116+
| `ai-saas-starter` | AI SaaS workflow with Vercel AI SDK chat, AI Elements, usage metering, quotas, and billing |
117117

118118
```bash
119119
pnpm registry:presets
@@ -284,7 +284,7 @@ See [`docs/repository.md`](./docs/repository.md) for ownership rules.
284284

285285
## Where This Is Going
286286

287-
- More stub modules graduating to ready installable source payloads
287+
- More proposed modules graduating to ready installable source payloads
288288
- Better diff/update workflows for installed modules
289289
- More provider adapters without making providers base dependencies
290290
- More production smoke paths for presets and recipes

apps/cli/src/cli.mjs

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ async function validateModule(moduleDir) {
207207
errors.push(`category must be one of: ${[...validModuleCategories].sort().join(", ")}`);
208208
}
209209
if (!validModuleStatuses.has(manifest.status)) {
210-
errors.push("status must be ready, stub, planned, experimental, stable, or deprecated");
210+
errors.push("status must be ready, planned, experimental, stable, or deprecated");
211211
}
212212
if (!Array.isArray(manifest.files)) errors.push("files must be an array");
213213
if (!Array.isArray(manifest.dependencies)) errors.push("dependencies must be an array");
@@ -219,9 +219,6 @@ async function validateModule(moduleDir) {
219219
if (installableStatuses.has(manifest.status) && manifest.files.length === 0) {
220220
errors.push(`${manifest.status} module must include at least one installable file`);
221221
}
222-
if (manifest.status === "stub" && manifest.files.length > 0) {
223-
errors.push("stub module should not include installable files; use experimental or ready");
224-
}
225222
for (const key of manifest.env ?? []) {
226223
if (!isEnvVarName(key)) errors.push(`env var must be SCREAMING_SNAKE_CASE: ${key}`);
227224
if (isUnsafePublicEnvName(key)) {
@@ -447,7 +444,7 @@ async function validateRegistry(flags = {}) {
447444
errors.push(`${file}: recipe category must be one of: ${[...validModuleCategories].sort().join(", ")}`);
448445
}
449446
if (!validModuleStatuses.has(recipe.status)) {
450-
errors.push(`${file}: recipe status must be ready, stub, planned, experimental, stable, or deprecated`);
447+
errors.push(`${file}: recipe status must be ready, planned, experimental, stable, or deprecated`);
451448
}
452449
if (!Array.isArray(recipe.modules)) errors.push(`${file}: modules must be an array`);
453450
if (!Array.isArray(recipe.stages)) errors.push(`${file}: stages must be an array`);
@@ -706,6 +703,56 @@ async function saveInstallManifest(target, manifest) {
706703
await writeFile(path.join(dir, "installed.json"), `${JSON.stringify(manifest, null, 2)}\n`);
707704
}
708705

706+
async function mergePackageScripts({ target, packageScripts, flags, installedFiles }) {
707+
if (!packageScripts || typeof packageScripts !== "object") return;
708+
709+
for (const [relative, scripts] of Object.entries(packageScripts)) {
710+
if (!isSafeRelativePath(relative) || !relative.endsWith("package.json")) {
711+
throw new Error(`packageScripts target must be a safe package.json path: ${relative}`);
712+
}
713+
if (!scripts || typeof scripts !== "object" || Array.isArray(scripts)) {
714+
throw new Error(`${relative}: packageScripts value must be an object`);
715+
}
716+
717+
const packagePath = path.join(target, relative);
718+
if (!existsSync(packagePath)) {
719+
console.log(`${flags.dryRun ? "would skip" : "skipped"} ${relative} packageScripts; file does not exist`);
720+
continue;
721+
}
722+
723+
const packageJson = await readJson(packagePath);
724+
const nextScripts = { ...(packageJson.scripts ?? {}), ...scripts };
725+
const nextPackageJson = { ...packageJson, scripts: nextScripts };
726+
const content = `${JSON.stringify(nextPackageJson, null, 2)}\n`;
727+
728+
if (!flags.dryRun) await writeFile(packagePath, content);
729+
installedFiles[relative] = hashContent(content);
730+
console.log(`${flags.dryRun ? "would update" : "updated"} ${relative} scripts`);
731+
}
732+
}
733+
734+
async function mergeGitignoreEntries({ target, entries, flags, installedFiles }) {
735+
if (!entries?.length) return;
736+
737+
const relative = ".gitignore";
738+
const gitignorePath = path.join(target, relative);
739+
const existing = existsSync(gitignorePath) ? await readFile(gitignorePath, "utf8") : "";
740+
const lines = existing.split(/\r?\n/);
741+
const existingEntries = new Set(lines.map((line) => line.trim()).filter(Boolean));
742+
const missing = entries.filter((entry) => !existingEntries.has(entry));
743+
744+
if (missing.length === 0) {
745+
installedFiles[relative] = hashContent(existing);
746+
return;
747+
}
748+
749+
const prefix = existing.trimEnd();
750+
const content = `${prefix ? `${prefix}\n\n` : ""}# StackFoundry generated build output\n${missing.join("\n")}\n`;
751+
if (!flags.dryRun) await writeFile(gitignorePath, content);
752+
installedFiles[relative] = hashContent(content);
753+
console.log(`${flags.dryRun ? "would update" : "updated"} ${relative}`);
754+
}
755+
709756
async function addModule(name, flags, visited = new Set(), context = {}) {
710757
if (visited.has(name)) return;
711758
visited.add(name);
@@ -745,6 +792,19 @@ async function addModule(name, flags, visited = new Set(), context = {}) {
745792
installedFiles[normalized] = sourceHash;
746793
}
747794

795+
await mergePackageScripts({
796+
target: flags.target,
797+
packageScripts: manifest.packageScripts,
798+
flags,
799+
installedFiles,
800+
});
801+
await mergeGitignoreEntries({
802+
target: flags.target,
803+
entries: manifest.gitignore,
804+
flags,
805+
installedFiles,
806+
});
807+
748808
for (const skill of maintenanceSkills) {
749809
const sourceHash = hashContent(skill.content);
750810
await writeFileWithSafety({
@@ -858,6 +918,19 @@ async function addRegistryItem(specifier, flags, visited = new Set()) {
858918
installedFiles[relative] = sourceHash;
859919
}
860920

921+
await mergePackageScripts({
922+
target: flags.target,
923+
packageScripts: item.meta?.packageScripts,
924+
flags,
925+
installedFiles,
926+
});
927+
await mergeGitignoreEntries({
928+
target: flags.target,
929+
entries: item.meta?.gitignore,
930+
flags,
931+
installedFiles,
932+
});
933+
861934
for (const skill of item.maintenanceSkills ?? []) {
862935
if (!skill.content)
863936
throw new Error(
@@ -1036,6 +1109,8 @@ async function buildRegistry() {
10361109
meta: {
10371110
category: manifest.category,
10381111
group: manifest.group,
1112+
gitignore: manifest.gitignore,
1113+
packageScripts: manifest.packageScripts,
10391114
status: manifest.status,
10401115
maturity: manifest.status,
10411116
recommendedFor: manifest.recommendedFor ?? [],
@@ -1140,6 +1215,8 @@ async function buildRegistry() {
11401215
category: manifest.category,
11411216
group: manifest.group,
11421217
env: manifest.env,
1218+
gitignore: manifest.gitignore,
1219+
packageScripts: manifest.packageScripts,
11431220
status: manifest.status,
11441221
maturity: manifest.status,
11451222
drizzle: manifest.drizzle,

apps/web/app/docs/page.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,16 @@ const moduleGroups = [
197197
},
198198
{
199199
category: "Optional AI",
200-
summary: "AI modules are categories in the registry, not the product identity.",
200+
summary: "Vercel AI SDK, AI Elements, and Cloudflare AI modules are optional building blocks.",
201201
modules: [
202+
"ai-sdk",
203+
"ai-elements",
202204
"ai-chat",
203-
"model-router",
204-
"prompt-library",
205-
"rag-starter",
205+
"ai-chatbot-sdk",
206206
"cloudflare-agents-sdk",
207207
"cloudflare-mcp-server",
208208
"cloudflare-vectorize",
209-
"evals",
209+
"cloudflare-kumo-ui",
210210
],
211211
},
212212
{

apps/web/app/page.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ type LandingModuleCard = {
2222
};
2323

2424
const stats = [
25-
{ value: "160+", label: "Modules" },
26-
{ value: "9", label: "Presets" },
27-
{ value: "12", label: "Categories" },
25+
{ value: "155", label: "Modules" },
26+
{ value: "13", label: "Presets" },
27+
{ value: "36", label: "Categories" },
2828
{ value: "MIT", label: "License" },
2929
];
3030

@@ -127,6 +127,25 @@ const moduleCards: LandingModuleCard[] = [
127127
actions: [{ label: "json", href: "/r/webhook-inbox.json" }],
128128
},
129129
},
130+
{
131+
name: "ai-chatbot-sdk",
132+
title: "AI Chatbot SDK",
133+
category: "optional AI",
134+
variant: "featured",
135+
version: "v0.1.0",
136+
description:
137+
"Vercel AI SDK chat, AI Elements primitives, gateway-ready model routing, and a source-owned chatbot shell.",
138+
tags: [
139+
{ label: "ai" },
140+
{ label: "Vercel AI SDK", tone: "provider" },
141+
{ label: "deps: ai-elements", tone: "dependency" },
142+
{ label: "maintenance skill", tone: "skill" },
143+
],
144+
footer: {
145+
summary: "2 files · 2 deps · 1 skill",
146+
actions: [{ label: "json", href: "/r/ai-chatbot-sdk.json" }],
147+
},
148+
},
130149
{
131150
name: "resend-email",
132151
title: "Resend Email",
@@ -250,7 +269,7 @@ const presetRows = [
250269
const assuranceRows = [
251270
{
252271
title: "What installs?",
253-
body: "Source files, route shells, helpers, schema slices, docs, skill guidance, and verification checklists.",
272+
body: "Source files, route shells, helpers, schema slices, docs, maintenance skills, and verification checklists.",
254273
},
255274
{
256275
title: "What stays out?",

0 commit comments

Comments
 (0)