Skip to main content

Module Development Guide

This guide covers developing external modules that live as separate git repos under the MoLOS monorepo.

Quick Start with CLI​

The fastest way to create a new module is using the built-in CLI:

# From MoLOS root directory
npm run module:create my-module --name "My Module" --author "Your Name" --description "My module description"

# Or with all defaults
npm run module:create my-module

This will create a complete module scaffold at modules/my-module with all necessary files and folders.

Manual Workflow​

If you prefer to start from a sample module manually:

  1. Create a new git repo
  2. Clone MoLOS main repo
  3. Clone MoLOS-Sample-Module or another working module as boilerplate
  4. Copy boilerplate into modules/<ModuleId>
  5. Run npm run module:sync to create symlinks and run migrations
  6. Run npm run dev to start development

Module Structure​

modules/<ModuleId>/
├── package.json # @molos/module-<module-id>
├── drizzle.config.ts # Database migration config (if has DB)
├── drizzle/ # Migration files (if has DB)
│ ├── 0000_initial.sql
│ ├── 0000_initial.down.sql
│ └── meta/
└── src/
├── index.ts # Main exports
├── config.ts # Module configuration (REQUIRED)
├── models/ # TypeScript types and enums
├── lib/ # Library code
│ ├── components/ # Svelte components
│ └── utils/ # Utility functions
├── server/
│ ├── ai/ # AI tools (optional)
│ │ └── ai-tools.ts
│ ├── database/ # Database schema (if has DB)
│ │ ├── schema/
│ │ │ ├── index.ts
│ │ │ └── tables.ts
│ └── repositories/ # Data access layer
│ ├── base-repository.ts
│ └── *.ts
├── routes/
│ ├── ui/ # SvelteKit UI routes
│ │ ├── +layout.svelte
│ │ ├── +page.svelte
│ │ └── */ # Sub-routes
│ └── api/ # API endpoints
│ └── +server.ts
└── stores/ # Svelte stores (Svelte 5 runes)

Development Map​

  1. Database Schema - Define tables and migrations
  2. TypeScript Models - Create type-safe interfaces and inputs
  3. Repository Layer - Implement data access logic
  4. API Endpoints - Build SvelteKit server routes
  5. UI Development - Create routes, components, and stores
  6. Module Configuration - Manifest + navigation config
  7. AI Integration - Optional AI tools for Architect Agent

Import Standards (CRITICAL)​

Module-Internal Code​

CRITICAL: When importing from within a module's own code, ALWAYS use the $module alias. This ensures imports work in both development and production builds.

// ✅ CORRECT: Use $module alias for module-internal imports
import { TaskRepository } from '$module/server/repositories/task-repository.js';
import { TaskStatus } from '$module/models/index.js';
import { myValidator } from '$module/server/utils/validator.js';

// ❌ WRONG: Fragile relative paths (break in production builds)
import { TaskRepository } from '../../../../../server/repositories/task-repository.js';
import { TaskStatus } from '../../../../models/index.js';

Main App Code​

Always use $lib alias for main app imports:

// ✅ ALWAYS use $lib alias
import { db } from '$lib/server/db';
import { Button } from '$lib/components/ui/button';
import { auth } from '$lib/server/auth';

// ❌ NEVER use relative paths (breaks in node_modules)
import { db } from '../../../../../src/lib/server/db';
import { Button } from '../../../../../src/lib/components/ui/button';

Cross-Module Imports​

Modules can import from other modules using two patterns:

// Pattern 1: $lib/modules/{ModuleName} - imports from module's lib directory
import { goalsStore } from '$lib/modules/MoLOS-Goals/stores';

// Pattern 2: $lib/models/external_modules/{ModuleName} - imports specific subdirectory
import { Goal } from '$lib/models/external_modules/MoLOS-Goals';

Database Migrations​

Migration Command Changes​

CRITICAL SAFETY RULE: NEVER RUN drizzle-kit generate

FORBIDDEN: Never run drizzle-kit generate or npm run db:generate. These commands are explicitly removed for safety.

Why:

  • Creates journal/SQL desync (migrations in journal but no SQL files)
  • Generates random names (0003_dizzy_jane_foster.sql) - zero context
  • Cannot enforce table naming conventions (MoLOS-{Name}_{table})
  • Overwrites manual migrations without warning

Correct Approach:

# Always create migrations manually with descriptive names
npm run db:migration:create --name add_new_feature --module <ModuleId> --reversible

# Validate after creating
npm run db:validate

# Apply (safe with auto-backup)
npm run db:migrate

Migration File Structure​

Forward Migration (0001_description.sql):

-- Migration: add_feature
-- Module: <ModuleId>
-- Created: 2026-03-17

CREATE TABLE <ModuleId>_items (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
name TEXT NOT NULL
);

--> statement-breakpoint

CREATE INDEX idx_<module>_items_user_id ON <ModuleId>_items(user_id);

Rollback Migration (0001_description.down.sql):

-- Rollback: add_feature
-- Module: <ModuleId>
-- Created: 2026-03-17

DROP INDEX IF EXISTS idx_<module>_items_user_id;

--> statement-breakpoint

DROP TABLE IF EXISTS <ModuleId>_items;

Configuration​

package.json​

{
"name": "@molos/module-<module-id>",
"version": "1.0.0",
"type": "module",
"exports": {
".": "./src/index.ts",
"./config": "./src/config.ts",
"./models": "./src/models/index.js",
"./database": "./src/server/database/schema.js"
},
"peerDependencies": {
"svelte": "^5.45.0"
},
"dependencies": {
"lucide-svelte": "^0.561.0"
}
}

config.ts (REQUIRED)​

import { SquareCheck, ListTodo } from 'lucide-svelte';
import type { ModuleConfig } from '$lib/config/types';

export const myModuleConfig: ModuleConfig = {
id: 'MoLOS-MyModule', // REQUIRED: Must match module ID convention
name: 'My Module',
href: '/ui/MoLOS-MyModule',
icon: SquareCheck,
description: 'Module description',
navigation: [
{
name: 'Dashboard',
icon: ListTodo,
href: '/ui/MoLOS-MyModule/dashboard'
}
]
};

export default myModuleConfig;

Svelte 5 Requirements​

State Management​

  • ✅ USE: Svelte 5 runes ($state, $derived, $props, $effect, $bindable)
  • ❌ AVOID: Svelte 4 stores (writable, readable, derived from 'svelte/store')

Exception: Existing modules may use Svelte 4 stores but migration is recommended.

Component Props​

  • ✅ USE: $props() for declaring component props in Svelte 5
  • ❌ AVOID: export let prop declarations (Svelte 4 legacy)

Exception: export let data is valid for passing data from +page.server.ts/+layout.server.ts load functions.

Shared State Files​

  • ✅ USE: .svelte.ts or .svelte.js files for shared reactive logic
  • ❌ AVOID: .ts files with exports of $state variables
// src/stores/entities.svelte.ts - CORRECT
let count = $state(0);
export const store = { get value() { return count; } };

Testing​

Run tests before pushing:

# Run all tests
npm run test

# Run tests in watch mode
npm run test:unit

Publishing​

Publish to npm​

# Build module
npm run build

# Publish
npm publish --access public

Submit to Modules Directory​

To be included in the official MoLOS Docker image, submit your module to the MoLOS modules directory.

Common Issues​

Import errors ($module/server/... not found)​

Ensure module code uses $module alias for internal imports, not relative paths.

Module not in sidebar​

Run npm run module:sync and verify config.ts exists.

Database table not found​

Create migration: npm run db:migration:create --name add_table --module <ModuleId> and then npm run db:migrate.


Last Updated: March 17, 2026