DocumentationReference

HazelJS CLI Package

npm downloads

@hazeljs/cli provides a command-line interface for scaffolding HazelJS applications, generating components, and managing packages.

Quick Reference

  • Purpose: @hazeljs/cli scaffolds new HazelJS projects, generates controllers/services/modules, and manages package installation — eliminating boilerplate and enforcing best practices.
  • When to use: Use @hazeljs/cli when starting a new HazelJS project or generating new components (controllers, services, modules, guards, etc.).
  • Key concepts: hazel new <project> (scaffold project), hazel generate <type> <name> (generate component), hazel add <package> [--setup] (install HazelJS package + optional setup file), hazel eval <golden.json> (golden dataset smoke check via @hazeljs/eval), project templates.
  • Dependencies: Install globally with npm install -g @hazeljs/cli.
  • Common patterns: hazel new my-app -icd my-apphazel g crud usershazel add cache --setupnpm run dev.
  • Common mistakes: Not installing the CLI globally; running hazel generate outside a HazelJS project directory; not running npm install after scaffolding.

Installation

Install globally to use the hazel command anywhere:

npm install -g @hazeljs/cli

Or use it via npx without installing:

npx @hazeljs/cli new my-app

Architecture

The CLI uses a template-based generation system powered by Mustache. Every generator follows the same pattern: accept a name, resolve template data, render the template, and write the file.

graph LR
  A["hazel g controller users"] --> B["Generator Base Class"]
  B --> C["Mustache Template Engine"]
  C --> D["users.controller.ts"]

  style A fill:#3b82f6,stroke:#60a5fa,stroke-width:2px,color:#fff
  style B fill:#8b5cf6,stroke:#a78bfa,stroke-width:2px,color:#fff
  style C fill:#8b5cf6,stroke:#a78bfa,stroke-width:2px,color:#fff
  style D fill:#10b981,stroke:#34d399,stroke-width:2px,color:#fff

Key design decisions:

  • Config-driven simple generators — 17+ single-file generators (controller, service, guard, agent, etc.) are defined as configuration objects in a single file, eliminating code duplication
  • Centralized package registry — all HazelJS package metadata (npm names, import hints, module imports, setup templates) lives in one place, used by both hazel add and hazel new -i
  • Unified Generator class — every generator extends a base class with a suffix property, so files are consistently named (name.controller.ts, name.service.ts, name.guard.ts, etc.)
  • Shared utilitiestoPascalCase, toKebabCase, toCamelCase, and renderTemplate live in one place and are used by all generators
  • --dry-run support — every generator can preview what it would create without writing anything

Creating a New Application

Quick skeleton (fastest)

hazel g app my-app
cd my-app
npm install
npm run dev

This generates a minimal HazelJS application skeleton from the CLI template (without running installs or git init).

hazel new my-app

This scaffolds a complete HazelJS project with:

  • src/index.ts — entry point with CORS and proper HazelApp bootstrap
  • src/app.module.ts — root module with @HazelModule decorator
  • src/hello.controller.ts — example controller
  • package.json — dependencies, scripts (build, start, dev, test, lint, format), ESLint devDependencies
  • tsconfig.json — TypeScript config with decorators, strict mode, and rootDir: ./src
  • .eslintrc.js — ESLint config with TypeScript and Prettier
  • .gitignore — sensible defaults

Interactive Mode

hazel new my-app --interactive
# or
hazel new my-app -i

Interactive mode walks you through project setup:

  1. Description — project description for package.json
  2. Author — your name
  3. License — Apache-2.0 (default), MIT, GPL-3.0, BSD-3-Clause, or ISC
  4. Packages — select additional HazelJS packages to install

When you select packages in interactive mode, the CLI automatically:

  • Installs the npm packages
  • Updates app.module.ts with the correct imports and module registration
  • Creates .env and .env.example files when Config is selected
  • Sets up Swagger integration in index.ts when Swagger is selected

Available packages in interactive mode

PackageWhat gets scaffolded
@hazeljs/aiAIModule in app module
@hazeljs/agentAgentModule in app module
@hazeljs/authJwtModule.forRoot() in app module
@hazeljs/cacheCacheModule in app module
@hazeljs/configConfigModule.forRoot() + .env files
@hazeljs/cronCronModule in app module
@hazeljs/dataDataModule.forRoot() in app module
@hazeljs/discoveryInstalled — use ServiceRegistry/DiscoveryClient programmatically
@hazeljs/event-emitterEventEmitterModule.forRoot() in app module
@hazeljs/gatewayGatewayModule in app module
@hazeljs/graphqlGraphQLModule in app module
@hazeljs/grpcGrpcModule in app module
@hazeljs/kafkaKafkaModule in app module
@hazeljs/messagingMessagingModule in app module
@hazeljs/mlMLModule.forRoot() in app module
@hazeljs/mcpInstalled — use createMcpServer() for Model Context Protocol
@hazeljs/pdf-to-audioPdfToAudioModule in app module
@hazeljs/promptsInstalled — use PromptTemplate, PromptRegistry for typed prompts
@hazeljs/prismaPrismaModule in app module
@hazeljs/queueQueueModule in app module
@hazeljs/ragRAGModule in app module
@hazeljs/resilienceInstalled — use CircuitBreaker, WithRetry decorators in services
@hazeljs/serverlessInstalled — use createLambdaHandler in handler files
@hazeljs/swaggerSwaggerModule + updated index.ts with Swagger setup
@hazeljs/websocketWebSocketModule in app module

Options

FlagDescription
-d, --dest <path>Destination directory (default: .)
--skip-installSkip running npm install
--skip-gitSkip git init
-i, --interactiveInteractive project setup

hazel eval (golden dataset smoke check)

Loads a golden dataset JSON file through @hazeljs/eval using a placeholder runner (pass-through) to verify shape and dependencies. Use --ci to exit with code 1 when thresholds fail—useful in pipelines before you wire a real RAG or agent runner.

For production evaluation, call runGoldenDataset from your own script with HazelAI, agents, or RAG services. See the Eval package.

hazel eval ./eval/golden.json
hazel eval ./eval/golden.json --ci

Generating Components

All generators live under hazel generate (alias: hazel g). Every generator supports:

  • -p, --path <path> — custom output directory
  • --dry-run — preview files without writing them
  • --json — output a single JSON object with created paths and next steps

To discover everything that can be generated:

hazel g --list

For JSON output:

hazel g --list --list-json

Quick Reference

CommandAliasCreates
hazel g app <name>Skeleton application
hazel g controller <name>cname.controller.ts
hazel g service <name>sname.service.ts
hazel g module <name>mModule + controller + service + DTOs
hazel g dto <name>dname.dto.ts + update-name.dto.ts
hazel g guard <name>guname.guard.ts
hazel g interceptor <name>iname.interceptor.ts
hazel g middleware <name>mwname.middleware.ts
hazel g filter <name>fname.filter.ts
hazel g pipe <name>name.pipe.ts
hazel g crud <name>Full CRUD resource
hazel g authAuth module + JWT guard + DTOs
hazel g gateway <name>wsname.gateway.ts
hazel g repository <name>reponame.repository.ts
hazel g ai-service <name>ainame.ai-service.ts
hazel g agent <name>name.agent.ts
hazel g serverless <name>slsname.handler.ts
hazel g configapp.config.ts
hazel g cache <name>name.cache.ts
hazel g cron <name>jobname.cron.ts
hazel g rag <name>name.rag.ts
hazel g discovery <name>name.discovery.ts

Core Generators

Controller

hazel g controller users
# alias: hazel g c users

Generates users.controller.ts:

import { Controller, Get, Post, Body, Param, Delete, Put } from '@hazeljs/core';
import { UsersService } from './users.service';
import { CreateUsersDto } from './dto/create-users.dto';
import { UpdateUsersDto } from './dto/update-users.dto';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll() {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(id);
  }

  @Post()
  create(@Body(CreateUsersDto) createDto: CreateUsersDto) {
    return this.usersService.create(createDto);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body(UpdateUsersDto) updateDto: UpdateUsersDto) {
    return this.usersService.update(id, updateDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(id);
  }
}

Service

hazel g service users
# alias: hazel g s users

Generates users.service.ts:

import { Service } from '@hazeljs/core';

@Service()
export class UsersService {
  constructor() {}

  async findAll() {
    return [];
  }

  async findOne(id: string) {
    return { id };
  }

  async create(createDto: any) {
    return createDto;
  }

  async update(id: string, updateDto: any) {
    return { id, ...updateDto };
  }

  async remove(id: string) {
    return { id };
  }
}

Module

hazel g module users
# alias: hazel g m users

Generates a complete feature module with 5 files in src/users/:

FileDescription
users.module.tsModule with @HazelModule decorator
users.controller.tsController with @Controller
users.service.tsService with @Injectable
dto/create-users.dto.tsCreate DTO
dto/update-users.dto.tsUpdate DTO
// users.module.ts
import { HazelModule } from '@hazeljs/core';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@HazelModule({
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

DTO (Data Transfer Objects)

hazel g dto product
# alias: hazel g d product

Generates two files in src/dto/:

// product.dto.ts (Create)
import { IsString, IsOptional } from 'class-validator';

export class CreateProductDto {
  @IsString()
  name: string;

  @IsString()
  @IsOptional()
  description?: string;
}

// update-product.dto.ts (Update)
import { IsString, IsOptional } from 'class-validator';

export class UpdateProductDto {
  @IsString()
  @IsOptional()
  name?: string;

  @IsString()
  @IsOptional()
  description?: string;
}

Guard

hazel g guard auth
# alias: hazel g gu auth

Generates auth.guard.ts:

import { Service, type CanActivate, type ExecutionContext } from '@hazeljs/core';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    // Add your guard logic here
    return true;
  }
}

Interceptor

hazel g interceptor logging
# alias: hazel g i logging

Generates logging.interceptor.ts:

import { Service, Interceptor, type ExecutionContext } from '@hazeljs/core';

@Injectable()
export class LoggingInterceptor implements Interceptor {
  async intercept(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown> {
    // Pre-processing logic here
    const result = await next();
    // Post-processing logic here
    return result;
  }
}

Middleware

hazel g middleware logger
# alias: hazel g mw logger

Generates logger.middleware.ts:

import { Service, type MiddlewareHandler, type Request, type Response, type NextFunction } from '@hazeljs/core';

@Injectable()
export class LoggerMiddleware implements MiddlewareHandler {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(`[LoggerMiddleware] ${req.method} ${req.url}`);
    next();
  }
}

Exception Filter

hazel g filter http
# alias: hazel g f http

Generates http.filter.ts:

import { Catch, type ExceptionFilter, type ArgumentsHost, HttpError, logger } from '@hazeljs/core';

@Catch(HttpError)
export class HttpExceptionFilter implements ExceptionFilter<HttpError> {
  catch(exception: HttpError, host: ArgumentsHost): void {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    const status = exception.statusCode || 500;
    const message = exception.message || 'Internal server error';

    logger.error(`[${request.method}] ${request.url} - ${message} (${status})`);

    response.status(status).json({
      statusCode: status,
      message,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}

Pipe

hazel g pipe validation

Generates validation.pipe.ts:

import { type PipeTransform, type RequestContext } from '@hazeljs/core';

export class ValidationPipe implements PipeTransform {
  transform(value: unknown, context: RequestContext): unknown {
    // Transform logic here
    return value;
  }
}

CRUD Generator

The CRUD generator creates a complete REST resource in one command:

hazel g crud product

This generates 4 files in src/product/:

FileDescription
product.controller.tsFull CRUD controller (GET, POST, PUT, DELETE)
product.service.tsService with all CRUD operations
dto/product.dto.tsCreate and Update DTOs with class-validator
product.module.tsModule wiring everything together

Custom Route Path

hazel g crud product -r api/v1/products

This sets the controller route to /api/v1/products instead of the default /product.


Auth Generator

Scaffolds a complete authentication module in one command:

hazel g auth

Generates 6 files in src/auth/:

FileDescription
auth.module.tsAuth module with providers and exports
auth.service.tsService with register() and login() methods
auth.controller.tsController with POST /auth/register and /auth/login
jwt-auth.guard.tsJWT Bearer token guard using @hazeljs/auth
dto/register.dto.tsRegister DTO with email, name, password validation
dto/login.dto.tsLogin DTO with email, password validation

After generating, follow the next steps printed by the CLI:

  1. Import AuthModule in your app module
  2. Configure JwtModule.forRoot({ secret: "your-secret", expiresIn: "1d" })
  3. Install bcryptjs: npm install bcryptjs @types/bcryptjs
  4. Implement database integration in AuthService

Package-Specific Generators

WebSocket Gateway

hazel g gateway chat
# alias: hazel g ws chat

Generates chat.gateway.ts using @hazeljs/websocket:

import { Realtime, OnConnect, OnDisconnect, OnMessage, Subscribe, Client, Data, WebSocketClient } from '@hazeljs/websocket';

@Realtime('/chat')
export class ChatGateway {
  @OnConnect()
  handleConnection(@Client() client: WebSocketClient) {
    console.log('Client connected:', client.id);
  }

  @OnDisconnect()
  handleDisconnect(@Client() client: WebSocketClient) {
    console.log('Client disconnected:', client.id);
  }

  @Subscribe('message')
  @OnMessage('message')
  handleMessage(@Client() client: WebSocketClient, @Data() data: unknown) {
    console.log('Message received from', client.id, ':', data);
  }
}

Repository (Prisma)

hazel g repository user
# alias: hazel g repo user

Generates user.repository.ts extending BaseRepository from @hazeljs/prisma:

import { Repository } from '@hazeljs/prisma';
import { PrismaService } from '@hazeljs/prisma';

@Repository({ model: 'user' })
export class UserRepository extends BaseRepository<any> {
  constructor(prisma: PrismaService) {
    super(prisma.client.modelName);
  }

  async findByName(name: string) {
    return this.findMany({ where: { name } });
  }
}

AI Service

hazel g ai-service chat
# alias: hazel g ai chat

Generates chat.ai-service.ts using @hazeljs/ai:

import { Service } from '@hazeljs/core';
import { AIService, AIFunction, AIPrompt } from '@hazeljs/ai';

@Service()
export class ChatAIService {
  constructor(private readonly aiService: AIService) {}

  @AIFunction({
    provider: 'openai',
    model: 'gpt-4',
    streaming: false,
  })
  async chatTask(@AIPrompt() prompt: string): Promise<unknown> {
    const result = await this.aiService.complete({
      provider: 'openai',
      model: 'gpt-4',
      messages: [{ role: 'user', content: prompt }],
    });
    return result;
  }
}

AI Agent

hazel g agent research

Generates research.agent.ts using @hazeljs/agent:

import { Agent, Tool } from '@hazeljs/agent';

@Agent({
  name: 'research',
  description: 'A research agent',
  systemPrompt: 'You are a helpful Research agent.',
  enableMemory: true,
  enableRAG: true,
})
export class ResearchAgent {
  @Tool({
    description: 'Example tool for research',
    parameters: [
      { name: 'input', type: 'string', description: 'Input parameter', required: true },
    ],
  })
  async exampleTool(input: { input: string }): Promise<{ result: string }> {
    return { result: `Processed: ${input.input}` };
  }
}

Serverless Handler

# AWS Lambda (default)
hazel g serverless api
# alias: hazel g sls api

# Google Cloud Function
hazel g serverless api --platform cloud-function

Generates api.handler.ts:

// Lambda
import { createLambdaHandler } from '@hazeljs/serverless';
import { AppModule } from './app.module';
export const handler = createLambdaHandler(AppModule);

// Cloud Function
import { createCloudFunctionHandler } from '@hazeljs/serverless';
import { AppModule } from './app.module';
export const handler = createCloudFunctionHandler(AppModule);

Config

hazel g config

Generates app.config.ts with setup instructions for @hazeljs/config:

import { ConfigModule, ConfigService } from '@hazeljs/config';

// Add to your app module imports:
// ConfigModule.forRoot({ envFilePath: '.env' })
//
// Inject and use:
// this.config.get('DATABASE_URL');
// this.config.get('PORT', '3000');  // with default

Cache

hazel g cache product

Generates product.cache.ts with @Cacheable and @CacheEvict decorators from @hazeljs/cache:

import { Service } from '@hazeljs/core';
import { CacheService, Cacheable, CacheEvict } from '@hazeljs/cache';

@Service()
export class ProductCacheService {
  constructor(private readonly cacheService: CacheService) {}

  @Cacheable({ key: 'product:all', ttl: 60 })
  async findAll() {
    return [];
  }

  @CacheEvict({ key: 'product:all' })
  async create(data: any) {
    return data;
  }
}

Cron Jobs

hazel g cron cleanup
# alias: hazel g job cleanup

Generates cleanup.cron.ts with @Cron decorator from @hazeljs/cron:

import { Service } from '@hazeljs/core';
import { Cron, CronExpression } from '@hazeljs/cron';

@Service()
export class CleanupCronService {
  @Cron(CronExpression.EVERY_MINUTE)
  handleEveryMinute() {
    console.log('[CleanupCron] Running every minute...');
  }

  @Cron('0 0 * * *') // Every day at midnight
  handleDaily() {
    console.log('[CleanupCron] Running daily task...');
  }

  @Cron(CronExpression.EVERY_HOUR)
  handleHourly() {
    console.log('[CleanupCron] Running hourly cleanup...');
  }
}

RAG (Retrieval-Augmented Generation)

hazel g rag knowledge

Generates knowledge.rag.ts using @hazeljs/rag:

import { Service } from '@hazeljs/core';
import { RAGPipeline, MemoryVectorStore } from '@hazeljs/rag';

@Service()
export class KnowledgeRagService {
  private pipeline: RAGPipeline;

  constructor() {
    const vectorStore = new MemoryVectorStore();
    this.pipeline = new RAGPipeline({ vectorStore, topK: 5 });
  }

  async addDocument(content: string, metadata?: Record<string, unknown>) {
    await this.pipeline.addDocument({ content, metadata: metadata || {} });
  }

  async query(question: string) {
    return this.pipeline.query(question);
  }
}

Service Discovery

hazel g discovery app

Generates app.discovery.ts using @hazeljs/discovery:

import { Service } from '@hazeljs/core';
import { ServiceRegistry, DiscoveryClient } from '@hazeljs/discovery';

@Service()
export class AppDiscoveryService {
  constructor(
    private readonly registry: ServiceRegistry,
    private readonly client: DiscoveryClient,
  ) {}

  async registerService() {
    await this.registry.register({
      name: 'app-service',
      host: 'localhost',
      port: 3000,
      metadata: { version: '1.0.0' },
    });
  }

  async discoverService(serviceName: string) {
    return this.client.getInstances(serviceName);
  }
}

Adding Packages

The hazel add command installs HazelJS packages and shows usage hints:

hazel add auth

This runs npm install @hazeljs/auth and prints:

Usage:
  import { JwtModule } from "@hazeljs/auth";
  // JwtModule.forRoot({ secret: "your-secret", expiresIn: "1d" })

Generate a setup file

Use --setup to also generate a minimal starter file for the package:

hazel add swagger --setup
# Installs @hazeljs/swagger AND creates swagger.setup.ts

hazel add oauth --setup
hazel add kafka --setup

This replaces the old hazel g setup <package> command. The generated *.setup.ts file contains a ready-to-edit snippet so you can wire the package in without hunting through docs.

Interactive mode

hazel add

Without a package name, it shows an interactive list of all available packages.

Available packages

Short namenpm packageUsage hint
ai@hazeljs/aiAIModule
agent@hazeljs/agentAgentModule
auth@hazeljs/authJwtModule.forRoot()
cache@hazeljs/cacheCacheModule
config@hazeljs/configConfigModule.forRoot()
cron@hazeljs/cronCronModule
data@hazeljs/dataDataModule.forRoot()
discovery@hazeljs/discoveryServiceRegistry, DiscoveryClient
event-emitter@hazeljs/event-emitterEventEmitterModule.forRoot()
gateway@hazeljs/gatewayGatewayModule
graphql@hazeljs/graphqlGraphQLModule
grpc@hazeljs/grpcGrpcModule
kafka@hazeljs/kafkaKafkaModule
messaging@hazeljs/messagingMessagingModule
ml@hazeljs/mlMLModule.forRoot()
mcp@hazeljs/mcpcreateMcpServer()
pdf-to-audio@hazeljs/pdf-to-audioPdfToAudioModule
prisma@hazeljs/prismaPrismaModule
prompts@hazeljs/promptsPromptTemplate, PromptRegistry
queue@hazeljs/queueQueueModule
rag@hazeljs/ragRAGPipeline, RAGModule
resilience@hazeljs/resilienceCircuitBreaker, WithRetry, WithTimeout
serverless@hazeljs/serverlesscreateLambdaHandler
swagger@hazeljs/swaggerSwaggerModule
websocket@hazeljs/websocketWebSocketModule

Utility Commands

Info

Display information about the current HazelJS project:

hazel info

The --dry-run Flag

Every generator supports --dry-run to preview what would be created without writing any files:

hazel g module users --dry-run

Without --json, the CLI prints human-readable lines such as [dry-run] Would create /path/to/src/users/users.module.ts for each file.

The --json Flag

If you want machine-readable output, add --json. The CLI prints a single JSON object to stdout with ok, created (file paths), and optional nextSteps.

hazel g controller users --json

Example output (with --json):

{"ok":true,"created":["/path/to/project/src/users.controller.ts"]}

With --dry-run --json you get the same shape; created lists the paths that would be written. This is useful for scripts and automation.


Real-World Workflows

Building a REST API

Option A — Quick skeleton (no install/git):

hazel g app my-api
cd my-api
npm install
# Then generate features as below

Option B — Full interactive setup:

# 1. Create the project
hazel new my-api -i
# Select: config, swagger, prisma, auth

# 2. Generate the users feature
hazel g crud users

# 3. Generate the products feature
hazel g module products
hazel g repository product

# 4. Add caching
hazel add cache
hazel g cache product

# 5. Add cron jobs for cleanup
hazel add cron
hazel g cron cleanup

Building an AI Application

Option A — Quick skeleton: hazel g app ai-app then cd ai-app && npm install.

Option B — Interactive:

# 1. Create the project
hazel new ai-app -i
# Select: config, ai

# 2. Generate an AI service
hazel g ai-service chat

# 3. Add RAG for document retrieval
hazel add rag
hazel g rag knowledge

# 4. Create an AI agent
hazel add agent
hazel g agent research

Building a Real-Time Application

# 1. Create the project
hazel new realtime-app -i
# Select: config, auth, websocket

# 2. Generate auth module
hazel g auth

# 3. Generate WebSocket gateways
hazel g gateway chat
hazel g gateway notifications

Going Serverless

# 1. Create the project
hazel new serverless-api

# 2. Add serverless support
hazel add serverless

# 3. Generate the handler
hazel g serverless api --platform lambda
# or for GCP:
hazel g serverless api --platform cloud-function

Best Practices

  1. Use modules to organize features — Run hazel g module <feature> to get the full structure, then customize from there.

  2. Always use --dry-run first — Preview what will be generated before committing to disk.

  3. Leverage aliases — Use hazel g c, hazel g s, hazel g m for speed.

  4. Use -p for organization — Place controllers in feature directories: hazel g c users -p src/users.

  5. Start with CRUD — For standard REST resources, hazel g crud <name> gives you everything in one shot.

  6. Use interactive mode for new projectshazel new my-app -i sets up everything correctly from the start. For a minimal skeleton without installs, use hazel g app my-app then cd my-app && npm install.

What's Next?

Recipes

Recipe: Scaffold a New Project

# Minimal skeleton (fastest)
npx @hazeljs/cli g app my-app

# AI-Native application with agents, RAG, PostgreSQL, Docker
npx @hazeljs/cli g app my-ai-app --template=ai-native

# Full interactive setup with package selection
npx @hazeljs/cli new my-app -i

Recipe: Generate Components

# Generate a complete CRUD resource (recommended)
hazel g crud users

# Generate individual components
hazel g controller users
hazel g service users
hazel g module users

# Generate an AI agent
hazel g agent support

Recipe: Golden dataset smoke check

Validates a golden JSON file with @hazeljs/eval and a placeholder runner. Use --ci for a non-zero exit when scores fail. For real RAG or agent checks, use runGoldenDataset in application code — see Eval package.

hazel eval ./eval/golden.json
hazel eval ./eval/golden.json --ci