Claude-skill-registry crystal-lang

Use this skill when working with the Crystal programming language. Crystal is a statically-typed, compiled language with Ruby-like syntax. It features type inference, null safety, macros, and compiles to efficient native code. Use for understanding Crystal's standard library, syntax, semantics, concurrency model, and FFI bindings.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/crystal-lang" ~/.claude/skills/majiayu000-claude-skill-registry-crystal-lang && rm -rf "$T"
manifest: skills/data/crystal-lang/SKILL.md
source content

Crystal-Lang Skill

Use this skill when working with the Crystal programming language. a statically-typed, compiled language with Ruby-like syntax that combines Ruby's coding efficiency with C's runtime performance.

When to Use This Skill

This skill should be triggered when:

  • Writing Crystal code and need syntax, semantic, or API guidance
  • Debugging Crystal compilation errors or runtime issues
  • Understanding Crystal's type system, type inference, or union types
  • Working with Crystal's concurrency model (fibers, channels, spawn)
  • Using Crystal macros for metaprogramming and compile-time code generation
  • Interfacing with C libraries via FFI bindings
  • Implementing web services with the Crystal standard library (HTTP, HTTPS, WebSocket)
  • Processing data formats (JSON, XML, YAML, CSV)
  • Working with Crystal's standard library APIs

Key Concepts

Type System

  • Type Inference: The compiler infers types without explicit annotations in most cases
  • Union Types: Variables can have multiple possible types at compile time (e.g.,
    Int32 | String
    )
  • Null Safety: Nilable types (
    String?
    ) must be checked before use
  • Generic Types: Reusable code with type parameters (e.g.,
    Array(T)
    ,
    Hash(K, V)
    )

Concurrency Model

  • Fibers: Lightweight cooperative threads scheduled by the runtime
  • Channels: Communication primitives for passing data between fibers
  • spawn: Create a new fiber for concurrent execution

Macros

  • Compile-time Execution: Macros run during compilation, not at runtime
  • AST Manipulation: Modify and generate code programmatically
  • Flag-based Compilation: Conditional code based on compile-time flags

Quick Reference

Basic Syntax

Hello World

# hello.cr
puts "Hello, World!"

Variables and Types

name = "Crystal"       # : String
count = 42            # : Int32
pi = 3.14             # : Float64
enabled = true        # : Bool
nothing = nil         # : Nil

# Type annotations work too
x : Int32 = 10

String Interpolation

name = "World"
puts "Hello, #{name}!"   # => Hello, World!

Methods and Blocks

Defining Methods

def greet(name : String) : String
  "Hello, #{name}!"
end

def add(x : Int32, y : Int32) : Int32
  x + y
end

Default Arguments

def greet(name : String, enthusiastic : Bool = false)
  message = "Hello, #{name}"
  enthusiastic ? "#{message}!" : message
end

Blocks and Procs

# Using a block
[1, 2, 3].map { |x| x * 2 }  # => [2, 4, 6]

# Short syntax
[1, 2, 3].map(&.to_s)        # => ["1", "2", "3"]

# Storing a block
double = ->(x : Int32) { x * 2 }
double.call(5)                # => 10

Control Flow

If/Else

if count > 0
  puts "Positive"
elsif count < 0
  puts "Negative"
else
  puts "Zero"
end

# Ternary
result = count > 0 ? "positive" : "non-positive"

Case/When

case value
when 1, 2, 3
  puts "Small"
when 4..10
  puts "Medium"
else
  puts "Large"
end

Unless

puts "Access denied" unless user.logged_in?

Classes and Structs

Class Definition

class Person
  property name : String
  property age : Int32

  def initialize(@name : String, @age : Int32)
  end

  def greet : String
    "Hi, I'm #{@name}, #{@age} years old"
  end
end

person = Person.new("Alice", 30)
person.greet  # => "Hi, I'm Alice, 30 years old"

Inheritance

class Employee < Person
  def initialize(@name : String, @age : Int32, @title : String)
    super(@name, @age)
  end
end

Structs for Value Types

struct Point
  property x : Float64
  property y : Float64

  def initialize(@x : Float64, @y : Float64)
  end
end

Collections

Arrays

# Literal
numbers = [1, 2, 3, 4, 5]

# Operations
numbers << 6              # append
numbers.first             # => 1
numbers.last              # => 5
numbers.size              # => 5
numbers.includes?(3)      # => true
numbers.map { |x| x * 2 } # => [2, 4, 6, 8, 10]

Hashes

# Literal
scores = {"Alice" => 100, "Bob" => 95}

# Access
scores["Alice"]           # => 100
scores["Charlie"]?        # => nil (safe access)
scores.fetch("Dave", 0)   # => 0 (default)

Ranges

1..10        # inclusive range
1...10       # exclusive range
('a'..'z').to_a.first(3)  # => ['a', 'b', 'c']

Union Types and Nilable Types

Union Types

def process(value : Int32 | String)
  # Methods must exist for ALL types in the union
  value.to_s
end

Nilable Types

def find_user(id : Int32) : User?
  # Returns User or nil
  users.find { |u| u.id == id }
end

user = find_user(1)
if user
  puts user.name  # user is guaranteed non-nil here
end

# Safe navigation
name = user&.name || "Unknown"

Type Narrowing

value = rand > 0.5 ? 42 : "hello"

if value.is_a?(Int32)
  value.abs  # Compiler knows value is Int32 here
else
  value.size  # Compiler knows value is String here
end

Exception Handling

Begin/Rescue/Ensure

begin
  File.read("nonexistent.txt")
rescue ex : FileNotFoundError
  puts "File not found: #{ex.message}"
rescue ex : Exception
  puts "Error: #{ex.message}"
ensure
  puts "Cleanup code runs here"
end

Custom Exceptions

class MyError < Exception
end

raise MyError.new("Something went wrong")

Concurrency

Spawning Fibers

spawn do
  puts "Running in background"
  sleep 1
  puts "Done"
end

puts "Main continues"
Fiber.yield  # Let other fibers run

Channels

channel = Channel(Int32).new

spawn do
  channel.send(42)
end

result = channel.receive  # Blocks until value is available
puts result  # => 42

Async Operations

def fetch_data : String
  "data"
end

# Non-blocking with spawn
spawn { puts fetch_data }
Fiber.yield

Macros

Compile-time Execution

# Run shell command at compile time
{% `echo "compiled at build time"` %}

# Check compile-time flags
{% if flag?(:x86_64) %}
  puts "Running on 64-bit architecture"
{% end %}

Macro Methods

macro define_method(name, content)
  def {{name}}
    {{content}}
  end
end

define_method(:greet, puts "Hello from macro!")

Reading Files at Compile Time

# Embed file contents at compile time
VERSION = {{ read_file("VERSION.txt").strip }}

File I/O

Reading Files

# Read entire file
content = File.read("file.txt")

# Read line by line
File.each_line("file.txt") do |line|
  puts line
end

# Check file exists
if File.exists?("file.txt")
  puts "File exists"
end

Writing Files

# Write string to file
File.write("output.txt", "Hello, File!")

# Append to file
File.open("log.txt", "a") do |file|
  file.puts "Log entry"
end

JSON Processing

Parsing JSON

require "json"

data = JSON.parse(%({"name": "Alice", "age": 30}))
data["name"].as_s  # => "Alice"
data["age"].as_i   # => 30

Generating JSON

require "json"

hash = {"name" => "Bob", "age" => 25}
JSON.build do |json|
  json.object do
    json.field "name", hash["name"]
    json.field "age", hash["age"]
  end
end

JSON Mapping

require "json"

class User
  include JSON::Serializable

  property name : String
  property age : Int32
end

user = User.from_json(%({"name": "Charlie", "age": 35}))
user.to_json  # => %({"name":"Charlie","age":35})

HTTP Client

Simple GET Request

require "http"

response = HTTP.get("https://api.example.com/data")
puts response.status_code  # => 200
puts response.body

POST with JSON Body

require "http"

response = HTTP.post("https://api.example.com/users",
  headers: {"Content-Type" => "application/json"},
  body: %({"name": "Dave"}).to_json
)

HTTP Client with Persistent Connection

require "http"

client = HTTP::Client.new("https://api.example.com")
response = client.get("/endpoint")
client.close

XML Processing

Parsing XML

require "xml"

xml = <<-XML
<person id="1">
  <firstname>Jane</firstname>
  <lastname>Doe</lastname>
</person>
XML

document = XML.parse(xml)
person = document.first_element_child
if person
  puts person["id"]         # => "1"
  puts person.content       # => "Jane"
end

Building XML

require "xml"

string = XML.build(indent: "  ") do |xml|
  xml.element("person", id: 1) do
    xml.element("firstname") { xml.text "Jane" }
    xml.element("lastname") { xml.text "Doe" }
  end
end

C Bindings (FFI)

Declaring External Library

lib LibC
  fun strlen(s : UInt8*) : SizeT
end

# Call C function
LibC.strlen(pointer)

C Linking

@[Link("pcre")]
lib LibPCRE
  fun pcre_compile(pattern : UInt8*) : Pointer(Void)
end

Pointer Operations

x = 1
ptr = pointerof(x)
ptr.value = 2
puts x  # => 2

# Allocated memory
ptr = Pointer.malloc(2, 42)
ptr[0]  # => 42
ptr[1]  # => 42

BitArray

require "bit_array"

ba = BitArray.new(12)  # => "BitArray[000000000000]"
ba[2]                  # => false
0.upto(5) { |i| ba[i * 2] = true }
ba                     # => "BitArray[101010101010]"
ba[2]                  # => true

Union Type Operations

# Union simplification
Union(Int32 | String)      # => (Int32 | String)
Union(Int32)               # => Int32
Union(Int32, Int32, Int32) # => Int32

Weak References

require "weak_ref"

ref = WeakRef.new("oof".reverse)
p ref      # => #<WeakRef(String):...>
GC.collect
p ref      # => #<WeakRef(String):... @target=Pointer.null>
p ref.value  # => nil

Reference Files

This skill includes comprehensive documentation in

references/
:

Getting Started (
getting_started.md
)

  • Source: Official Crystal documentation (medium confidence)
  • Pages: 2 (Language Introduction, About this guide)
  • Content: Beginner-friendly introduction to Crystal's core concepts

Standard Library (
standard_library.md
)

  • Source: Official Crystal API documentation (medium confidence)
  • Pages: 265 (extensive API coverage)
  • Topics:
    • Core types: Union, WeakRef, Pointer, BitArray
    • I/O operations: XML, JSON, compression, hexdump
    • Networking: HTTP, HTTPS, WebSocket, OpenSSL
    • System: GC stats, event loop, LLVM integration
    • Standard library utilities

Syntax and Semantics (
syntax_and_semantics.md
)

  • Source: Official Crystal language reference (medium confidence)
  • Pages: 351 (comprehensive language specification)
  • Topics:
    • Crystal::Macros module for compile-time metaprogramming
    • Event loop and concurrency primitives
    • Type system details (generics, unions, nilable types)
    • Inheritance and type relationships
    • C bindings and FFI
    • Language semantics and features

Working with This Skill

For Beginners

  1. Start with the Getting Started reference for language introduction
  2. Review the basic syntax examples in the Quick Reference above
  3. Practice with simple programs before moving to advanced topics

For Intermediate Users

  1. Use Syntax and Semantics for understanding type system details
  2. Reference the Standard Library for available APIs
  3. Explore macros for compile-time code generation

For Advanced Users

  1. Dive into C bindings for performance-critical code
  2. Study concurrency patterns with fibers and channels
  3. Use advanced macro techniques for metaprogramming

Navigation Tips

  • Search reference files using the "URL:" markers to locate specific API docs
  • Code examples include language tags for syntax highlighting
  • Macro examples use
    {% %}
    for compile-time code
  • Type annotations use
    # : TypeName
    comments

Resources

Official Documentation

Community

  • Crystal Forum
  • Gitter channel
  • IRC: #crystal-lang at irc.libera.chat
  • Stack Overflow: crystal-lang tag
  • GitHub: crystal-lang/crystal

Notes

  • This skill synthesizes knowledge from official Crystal documentation
  • Documentation version: 1.18
  • Crystal prioritizes backward compatibility within major versions
  • The language is statically-typed but with powerful type inference
  • Compile-time macros enable zero-cost abstractions

Updating

To refresh this skill with updated documentation:

  1. Re-run the documentation scraper
  2. The skill will be rebuilt with the latest information from official sources