Skip to main content

Overview

Radish is a platform for designing, generating, and operating applications from structured blueprints.

Instead of producing throwaway prototypes or opaque AI-generated code, Radish compiles explicit application descriptions into maintainable architecture. The platform is designed to help developers move quickly from an application idea to a real system foundation that can be inspected, versioned, extended, and deployed.

Radish is built around a simple flow:

Intent → Blueprint → Architecture → Application

A user or team describes an application. That intent is translated into one or more structured blueprints. Radish compiles those blueprints into architecture layers. Developers and AI tools then build application behavior and presentation on top of that generated foundation.

The recommended entry point for new projects is radish init, which bootstraps a project directory with a blueprints/ folder, Claude Code skills, and a CLAUDE.md. From there, developers can use the generated /init slash command to create blueprints conversationally, then run radish create app to generate the full stack.

Core Components​

ComponentPurpose
Radish CLICompiles blueprints into generated architecture
Radish HubOrchestrates applications, blueprints, and deployments
Radish CloudHosted management for hubs, tenants, and environments
Radish LibLibrary of blueprint patterns, prompts, and reusable designs

What Radish Generates​

Radish generates a complete, production-ready application stack. Some infrastructure is always-on — present in every generated app with no flags to set. Other capabilities are feature-gated — enabled per-project in the app blueprint when you need them, absent when you don't. This keeps simple apps simple while giving complex apps the infrastructure they need without writing it from scratch.

Multi-Stack Generation​

Because blueprints describe what an application is — not how it's built — the same blueprint can compile to different technology stacks. Radish is opinionated about architecture and process but agnostic about language and framework.

StackLanguageFrameworkDatabaseStatus
Node (default)TypeScriptSvelteKitMongoDBProduction
LaravelPHPLaravelMySQL/PostgreSQLProduction
PythonPython——In development

Database adapters are also expanding: MongoDB is the default, with SQLite and localStorage adapters in progress for desktop and lightweight deployments.

The generation flag is a single option — radish create datalayer --stack laravel — and the same blueprints, roles, and features compile to the target stack's idioms: Eloquent models instead of Mongoose, Form Requests instead of Zod schemas, Sanctum instead of cookie sessions, Policies instead of service-layer guards.

Datalayer​

  • Contracts and validation (Zod schemas / Form Requests)
  • Repositories and persistence access (MongoDB/Mongoose, Eloquent)
  • Services with four-layer access control (see below)
  • Field metadata APIs for runtime introspection
  • REST API routes (SvelteKit / Laravel controllers)
  • Generated documentation (API docs, OpenAPI spec)

Four-Layer Access Control​

Every service method is gated by a layered authorization model. The layers compose — each narrows the result set from the previous one:

  1. RBAC — role-based permission check. Roles are defined in the roles blueprint and seeded at startup. Each role holds a set of permissions (entity:action), and the service rejects the call if the user's role lacks the required permission.
  2. Ownership — record-level filtering. Entities with "owned": true automatically scope queries to ownerId === currentUser for non-admin roles. Admins see everything; regular users see only their own records.
  3. Scoped access — tenant or organizational boundaries. Multi-tenant apps filter by tenantId so users in one tenant never see another tenant's data, even if they share the same role.
  4. Grants — per-record ACL (feature-gated: features.grants). Fine-grained sharing: "User A grants User B read access to this specific Order." Grants extend visibility beyond ownership without elevating the user's role.

This model is generated, not hand-wired. Define an entity's ownership mode and role permissions in the blueprints, and every service method, API route, and admin page respects the rules.

Application Scaffolding​

  • SvelteKit skeleton with route groups ((auth), (public), (app))
  • Admin panel with entity CRUD, user management, role management
  • Setup wizard at /setup for first-time admin creation
  • SEO infrastructure (sitemap.xml, robots.txt, llms.txt)
  • Login/logout with signed session cookies and API key support
  • Password recovery via PasswordResetToken (always-on builtin entity)
  • Theme layer generation (DaisyUI theme from blueprint)

Blueprint Verification & Versioning​

Blueprints are the source of truth. Radish tracks the relationship between blueprints and generated code:

  • Hash tracking — every generated file records which blueprint version produced it
  • Drift detection — radish verify compares current blueprint hashes against what was last generated, surfacing when code is stale
  • Orphan detection — finds generated files that no longer correspond to any blueprint entity (e.g., after removing an entity)
  • Doctor — radish doctor runs the full suite: blueprint validation, drift check, orphan scan, search index status
  • Convert — radish convert handles YAML ↔ JSON for teams migrating legacy blueprints
  • Migrate — radish migrate manages live schema migrations: generate diffs the current blueprint against the last snapshot and produces a migration file, status shows pending migrations, up applies them to MongoDB, and down rolls back the last applied migration

This means a team can answer "is this app in sync with its blueprints?" at any time, and CI can enforce it.


Always-On Infrastructure​

These subsystems are generated in every app — no feature flags, no configuration. They represent the baseline that every Radish app ships with.

Observability​

  • Correlation IDs on every request (generated, propagated through service calls)
  • Service instrumentation — every CRUD method tracked with timing and outcome
  • trackedFetch() for external API calls (Dynamics 365, Stripe, etc.) with automatic correlation
  • Structured logging with correlation-aware logger
  • Health endpoint with real-time metrics
  • Hub reporter for centralized monitoring across apps

Rate Limiting​

  • Default tiers: auth endpoints (20/min), API routes (100/min), public routes (60/min)
  • rateLimit() — apply a named tier to any route
  • registerTier() — define custom rate limit tiers
  • withRateLimit() — wrap custom endpoints with per-route limits
  • Automatic 429 Too Many Requests with Retry-After header

Idempotency​

  • Every mutating API call supports an Idempotency-Key header
  • Duplicate requests within the TTL return the original response without re-executing
  • Stored as IdempotencyKey entities with automatic expiry
  • Prevents double-creates from network retries, webhook replays, and client bugs

Scheduled Jobs​

  • Handler registry — registerJobHandler() with cron or interval scheduling
  • Timezone-aware cron evaluation and configurable timeouts
  • Full execution lifecycle: running → completed / failed / cancelled
  • Consecutive failure tracking with automatic reset on success
  • Manual trigger from admin panel (triggeredBy: 'manual')
  • Job Snapshots — declared metric shapes on handlers (dimensions, metrics, bucket grain)
    • Validated context.snapshot() API with in-memory buffering
    • Bucketed upsert for idempotency (re-runs overwrite, not duplicate)
    • series() and rollup() query methods with weighted-average support
    • Cardinality cap to prevent unbounded growth

Entity Versioning & Audit Trails​

Any entity can opt into change tracking by setting versioning in the types blueprint — no feature flag, no extra wiring. Radish generates the models, contracts, services, API endpoints, and admin UI for whichever strategy you choose:

  • Full versioning (versioning: "full") — complete entity snapshots on every change, version comparison (/versions/compare?a=3&b=5), and revert to any prior version (POST /revert/{version})
  • Simple versioning (versioning: "simple") — lightweight audit logs storing only field-level diffs (old/new values), 10–20× less storage than full snapshots
  • Field-level tracking (trackChanges: true on individual fields) — enhanced change metadata with approval workflows (pending → approved/rejected) for sensitive fields like pricing or contract terms
  • Strategies compose — an entity can use full versioning for compliance while also tracking critical fields with approval gates
  • All versioning respects the access control model — users need entity:view to see history, and change records always capture changedBy

Field-Level Encryption​

Sensitive data is encrypted at rest using AES-256-CBC, with two complementary mechanisms depending on where the secret lives:

  • Entity fields — declare any field as "type": "encryptedKey" in the types blueprint. The value is encrypted before writing to the database and decrypted on read through the service layer. API responses return [ENCRYPTED] — the raw ciphertext never leaves the server.
  • Settings with fieldSchema — the Settings entity stores complex objects (API credentials, integration configs) where only specific fields need encryption. Declare a fieldSchema marking which fields are encryptedKey, and the rest stay readable for debugging while secrets are encrypted:
    { "serverUrl": "string", "clientId": "string", "clientSecret": "encryptedKey" }
  • Single encryption key — both mechanisms use the same RADISH_ENCRYPTION_KEY environment variable. Missing key + encrypted field access produces a clear error with generation instructions, not a silent failure.
  • Scoped settings — Settings support a three-tier cascade (system → tenant → user) with encryption working at all levels, so tenant-specific API keys stay isolated and encrypted.
  • API masking — list() and REST responses mask encrypted fields as [ENCRYPTED]. Server-side code uses get() / getDecrypted() for plaintext access.

Feature-Gated Capabilities​

These are enabled per-project in the app blueprint (features: { search: true, cms: true, ... }). When disabled, zero code is generated for that feature — no dead imports, no unused models, no wasted surface area.

  • Typesense integration for full-text search, filtering, faceting
  • Index schemas with field type mapping and toSearchDoc() mappers
  • Index filters for membership control (match → upsert, no match → delete)
  • Search feedback entities (SearchQuery, SearchClick, SearchAssociation)
  • Inline and background sync modes
  • Search API endpoint (/api/v1/search)
  • CLI tools: radish search reindex, radish search status, radish search doctor

Grants (features.grants)​

  • Per-record ACL — share individual records with specific users
  • Grant entity with targetType, targetId, granteeId, permissions
  • Integrates with the access control layer — granted records appear alongside owned records in list queries
  • Service-level $or filtering: { ownerId } OR { _id: { $in: grantedIds } }
  • Revocation and expiry support

CMS (features.cms)​

  • ContentBlock — rich content with versioning, status lifecycle (draft → published → archived)
  • MediaAsset — file metadata with type classification and alt text
  • Attribute — key-value metadata attachable to any entity
  • FormTemplate — reusable form definitions with field schemas
  • Rule — conditional logic definitions for workflows and validation

Datasets (features.datasets)​

  • Analytics aggregation engine for metrics, KPIs, and reporting
  • DatasetDefinition — declares a dataset: source, grain columns, sync schedule, indexed dimensions
  • DatasetField — column definitions with aggregation type (sum, avg, count, min, max)
  • DatasetRow — time-series data points with dimension/metric pairs
  • Sync engine — source-agnostic, maps external data through column definitions into dataset rows
  • Rollup, trend, and topN query methods
  • Compound key upsert for idempotent sync (re-sync overwrites, never duplicates)

AI Context & Skills​

Radish generates a complete AI development environment alongside the application code. The goal is that an AI agent dropped into a generated project can immediately understand the architecture, follow the framework's conventions, and extend the application without breaking generated boundaries.

  • Slash commands — /api injects the full REST API reference (endpoints, auth, filters, response shapes); /radish re-injects project context (entities, fields, roles, features, directory ownership); /blueprint provides blueprint authoring context; /search provides search infrastructure context (generated conditionally when search-enabled entities exist)
  • Agent definitions — specialized agents (orchestrator, datalayer, roles, ui, admin) with focused file access boundaries and delegation rules
  • Skills — task-oriented procedures that agents invoke to perform common operations correctly:
    • add-entity — walk through adding a new entity to the blueprint, validate, regenerate
    • add-feature — enable and configure features (search, CMS, grants, datasets)
    • diagnose — run health checks across blueprints, generation status, and search indexes
    • init — guided blueprint generation for a new project
    • status — inspect current project state (entities, roles, features, generation drift)
  • Reference docs — the platform docs at .radish/docs/ and the app's generated API reference at .radish/lib/datalayer/docs/, both available to agents via @ imports
  • All context is derived from blueprints — entity-accurate, always current, regenerated alongside the application code

Deployment Artifacts​

  • Dockerfile (Debian slim, multi-stage build, healthcheck)
  • docker-compose.yml (production-ready)
  • .gitlab-ci.yml (Kaniko build, deploy trigger)
  • radish deploy init for Coolify provisioning

Design Priorities​

Radish is built to support:

  • deterministic generation — same blueprints always produce the same code
  • framework agnosticism — blueprints describe what, not how; the same definition compiles to Node/SvelteKit, Laravel/PHP, or future stacks
  • inspectable output — generated code is readable, not minified or obfuscated
  • blueprint versioning — track, diff, and audit changes to your application definition
  • AI-assisted workflows — generated context and skills keep AI agents aligned with the framework
  • feature gating — opt into complexity only when you need it
  • portability across repositories, packages, and deployment models
  • gradual evolution toward a broader application compiler