Skip to content
Active

yabasha/composable-ai-stack

The Composable AI Stack (CAS) is a production-ready monorepo template designed for developers building AI-integrated SaaS applications. It provides a structured, modular foundation that abstracts the complexity of scaling from localized prototyping to robust enterprise deployments. By standardizing the integration of LLMs, database interactions, and billing logic, it enables teams to focus on core product features rather than boilerplate architecture.

Built on a modern TypeScript stack, the project leverages Bun for high-performance execution and Turborepo for efficient workspace management. The backend is powered by Convex, providing a unified, reactive database experience, while optional ElysiaJS endpoints offer flexibility for API-level tasks like custom middleware and rate limiting. The stack emphasizes type safety and reliability, featuring a rigid "guardrail" pattern that enforces input/output validation via Zod schemas and integrates Langfuse by default for comprehensive LLM observability, prompt tracing, and performance monitoring.

This project is an excellent choice for developers seeking a "Convex-first" architecture that balances rapid development with long-term maintainability. It effectively bridges the gap between simple side projects and large-scale applications by including pre-configured evaluation harnesses, shared component libraries with shadcn/ui, and automated version-pinning tools to ensure long-term dependency stability.

Stars
1
Forks
0
Language
TypeScript
Updated
5mo ago

A modular AI stack that scales from local tools to enterprise systems

  • Name: Composable AI Stack
  • Short: CAS
  • Repo slug: cas or composable-ai-stack
  • Package scope (if you publish): @cas/* or @composable-ai/*
  • Docs title line: Composable AI Stack (CAS)
  • One-liner tagline: A modular AI stack that scales from local tools to enterprise systems.

Overview

A reusable monorepo template for AI-Integrated SaaS apps:

  • apps/web: Next.js + Tailwind + shadcn/ui
  • apps/convex: Convex backend (schema + functions + HTTP endpoints)
  • apps/api: Optional ElysiaJS (Bun) API gateway
  • apps/worker: background tasks + eval runner CLI (Bun)
  • packages/: shared prompts, schemas, AI utilities, eval harness, configs

Goal: be your modular AI stack that scales from local tools to enterprise systems


Requirements

  • Bun
  • A Convex project (free tier works for prototyping)
  • Optional: Stripe account for memberships

Quick Start

1) Install dependencies (root)

bun install

2) Copy env and fill values

cp .env.example .env

3) Run development

In separate terminals:

bun run dev:convex
bun run dev:web
# optional
bun run dev:api

Or run everything:

bun run dev

Convex Setup

From apps/convex:

cd apps/convex
bunx convex dev

Convex will output a deployment URL. Set:

  • NEXT_PUBLIC_CONVEX_URL in .env (and/or apps/web/.env.local)

shadcn/ui + Tailwind

apps/web is preconfigured with Tailwind and a minimal shadcn/ui setup.

Add a shadcn component (from within apps/web):

cd apps/web
bunx shadcn@latest add button

Where to tweak:

  • apps/web/components.json
  • apps/web/tailwind.config.ts
  • apps/web/app/globals.css

Memberships / Billing (Convex-first)

Template includes placeholders for:

  • membership fields in apps/convex/convex/schema.ts
  • a webhook route in apps/convex/convex/http.ts (/stripe/webhook)

Typical flow:

  1. Create checkout session in a Convex action (server-side)
  2. Stripe redirects user back to your app
  3. Stripe sends webhook events to /stripe/webhook
  4. Convex updates your users.planStatus

If you want a dedicated webhook gateway with custom middleware/rate limiting, use apps/api (ElysiaJS).


Scaling the rate limiter

apps/api ships an in-memory rate limiter (apps/api/src/middleware/rate-limit.ts). It tracks request counts in a single-process Map. For multi-worker or multi-instance deployments, replace the backing store with Redis or Upstash:

  1. Install: bun add --filter=api @upstash/ratelimit @upstash/redis
  2. Swap the Map in rate-limit.ts for an Upstash Ratelimit instance.
  3. Set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN in .env.

The middleware exposes X-RateLimit-Backend: memory so you can verify which store is in use at runtime.


Scripts (root)

  • bun run dev — dev for all apps
  • bun run dev:web — Next.js only
  • bun run dev:convex — Convex only
  • bun run dev:api — Elysia only
  • bun run build — build all buildable apps
  • bun run eval — run eval harness

Repo Layout

apps/
  web/
  convex/
  api/
  worker/

packages/
  shared/
  schemas/
  prompts/
  ai/
  evals/
  config/

See use-cases.md and apps/api/use-cases.md.

UI Stack

  • Web UI uses Tailwind CSS v4.1 + shadcn/ui.

Versions (template defaults)

Pinned to your requested versions:

  • Bun: 1.3.7
  • Turborepo (turbo): 2.7.6
  • TypeScript: 5.9.3
  • Prettier: 3.8.1
  • Next.js: 16.1.6 (App Router)
  • React: 19.2.4
  • Tailwind CSS: 4.1.18
  • Elysia: 1.4.22
  • Convex: 1.31.6
  • ESLint: 9.39.2

Keeping versions pinned

Run:

bun run check:versions

CI will fail if any pinned dependency versions drift.


Guardrail Pattern

The @acme/ai package provides a guardrail pattern for safe, validated LLM calls:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Input     │────▶│    Zod      │────▶│ Moderation  │────▶│  LLM Call   │
│   (raw)     │     │ Validation  │     │   Hook      │     │             │
└─────────────┘     └─────────────┘     └─────────────┘     └──────┬──────┘
                                                                   │
                    ┌─────────────┐     ┌─────────────┐           │
                    │   Output    │◀────│    Zod      │◀──────────┘
                    │  (typed)    │     │ Validation  │
                    └─────────────┘     └─────────────┘

Usage Example

import { z } from 'zod';
import { runWithGuardrails, openai, DEFAULT_MODELS } from '@acme/ai';

const inputSchema = z.object({ message: z.string().max(500) });
const outputSchema = z.object({ reply: z.string(), confidence: z.number() });

const result = await runWithGuardrails(
  openai(DEFAULT_MODELS.openai),
  'Generate a helpful reply',
  { message: 'Hello, I need help!' },
  {
    name: 'support-reply',
    inputSchema,
    outputSchema,
    moderationHook: async (input) => input.message.length > 0,
  }
);

console.log(result.output); // { reply: '...', confidence: 0.95 }
console.log(result.traceId); // Langfuse trace ID

All guardrail runs are automatically traced to Langfuse with full input/output logging.


Observability

This stack uses Langfuse for LLM observability and tracing:

Required Environment Variables

# LLM Providers
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-...

# Langfuse (Observability)
LANGFUSE_PUBLIC_KEY=pk-...
LANGFUSE_SECRET_KEY=sk-...
LANGFUSE_BASE_URL=https://cloud.langfuse.com  # Optional: use your self-hosted instance

Features

  • Automatic tracing: Every LLM call via tracedGenerate() or runWithGuardrails() is traced
  • Generation tracking: Prompts, outputs, token usage, and latency are captured
  • Score logging: Eval scores are sent to Langfuse for monitoring
  • Self-hosted option: Run your own Langfuse instance by changing LANGFUSE_BASE_URL

Author

Created by Bashar Ayyash — yabasha.dev

§ Cite this project

Bashar Ayyash. (2026). yabasha/composable-ai-stack [Computer software]. https://yabasha.dev/open-source/composable-ai-stack

yabasha/monolith

Active

This project provides a robust, scalable architecture for modern full-stack development by combining a Laravel 12 backend with a Next.js 16 frontend in a unified monorepo. It is designed for developers who value explicit structure, clear boundaries between application layers, and high-performance workflows. By organizing the core application code within an apps directory and isolating shared UI primitives in a packages workspace, it enables teams to build complex systems while maintaining a consistent design language.

  • TypeScript
  • 2 stars
  • 0 forks
  • updated 9mo ago

yabasha/yabasha-gex

Active

GEX is a versatile command-line interface tool designed to help developers audit, document, and manage their Node.js package environments. It provides a structured approach to generating reproducible reports for local projects and globally installed packages. By supporting multiple runtime environments—Node.js (npm), Bun, Yarn, and pnpm—it serves as a unified utility for teams needing to track dependency states, enforce license compliance, or simplify vulnerability auditing across diverse infrastructure.

  • TypeScript
  • 1 stars
  • 0 forks
  • updated 5mo ago

yabasha/cas

Active

@yabasha/cas is a command-line interface tool designed to instantly scaffold professional-grade, AI-ready monorepos. It is tailored for developers building production SaaS applications who require a standardized, high-performance foundation built on the Composable AI Stack. By providing interactive prompts and CLI-driven configuration, the tool allows users to selectively integrate complex architectural components like background workers, external API gateways, and automated evaluation harnesses without manual setup.

  • TypeScript
  • 0 stars
  • 0 forks
  • updated 5mo ago