# ObjectStack Architecture > **v5.0 (2026): `project` → `environment`.** The runtime concept formerly called *Project* (per-tenant business workspace; Org/Project/Branch hierarchy) is now called *Environment* throughout the codebase: CLI flags (`--environment`/`-e`), HTTP paths (`/api/v1/environments/:environmentId/...`), headers (`X-Environment-Id`), env vars (`OS_ENVIRONMENT_ID`), exported symbols (`createSystemEnvironmentPlugin`, `SYSTEM_ENVIRONMENT_ID`), DB columns (`environment_id`), and JSON schemas (`EnvironmentArtifact`) all use the new term with no aliases or deprecation shims. The word "project" elsewhere in this document still refers to the npm/monorepo sense (i.e., the framework as a software project). See `.changeset/v5-project-to-environment-rename.md` for the full breaking-change list and ADR-0006 for the rationale. > **Architecture Document** - Updated January 2026 > > This document provides a comprehensive overview of ObjectStack's microkernel architecture, package distribution, and design principles. ## Table of Contents 1. [Architecture Overview](#architecture-overview) 2. [Microkernel Design](#microkernel-design) 3. [Package Structure](#package-structure) 4. [Layer Architecture](#layer-architecture) 5. [Plugin System](#plugin-system) 6. [Dependency Graph](#dependency-graph) 7. [Design Decisions](#design-decisions) 8. [Additional Resources](#additional-resources) --- ## Architecture Overview ObjectStack is built on a **microkernel architecture** inspired by operating system design principles. The system separates core functionality (the kernel) from business logic (plugins), enabling: - **Modularity**: Each component is independently developed, tested, and deployed - **Extensibility**: New features added through plugins without modifying core - **Testability**: Components can be mocked and tested in isolation - **Technology Independence**: Swap implementations without breaking contracts ### Core Principles 1. **Protocol-First Design**: All interactions defined through Zod schemas 2. **Separation of Concerns**: Three distinct layers (QL, OS, UI) 3. **Dependency Injection**: Services registered and consumed through DI container 4. **Event-Driven Communication**: Plugins communicate via hooks/events 5. **Reverse Domain Naming**: Global uniqueness through domain notation --- ## Microkernel Design ### The ObjectKernel **Location**: `packages/core/src/kernel.ts` The ObjectKernel is the heart of the system, providing: ``` ┌─────────────────────────────────────────────────────┐ │ ObjectKernel (Core) │ │ ┌───────────────────────────────────────────────┐ │ │ │ Plugin Lifecycle Manager │ │ │ │ • Dependency Resolution (Topological Sort) │ │ │ │ • Init → Start → Destroy Phases │ │ │ └───────────────────────────────────────────────┘ │ │ ┌───────────────────────────────────────────────┐ │ │ │ Service Registry (DI Container) │ │ │ │ • registerService(name, service) │ │ │ │ • getService(name): T │ │ │ └───────────────────────────────────────────────┘ │ │ ┌───────────────────────────────────────────────┐ │ │ │ Event Bus (Hook System) │ │ │ │ • hook(name, handler) │ │ │ │ • trigger(name, ...args) │ │ │ └───────────────────────────────────────────────┘ │ │ ┌───────────────────────────────────────────────┐ │ │ │ Logger (Pino-based) │ │ │ │ • Server: JSON logs to stdout │ │ │ │ • Browser: Console with pretty formatting │ │ │ └───────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────┘ │ ┌─────────┴─────────┬──────────┬──────────┐ │ │ │ │ ┌───▼────┐ ┌───────▼──┐ ┌──▼───┐ ┌───▼────┐ │ObjectQL│ │ Driver │ │ Hono │ │ App │ │ Plugin │ │ Plugin │ │Server│ │ Plugin │ └────────┘ └──────────┘ └──────┘ └────────┘ ``` ### Plugin Lifecycle ``` State Machine: ┌────────┐ │ idle │ ← Initial state └───┬────┘ │ kernel.use(plugin) ▼ ┌────────┐ │ init │ ← Register services, subscribe to hooks └───┬────┘ │ kernel.bootstrap() ▼ ┌────────┐ │ start │ ← Connect to databases, start servers └───┬────┘ │ ▼ ┌─────────┐ │ running │ └───┬─────┘ │ kernel.shutdown() ▼ ┌─────────┐ │ destroy │ ← Clean up resources └─────────┘ ``` --- ## Package Structure ObjectStack is organized as a **monorepo** with distinct package layers: ### Core Packages #### `@objectstack/spec` **Location**: `packages/spec/` **Role**: Protocol Definitions (The "Constitution") - Zod schemas for all protocols (ObjectQL, ObjectOS, ObjectUI) - TypeScript type definitions - JSON Schema generation - Constants and enums - **Zero runtime dependencies** (except Zod) ```typescript // packages/spec/src/ ├── data/ # ObjectQL schemas (Object, Field, Query, etc.) ├── ui/ # ObjectUI schemas (App, View, Dashboard, etc.) ├── system/ # ObjectOS schemas (Manifest, Driver, Plugin, etc.) ├── automation/ # Workflow, Flow, Trigger schemas ├── ai/ # Agent, RAG, Model schemas ├── api/ # API contract schemas ├── auth/ # Authentication & Authorization schemas └── shared/ # Common utilities ``` #### `@objectstack/core` **Location**: `packages/core/` **Role**: Microkernel Runtime - `ObjectKernel` - Plugin lifecycle manager - `PluginContext` - Runtime context for plugins - `Logger` - Universal logging (Pino-based) - Service Registry (DI Container) - Event Bus (Hook System) **Dependencies**: `@objectstack/spec`, `pino`, `zod` #### `@objectstack/types` **Location**: `packages/types/` **Role**: Shared Runtime Interfaces - Type definitions used across packages - Runtime environment types - Minimal, focused on shared contracts **Dependencies**: `@objectstack/spec` ### Engine Packages #### `@objectstack/objectql` **Location**: `packages/objectql/` **Role**: ObjectQL Query Engine - ObjectQL core engine - Schema registry - Query compilation - Driver management - Protocol implementation **Dependencies**: `@objectstack/core`, `@objectstack/spec`, `@objectstack/types` #### `@objectstack/metadata` **Location**: `packages/metadata/` **Role**: Metadata Loading & Persistence - Metadata serialization/deserialization (JSON, YAML, TypeScript) - File system operations (load, save, watch) - Validation using Zod schemas - ETag-based caching - Import/export tools - SchemaRegistry persistence bridge **Dependencies**: `@objectstack/spec`, `@objectstack/core`, `@objectstack/types`, `glob`, `js-yaml`, `chokidar` #### `@objectstack/runtime` **Location**: `packages/runtime/` **Role**: Runtime Utilities & Plugins - `DriverPlugin` - Generic driver wrapper - `AppPlugin` - Application loader - HTTP Server utilities - REST API server - Middleware system **Dependencies**: `@objectstack/core`, `@objectstack/spec`, `@objectstack/types` ### Client Packages #### `@objectstack/client` **Location**: `packages/client/` **Role**: Official TypeScript Client SDK for ObjectStack Protocol **Features**: - **Auto-Discovery**: Connects to ObjectStack server and auto-configures API endpoints - **Typed Metadata**: Retrieve Object and View definitions with full TypeScript support - **Metadata Caching**: ETag-based conditional requests for efficient metadata caching - **Data Operations**: - Advanced queries with filtering, sorting, and field selection - CRUD operations (create, read, update, delete) - Batch operations with transaction support (batch create/update/upsert/delete) - Query builder with type-safe filters - **View Storage**: Save, load, share, and manage custom UI view configurations - **Error Handling**: Standardized error codes with retry guidance - **HTTP Caching**: ETag support for optimized metadata requests **API Surface**: - `client.connect()`: Initialize client with server discovery - `client.meta.*`: Metadata operations (getObject, getCached, getView) - `client.data.*`: Data operations (find, get, query, create, batch, update, delete) - `client.views.*`: View storage operations (create, get, list, update, delete, share) **Dependencies**: `@objectstack/core`, `@objectstack/spec` #### `@objectstack/client-react` **Location**: `packages/client-react/` **Role**: React Hooks for ObjectStack Client SDK **Features**: - **Data Hooks**: `useQuery`, `useMutation`, `usePagination`, `useInfiniteQuery` - **Metadata Hooks**: `useObject`, `useView`, `useFields`, `useMetadata` - **Context Management**: `ObjectStackProvider`, `useClient` - **Type Safety**: Full TypeScript generics support for type-safe data - **Auto-refetch**: Automatic data refetching and caching - **Loading States**: Built-in loading and error state management **Dependencies**: `@objectstack/client`, `@objectstack/core`, `@objectstack/spec` **Peer Dependencies**: `react` ### Plugin Packages Located in `packages/plugins/*`: #### `@objectstack/driver-memory` **Location**: `packages/plugins/driver-memory/` **Role**: In-Memory Driver (Reference Implementation) - Complete ObjectQL driver implementation - Used for testing and prototyping - Demonstrates driver contract **Dependencies**: `@objectstack/core`, `@objectstack/spec` #### `@objectstack/plugin-hono-server` **Location**: `packages/plugins/plugin-hono-server/` **Role**: HTTP Server Plugin - Hono-based HTTP server - REST API endpoints - Middleware support **Dependencies**: `@objectstack/core`, `@objectstack/spec`, `@objectstack/types`, `hono` #### `@objectstack/plugin-msw` **Location**: `packages/plugins/plugin-msw/` **Role**: Mock Service Worker Plugin - Browser-based API mocking - E2E testing support - Development mode **Dependencies**: `@objectstack/objectql`, `@objectstack/spec`, `@objectstack/types`, `msw` ### Tools Packages #### `@objectstack/cli` **Location**: `packages/cli/` **Role**: Command Line Interface - Project scaffolding - Code generation - Development tools - Build & deployment utilities **Dependencies**: `@objectstack/spec`, `commander`, `chalk`, `tsx`, `zod` --- ## Layer Architecture ObjectStack follows a **Three-Layer Protocol Stack**: ``` ┌──────────────────────────────────────────────────┐ │ Layer 3: ObjectUI (View) │ │ ┌────────────────────────────────────────────┐ │ │ │ Apps, Views, Dashboards, Reports │ │ │ │ "How do users interact?" │ │ │ └────────────────────────────────────────────┘ │ │ Packages: @objectstack/client-react │ └────────────────┬─────────────────────────────────┘ │ REST API / GraphQL ┌────────────────▼─────────────────────────────────┐ │ Layer 2: ObjectOS (Control) │ │ ┌────────────────────────────────────────────┐ │ │ │ Auth, Permissions, Workflows, Events │ │ │ │ "Who can do what, when?" │ │ │ └────────────────────────────────────────────┘ │ │ Packages: @objectstack/runtime, │ │ @objectstack/plugin-hono-server │ └────────────────┬─────────────────────────────────┘ │ ObjectQL Protocol ┌────────────────▼─────────────────────────────────┐ │ Layer 1: ObjectQL (Data) │ │ ┌────────────────────────────────────────────┐ │ │ │ Objects, Fields, Queries, Drivers │ │ │ │ "What is the data structure?" │ │ │ └────────────────────────────────────────────┘ │ │ Packages: @objectstack/objectql, │ │ @objectstack/driver-* │ └──────────────────────────────────────────────────┘ Foundation: ┌──────────────────────────────────────────────────┐ │ @objectstack/core (Microkernel) │ │ @objectstack/spec (Protocols) │ │ @objectstack/types (Shared Types) │ └──────────────────────────────────────────────────┘ ``` ### Layer Boundaries | Layer | Knows About | Doesn't Know About | |-------|-------------|-------------------| | **ObjectQL** | Schema, fields, queries, drivers | Users, permissions, UI | | **ObjectOS** | Auth, workflows, events | Data structure, UI layout | | **ObjectUI** | Layout, navigation, actions | Business logic, storage | --- ## Plugin System ### Plugin Interface ```typescript interface Plugin { name: string; // Reverse domain notation version?: string; // Semantic version dependencies?: string[]; // Plugin names this depends on init(ctx: PluginContext): Promise | void; start?(ctx: PluginContext): Promise | void; destroy?(): Promise | void; } ``` ### Built-in Plugins #### ObjectQLPlugin **Name**: `com.objectstack.engine.objectql` **Location**: `packages/objectql/src/plugin.ts` ```typescript Services Registered: - 'objectql': ObjectQL engine instance - 'protocol': Protocol implementation shim Lifecycle: - init: Register ObjectQL as service - start: Discover and register drivers and apps ``` #### DriverPlugin **Name**: `com.objectstack.driver.{name}` **Location**: `packages/runtime/src/driver-plugin.ts` ```typescript Services Registered: - 'driver.{name}': Driver instance Lifecycle: - init: Register driver service - start: Log driver started ``` #### AppPlugin **Name**: `com.objectstack.app.{name}` **Location**: `packages/runtime/src/app-plugin.ts` ```typescript Services Registered: - 'app.{name}': Manifest instance Lifecycle: - init: Register app manifest as service ``` ### Plugin Capability Declaration **Location**: `packages/spec/src/system/plugin-capability.zod.ts` Plugins declare capabilities through structured manifests: ```typescript interface PluginCapabilityManifest { implements?: PluginCapability[]; // Protocols implemented provides?: PluginInterface[]; // Services exposed requires?: PluginDependency[]; // Required plugins extensionPoints?: ExtensionPoint[]; // Extension hooks extensions?: Extension[]; // Extensions contributed } ``` --- ## Dependency Graph ### Core Dependencies ``` @objectstack/spec (Zod schemas, zero runtime deps except zod) ↑ ├── @objectstack/types │ ↑ │ └── (Shared by many packages) │ ├── @objectstack/core (Kernel + Logger) │ ↑ │ ├── @objectstack/objectql (Query Engine) │ │ ↑ │ │ └── @objectstack/plugin-msw │ │ │ ├── @objectstack/metadata (Metadata I/O) │ │ ↑ │ │ ├── @objectstack/runtime (Uses for manifest loading) │ │ ├── @objectstack/cli (Uses for code generation) │ │ └── @objectstack/objectql (Uses for registry persistence) │ │ │ ├── @objectstack/runtime (Plugins & HTTP) │ │ ↑ │ │ └── (Used by server plugins) │ │ │ ├── @objectstack/client │ │ ↑ │ │ └── @objectstack/client-react │ │ │ └── @objectstack/driver-memory │ ├── @objectstack/cli (Standalone tool) ``` ### Dependency Rules 1. **`@objectstack/spec` has ZERO dependencies** (except Zod) - Pure protocol definitions - Can be used standalone for type-checking 2. **`@objectstack/core` depends only on `@objectstack/spec`** - Minimal kernel - No knowledge of ObjectQL or UI 3. **`@objectstack/objectql` depends on `core` and `spec`** - Pluggable into kernel - Independent of UI layer 4. **Plugins depend on `core` and optionally `objectql`** - Never depend on other plugins directly - Use service registry for runtime coupling 5. **No circular dependencies** - Enforced through topological sort - Build-time validation --- ## Design Decisions ### 1. Microkernel vs Monolithic **Decision**: Use microkernel architecture **Rationale**: - Business logic isolated in plugins - Core remains stable - Easy to swap implementations - Better testability **Tradeoffs**: - More complex setup - Plugin discovery overhead - Learning curve for plugin API ### 2. Zod-First Schema Definition **Decision**: All schemas defined with Zod **Rationale**: - Runtime validation - TypeScript inference - JSON Schema generation - Single source of truth **Implementation**: ```typescript // Define once with Zod export const FieldSchema = z.object({ ... }); // TypeScript types inferred export type Field = z.infer; // JSON Schema generated at build time ``` ### 3. Reverse Domain Naming **Decision**: Use reverse domain notation for plugins **Rationale**: - Global uniqueness - Industry standard (OSGi, Eclipse, Android) - Clear ownership - Hierarchical organization **Examples**: - `com.objectstack.engine.objectql` - `com.objectstack.driver.postgres` - `com.acme.crm.customer-management` ### 4. Service Registry Pattern **Decision**: Use DI container for service discovery **Rationale**: - Loose coupling - Runtime flexibility - Easy mocking for tests - No hard dependencies **Alternative Considered**: Direct imports **Rejected Because**: Creates tight coupling ### 5. Event-Driven Communication **Decision**: Use hook/event system for inter-plugin communication **Rationale**: - Decoupled communication - Multiple subscribers - Async handling - Extensibility **Standard Events**: ```typescript // Kernel lifecycle 'kernel:init' 'kernel:ready' 'kernel:shutdown' // Data lifecycle 'data:record:beforeCreate' 'data:record:afterCreate' 'data:record:beforeUpdate' 'data:record:afterUpdate' ``` ### 6. Three-Layer Protocol Stack **Decision**: Separate QL, OS, UI into distinct layers **Rationale**: - Separation of concerns - Technology independence - Parallel development - Incremental migration **See Also**: [content/docs/introduction/architecture.mdx](content/docs/introduction/architecture.mdx) ### 7. Monorepo Structure **Decision**: Use pnpm workspaces **Rationale**: - Shared dependencies - Atomic commits - Easier refactoring - Consistent versioning **Build Order**: 1. `@objectstack/spec` 2. `@objectstack/types`, `@objectstack/core` 3. `@objectstack/objectql`, `@objectstack/runtime` 4. Plugins and clients ### 8. Plugin vs Package **Decision**: Not all packages are plugins **Rationale**: - `@objectstack/spec` - Pure data, no runtime - `@objectstack/cli` - Standalone tool - `@objectstack/core` - Kernel, not a plugin **Plugin Packages**: Implement `Plugin` interface and can be registered with kernel --- ## Package Naming Conventions ### Package-Level Identifiers (Distribution) **Format**: `@objectstack/{category}-{name}` **Style**: `kebab-case` **Examples**: - `@objectstack/driver-memory` - `@objectstack/plugin-hono-server` - `@objectstack/client-react` ### Plugin Identifiers (Runtime) **Format**: `{domain}.{category}.{name}` **Style**: `kebab-case` **Examples**: - `com.objectstack.engine.objectql` - `com.objectstack.driver.postgres` - `com.acme.crm.customer-management` ### Code-Level Identifiers **Configuration Keys**: `camelCase` ```typescript { maxLength: 120, defaultValue: 'hello' } ``` **Data Values**: `snake_case` ```typescript { name: 'first_name', object: 'project_task' } ``` --- ## Additional Resources ### Architecture Decision Records (ADRs) Important architectural decisions are documented as ADRs in `docs/adr/`: - [ADR-0001: Metadata Service Architecture](docs/adr/0001-metadata-service-architecture.md) - Explains why both ObjectQL and MetadataPlugin can provide metadata service and how they work together ### Component-Specific Documentation - [Metadata Flow Documentation](docs/METADATA_FLOW.md) - Detailed explanation of how metadata flows from definition to runtime, including configuration examples and troubleshooting --- ## Future Considerations ### Planned Enhancements 1. **Plugin Versioning & Compatibility** - SemVer range matching - Breaking change detection - Deprecation warnings 2. **Plugin Registry & Hub** - Centralized plugin discovery - Quality scoring - Security scanning 3. **Hot Reload** - Runtime plugin reload - State preservation - Development mode 4. **Multi-Tenancy** - Kernel per tenant - Resource isolation - Shared plugin instances 5. **Enhanced Logging** - Structured logging - Distributed tracing - Performance metrics --- ## Related Documentation - [Quick Reference Guide](./QUICK-REFERENCE.md) - Fast lookup for common tasks - [Package Dependency Graph](./PACKAGE-DEPENDENCIES.md) - Complete dependency visualization - [Development Roadmap](./ROADMAP.md) - Next-phase optimization & improvement plan - [Studio Roadmap](./apps/studio/ROADMAP.md) - Studio IDE development plan - [MicroKernel Architecture Guide](./content/docs/developers/micro-kernel.mdx) - [Plugin Ecosystem Architecture](./content/docs/developers/plugin-ecosystem.mdx) - [Writing Plugins](./content/docs/developers/writing-plugins.mdx) - [Three-Layer Stack](./content/docs/introduction/architecture.mdx) - [Design Principles](./content/docs/introduction/design-principles.mdx) --- **Last Updated**: February 2026 **Maintainers**: ObjectStack Core Team **Status**: Living Document