This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Azu CLI is a feature-complete, production-ready command-line interface for the Azu Toolkit - a Rails-like framework for Crystal that provides database management, code generation, hot reloading, and comprehensive development tools.
- Language: Crystal 1.16.3
- CLI Framework: Topia (https://github.com/azutoolkit/topia)
- Target Frameworks:
- Azu Web Framework (https://github.com/azutoolkit/azu)
- CQL ORM (https://github.com/azutoolkit/cql)
- JoobQ (https://github.com/azutoolkit/joobq)
# Install dependencies
shards install
# Build the CLI
shards build --production --ignore-crystal-version
# Run the CLI directly during development
crystal run src/azu_cli.cr -- [command] [args]
# Install locally for testing
make install# Run all tests
crystal spec
# Run specific test file
crystal spec spec/azu_cli/integration/joobq_generator_spec.cr
# Run tests in watch mode (using azu test command in a generated project)
azu test --watch# Build via Makefile (recommended)
make build
# Build manually
crystal build -o bin/azu src/azu_cli.cr -p --no-debug# Install globally (may require sudo)
make install
# Install man page
make install-man
# Uninstall
make clean-
CLI Framework (src/azu_cli/cli.cr)
- Uses Topia for command parsing and routing
- Middleware system for logging, error handling, and configuration
- Plugin architecture for extensibility
- Command registration happens in
CLI#setup_commands
-
Commands (src/azu_cli/commands/)
- All commands inherit from
Commands::Base - Base class provides argument parsing, error handling, and validation
- Command execution returns
Commands::Resultwith success/error state - Database commands in
commands/db/ - Job queue commands in
commands/jobs/
- All commands inherit from
-
Generators (src/azu_cli/generators/)
- Use Teeplate for file tree generation
- Each generator inherits from
Teeplate::FileTree - Template files use ECR (Embedded Crystal) in
templates/directory - Generators support:
- Models (CQL ORM)
- Endpoints (HTTP handlers)
- Services (business logic)
- Scaffolds (complete CRUD)
- Authentication (JWT/Session)
- Jobs (JoobQ background jobs)
- Channels (WebSocket)
- Migrations
-
Templates (src/azu_cli/templates/)
project/- New project scaffoldingscaffold/- CRUD component generationauth/- Authentication systemjoobq/- Background job infrastructure- All use
.ecrextension for template files - Variables interpolated using
<%= @variable %>syntax
-
Middleware (src/azu_cli/middleware/)
- Logging middleware for command execution
- Error handler for consistent error reporting
- Configuration middleware for environment setup
- Executed before/after each command via
CLI#execute_command
-
Plugins (src/azu_cli/plugins/)
- Base plugin system using
Plugins::Base - Built-in plugins: GeneratorPlugin, DatabasePlugin, DevelopmentPlugin
- Hooks:
on_load,before_command,after_command,on_error
- Base plugin system using
Command Pattern: Each CLI command is a class with execute method returning Result
Template Pattern: Generators use Teeplate with ECR templates for code generation
Middleware Pipeline: Commands pass through middleware chain for logging, config, error handling
Plugin System: Extensibility through plugin hooks at CLI lifecycle events
Type Safety: Crystal's type system enforced throughout - explicit type annotations for public APIs
- Migration system uses CQL's
Migratorclass - Automatic schema synchronization to
src/db/schema.cr - Migration files in
db/migrations/with timestamp prefixes - Supports PostgreSQL, MySQL, SQLite
- Models use
CQL::Recordwith macro-powered DSL
- User runs
azu generate [type] [name] [attributes] Commands::Generateparses arguments and options- Appropriate generator instantiated (e.g.,
Generate::Model) - Generator initializes with name, attributes, options
- Teeplate renders ECR templates with instance variables
- Files written to appropriate directories in project structure
- Custom error categories defined in
Config::ErrorCategory - Error severity levels: DEBUG, INFO, WARN, ERROR, FATAL
Commands::Base#handle_errorprovides consistent error formatting- Debug mode shows full stack traces
- Exit codes: 0 (success), 1 (failure), 2 (invalid usage)
- Commands: PascalCase classes (e.g.,
Commands::DB::Migrate) - Generators: PascalCase classes (e.g.,
Generate::Model) - Files: snake_case (e.g.,
user_model.cr) - Templates: snake_case with .ecr extension
- Template variables: snake_case instance variables (
@snake_case_name)
project_name/
├── src/
│ ├── models/ # CQL models
│ ├── endpoints/ # HTTP request handlers
│ ├── requests/ # Request validation
│ ├── pages/ # Response pages
│ ├── services/ # Business logic
│ ├── jobs/ # Background jobs
│ ├── channels/ # WebSocket channels
│ ├── middleware/ # HTTP middleware
│ ├── initializers/ # App initialization
│ └── db/
│ ├── migrations/ # Database migrations
│ ├── schema.cr # Auto-generated schema
│ └── seed.cr # Seed data
├── public/
│ └── templates/ # Jinja templates
├── spec/ # Tests
└── config/ # Configuration files
Common template variables:
@name- Original name (e.g., "User")@snake_case_name- Underscored (e.g., "user")@resource_plural- Pluralized (e.g., "users")@table_name- Database table (e.g., "users")@attributes- Hash of attribute names to types@timestamps- Boolean for created_at/updated_at@module_name- Schema/module context
When parsing attribute arguments like name:string email:string:unique age:int32:
- Format:
name:type[:modifier] - Types:
string,int32,int64,float64,bool,time,uuid - Modifiers:
unique,index,required - References:
user_id:int64:ref:userscreates foreign key
Models use CQL::Record with schema DSL:
module AppSchema
@[CQL::Model(table_name: users)]
struct User < CQL::Record(Int64)
property name : String
property email : String
db_context AppDatabase
end
endMigrations use CQL Schema DSL:
class CreateUsers < CQL::Migration(timestamp)
def up
schema.table :users do
primary :id, Int64
column :name, String
column :email, String, unique: true
timestamps
end
schema.users.create!
end
end- Background job infrastructure setup via
azu generate joobq - Jobs inherit from JoobQ job classes
- Configuration in
config/joobq.{environment}.yml - Worker process started with
azu jobs:worker - Queue monitoring via
azu jobs:statusorazu jobs:ui
Commands::Base#parse_args handles:
- Long flags:
--option valueor--option=value - Short flags:
-o value - Boolean flags:
--flag(no value) - Positional arguments stored in
@args - All arguments (including flags) in
@all_args
Generators extend Teeplate::FileTree:
- Set
directoryto template source path - Define instance variables matching template placeholders
- Call
superor let Teeplate auto-render on initialization - Files rendered to current directory or specified output
- Timestamps use Unix epoch format (e.g.,
20240115103045_i64) - Migration files:
{timestamp}_{action}_{table_name}.cr - Auto-updates
src/db/schema.crafter running migrations - Rollback uses
--steps Nto roll back N migrations - Status shows pending vs. executed migrations
- Can generate OpenAPI specs from code:
azu openapi:export - Can generate code from OpenAPI specs:
azu openapi:generate - Analyzers extract models, endpoints, requests, responses
- Supports JSON and YAML formats
- Uses Crystal's built-in spec framework with spec2 extension
- Integration tests in
spec/azu_cli/integration/ - Test helpers in
spec/support/ - Fixtures in
spec/fixtures/ - Mock file operations when testing generators
- Test both success and error paths
- Create file in
src/azu_cli/commands/(or subdirectory) - Inherit from
Commands::Base - Implement
execute : Resultmethod - Register in
CLI#setup_commands - Add help text and examples via
show_help/show_examples
- Create file in
src/azu_cli/generators/ - Inherit from
Teeplate::FileTree - Set
directorypointing to templates - Define instance variables for template interpolation
- Create ECR templates in
src/azu_cli/templates/ - Register in
Commands::Generate#execute
- Templates use ECR:
<%= expression %>for output,<% code %>for logic - Access generator instance variables:
<%= @name %> - Use helpers from generator class:
<%= snake_case_name %> - Test by running generator and verifying output
- Enable debug mode: Set
Config.instance.debug_mode = true - Use
Logger.debugfor debug messages (only shown in debug mode) - Use
ppmacro for inspecting values during development - Stack traces shown in debug mode on errors