Flow SDK

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.

modules/itsm-helpers.ts
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:

typescript
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

FieldTypeRequiredDefaultDescription
keystringrequiredImport path segment. @workspace/<key>. Must be unique.
namestringrequiredDisplay name.
descriptionstringoptionalWhat this module provides.
exportsstring[]optionalDeclared public exports (for docs generation). Inferred from code if omitted.
dependenciesstring[]optionalOther module keys this module imports from. Circular deps are blocked.
tagsstring[]optionalLabels.

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@3 for 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:

typescript
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:

modules/types.ts
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
}
Group shared type definitions in a types module. This creates a single source of truth for your domain model across all artifacts and avoids interface drift.