Skip to Content
DocumentationBuildFundamentalsModules & Workspaces

Modules & Workspaces

Loopstack uses NestJS modules to organize your application. Workflows and tools are registered as standard NestJS providers.

Modules

A module groups related workflows, tools, and services together.

Basic Module

import { Module } from '@nestjs/common'; import { ClaudeModule } from '@loopstack/claude-module'; import { MyTool } from './tools/my.tool'; import { MyWorkflow } from './workflows/my.workflow'; @Module({ imports: [ClaudeModule], providers: [MyWorkflow, MyTool], exports: [MyWorkflow, MyTool], }) export class MyFeatureModule {}

Key Rules

  • LoopCoreModule is global — registered once by LoopstackModule.forRoot(), do not import it in feature modules
  • Import feature modules like ClaudeModule for AI, SandboxToolModule for Docker sandboxes, etc.
  • Documents are NOT providers — they are plain DTOs and don’t need registration
  • Export workflows and tools that other modules might need

Registering in AppModule

Add your module to the main AppModule:

import { Module } from '@nestjs/common'; import { LoopstackModule } from '@loopstack/loopstack-module'; import { MyFeatureModule } from './my-feature/my-feature.module'; @Module({ imports: [LoopstackModule.forRoot(), MyFeatureModule], }) export class AppModule {}

Multi-Module Example

For larger applications, split functionality across modules:

// analytics.module.ts @Module({ imports: [ClaudeModule], providers: [AnalyticsWorkflow, DataFetchTool], exports: [AnalyticsWorkflow], }) export class AnalyticsModule {} // notifications.module.ts @Module({ providers: [NotificationWorkflow, EmailTool], exports: [NotificationWorkflow], }) export class NotificationsModule {} // app.module.ts @Module({ imports: [LoopstackModule.forRoot(), AnalyticsModule, NotificationsModule], }) export class AppModule {}

Module Configuration (forRoot / forFeature)

Many Loopstack modules support forRoot() and forFeature() for configuring defaults. This follows the standard NestJS dynamic module pattern.

  • forRoot(config) — sets global defaults for the module. Call once in your root AppModule.
  • forFeature(config)overrides defaults for a specific feature module. Tools in that module use the override instead of the global.
// app.module.ts — global default: all LLM calls use claude-sonnet-4-6 @Module({ imports: [ LoopstackModule.forRoot(), LlmProviderModule.forRoot({ model: 'claude-sonnet-4-6' }), ClaudeModule, MyFeatureModule, ], }) export class AppModule {} // my-feature.module.ts — this module's LLM calls use claude-opus-4-6 instead @Module({ imports: [LlmProviderModule.forFeature({ model: 'claude-opus-4-6' })], providers: [MyWorkflow], }) export class MyFeatureModule {}

Modules that support this pattern include LlmProviderModule, RemoteClientModule, SecretsModule, and others. Per-call config (via options.config) always takes priority over module defaults.

Dependency Injection

Workflows and tools use standard NestJS constructor injection:

@Workflow({ widget: __dirname + '/chat.ui.yaml', }) export class ChatWorkflow extends BaseWorkflow { constructor( private readonly llmGenerateText: LlmGenerateTextTool, private readonly myTool: MyCustomTool, ) { super(); } }

Sub-workflows are also injected via constructor:

export class ParentWorkflow extends BaseWorkflow { constructor(private readonly subWorkflow: SubWorkflow) { super(); } }

Using in Loopstack Studio

Once registered:

  1. Open Loopstack Studio at http://localhost:5173
  2. Your workspace appears in the sidebar
  3. Click a workflow to create a new run
  4. Fill in the input form and start the workflow

Registry References

Last updated on