Modules
Create reusable TypeScript libraries shared across artifacts — utility functions, type definitions, shared constants, and helper wrappers for external services.
A module is a TypeScript file that can be imported by any artifact in your workspace. Modules let you share code without duplication — write a helper once, import it everywhere. Modules are versioned, tested, and deployed just like artifacts.
Creating a Module
Go to SDK → Modules → New Module. Give it a key (used as the import path) and write your exports.
import type { NodeContext } from '@flowos/sdk'
/**
* Build a standard incident title from components.
*/
export function formatIncidentTitle(service: string, description: string): string {
return `[${service}] ${description}`
}
/**
* Calculate priority from severity and urgency using the P-matrix.
*/
export function calculatePriority(severity: 'P1'|'P2'|'P3'|'P4', urgency: 'low'|'medium'|'high'): string {
if (severity === 'P1' || urgency === 'high') return 'P1'
if (severity === 'P2' || urgency === 'medium') return 'P2'
if (severity === 'P3') return 'P3'
return 'P4'
}
/**
* Find the on-call user for a team by querying the on-call schedule.
*/
export async function getOnCallUser(ctx: NodeContext, teamSlug: string): Promise<string | null> {
const schedules = await ctx.tables.query('on_call_schedules', {
filter: { team: teamSlug, active: true },
pageSize: 1,
})
return schedules.data[0]?.current_user_id ?? null
}Importing in Artifacts
Import a module using the @workspace/ prefix followed by the module key:
import { formatIncidentTitle, getOnCallUser } from '@workspace/itsm-helpers'
import type { NodeContext } from '@flowos/sdk'
export async function run(ctx: NodeContext) {
const title = formatIncidentTitle('API Gateway', 'returning 503 errors')
const onCall = await getOnCallUser(ctx, 'platform-engineering')
const incident = await ctx.tables.create('incidents', {
title,
assigned_to: onCall,
severity: 'P1',
status: 'open',
})
return { incidentId: incident.id }
}Module Manifest
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| key | string | required | — | Import path segment. @workspace/<key>. Must be unique. |
| name | string | required | — | Display name. |
| description | string | optional | — | What this module provides. |
| exports | string[] | optional | — | Declared public exports (for docs generation). Inferred from code if omitted. |
| dependencies | string[] | optional | — | Other module keys this module imports from. Circular deps are blocked. |
| tags | string[] | optional | — | Labels. |
Versioning
Every module save creates a new version. Artifacts pin to a specific version or to latest.
- •Artifacts using
@workspace/key(no version) always resolve to the latest deployed version. - •Pin to a specific version with
@workspace/key@3for stability. - •The dependency graph (SDK → Dependencies) shows which artifacts are affected when you publish a new module version.
- •Breaking a module's exports while artifacts depend on it raises a validation error at publish time.
Using npm Packages
You can import a curated set of pre-bundled npm packages inside modules and artifacts:
import { format, parseISO, differenceInHours } from 'date-fns'
import { z } from 'zod'
import _ from 'lodash'
import dayjs from 'dayjs'
import { marked } from 'marked'Packages are bundled at compile time. To request a package not on the approved list, go to SDK → Modules → Package Requests.
Type-Only Modules
Modules can export only TypeScript types — useful for sharing interface definitions across artifacts without any runtime code:
export interface IncidentContext {
incidentId: string
number: string
severity: 'P1' | 'P2' | 'P3' | 'P4'
assignedTeam: string
}
export type EscalationLevel = 'L1' | 'L2' | 'L3' | 'management'
export interface SlaPolicy {
responseHours: number
resolutionHours: number
businessHoursOnly: boolean
}types module. This creates a single source of truth for your domain model across all artifacts and avoids interface drift.