This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
The project must always be in sync. When there are conflicts or discrepancies, the priority order for truth is:
- Proposals (
Proposals/) - The authoritative specification - Code (
Sources/) - The implementation - Documentation (Wiki,
OVERVIEW.md,README.md) - Developer docs - Website (
Website/) - Public website - Book (
Book/) - The Language Guide
When updating any layer, ensure all lower-priority layers are updated to match.
The Platform Support table in README.md lists feature availability for macOS, Linux, and Windows. When adding or modifying platform-specific features, always update this table to reflect current support status.
- Proposals (
Proposals/): Use ASCII art for diagrams - Book (
Book/): Use SVG for diagrams
swift build # Build the project
swift test # Run all tests
aro run ./Examples/UserService # Run multi-file application
aro run ./Examples/HTTPServer # Run server (uses Keepalive action)
aro compile ./MyApp # Compile all .aro files in directory
aro check ./MyApp # Syntax check all .aro files
aro build ./MyApp # Compile to native binary (LLVM IR + object file)
aro build ./MyApp --verbose --optimize # Verbose build with optimizationsThis is a Swift 6.2 parser/compiler/runtime for ARO (Action Result Object), a DSL for expressing business features as Action-Result-Object statements.
An ARO application is a directory containing .aro files:
MyApp/
├── openapi.yaml # OpenAPI contract (required for HTTP server)
├── main.aro # Contains Application-Start (required, exactly one)
├── users.aro # Feature sets for user operations
├── orders.aro # Feature sets for order operations
├── events.aro # Event handler feature sets
├── products.store # Seeds products-repository (read-only)
└── sessions.store # Seeds sessions-repository (writable if chmod o+w)
For larger applications, use the sources/ subdirectory convention:
MyApp/
├── openapi.yaml # Configuration in root
├── main.aro # Entry point (optional location)
└── sources/ # Source files in subdirectory
├── users/
│ └── users.aro
└── orders/
└── orders.aro
Key Rules:
- All
.arofiles in the directory and subdirectories are automatically discovered and parsed - Files can be in root,
sources/, or any subdirectory to any depth - No imports needed - all feature sets are globally visible within the application
- Exactly ONE
Application-Startfeature set per application (error if 0 or multiple) - At most ONE
Application-End: Successand ONEApplication-End: Error(both optional) - Feature sets are triggered by events, not direct calls
- Contract-First HTTP:
openapi.yamlis required for HTTP server (no contract = no server)
Directory → Find all .aro files → Compile each → Validate single Application-Start → Register with EventBus
- Lexer (
Lexer.swift): Tokenizes source, recognizing articles (a/an/the), prepositions, and compound identifiers - Parser (
Parser.swift): Recursive descent parser producing AST - SemanticAnalyzer (
SemanticAnalyzer.swift): Builds symbol tables and performs data flow analysis - Compiler (
Compiler.swift): Orchestrates the pipeline, entry point isCompiler.compile(source)
Application-Start executes → Services start → Event loop waits → Events trigger feature sets
- ApplicationLoader: Discovers and compiles all
.arofiles in directory - ExecutionEngine (
Core/ExecutionEngine.swift): Orchestrates program execution - EventBus (
Events/EventBus.swift): Routes events to matching feature sets - FeatureSetExecutor (
Core/FeatureSetExecutor.swift): Executes feature sets when triggered - ActionRegistry (
Actions/ActionRegistry.swift): Maps verbs to implementations
Feature sets are triggered by events based on their business activity:
| Business Activity Pattern | Triggered By |
|---|---|
operationId (e.g., listUsers) |
HTTP route match via OpenAPI contract |
{EventName} Handler |
Custom domain events |
{repository-name} Observer |
Repository changes (store/update/delete) |
File Event Handler |
File system events |
Socket Event Handler |
Socket events |
ARO uses contract-first API development. HTTP routes are defined in openapi.yaml, and feature sets are named after operationId values.
Without openapi.yaml: HTTP server does NOT start, no port is opened. With openapi.yaml: HTTP server is enabled and routes are handled.
Example:
# openapi.yaml
openapi: 3.0.3
info:
title: User API
version: 1.0.0
paths:
/users:
get:
operationId: listUsers # Feature set name
post:
operationId: createUser
/users/{id}:
get:
operationId: getUser(* Feature set names match operationIds from openapi.yaml *)
(listUsers: User API) {
Retrieve the <users> from the <user-repository>.
Return an <OK: status> with <users>.
}
(createUser: User API) {
Extract the <data> from the <request: body>.
Create the <user> with <data>.
Emit a <UserCreated: event> with <user>.
Return a <Created: status> with <user>.
}
(getUser: User API) {
Extract the <id> from the <pathParameters: id>.
Retrieve the <user> from the <user-repository> where id = <id>.
Return an <OK: status> with <user>.
}
(* Event handlers still work as before *)
(Send Welcome Email: UserCreated Handler) {
Extract the <user> from the <event: user>.
Send the <welcome-email> to the <user: email>.
Return an <OK: status> for the <notification>.
}
Path Parameters: Extracted from URL and available via pathParameters:
Extract the <id> from the <pathParameters: id>.
Request Body: Typed according to OpenAPI schema:
Extract the <data> from the <request: body>.
Code contains only the happy case. Errors are handled by the runtime. For example when a user cannot be retrieved from the repository, the server just returns: Can not retrieve the user from the user-repository where id = 530.
Do not use it for production code, it is terribly insecure.
Parser:
Program→FeatureSet[]→Statement[](eitherAROStatementorPublishStatement)AROStatement:Action [the] <Result> preposition [the] <Object>(articles optional)SymbolTable: Immutable,Sendablesymbol storage per feature setGlobalSymbolRegistry: Cross-feature-set symbol access for published variables
Runtime:
ActionImplementation: Protocol for action implementationsResultDescriptor/ObjectDescriptor: Statement metadata for actionsExecutionContext: Runtime context protocolRuntimeEvent: Protocol for events
Actions are classified by data flow direction:
- REQUEST (Extract, Parse, Retrieve, Fetch): External → Internal
- OWN (Compute, Validate, Compare, Create, Transform): Internal → Internal
- RESPONSE (Return, Throw): Internal → External
- EXPORT (Publish, Store, Log, Send, Emit): Makes symbols globally accessible or exports data
Built-in services available at runtime:
- AROHTTPServer: SwiftNIO-based HTTP server
- AROHTTPClient: AsyncHTTPClient-based HTTP client
- AROFileSystemService: File I/O with FileMonitor watching
- AROSocketServer / AROSocketClient: TCP communication
ARO supports plugins in multiple languages for extending functionality:
| Type | Language | Interface |
|---|---|---|
swift-plugin |
Swift | @_cdecl functions with C ABI |
rust-plugin |
Rust | #[no_mangle] extern "C" functions |
c-plugin |
C/C++ | Standard C ABI |
python-plugin |
Python | aro_plugin_info() + aro_action_{name}() functions |
MyApp/
├── main.aro
├── openapi.yaml
└── Plugins/
└── my-plugin/
├── plugin.yaml # Plugin manifest (required)
└── src/ # Source files
- PluginLoader (
Services/PluginLoader.swift): Discovers and loads plugins fromPlugins/directory - UnifiedPluginLoader (
Plugins/UnifiedPluginLoader.swift): Unified loading for all plugin types - NativePluginHost (
Plugins/NativePluginHost.swift): Loads C/Rust plugins viadlopen - PythonPluginHost (
Plugins/PythonPluginHost.swift): Runs Python plugins via subprocess - SwiftPluginHost (
Plugins/SwiftPluginHost.swift): Loads Swift plugins
All native plugins must implement:
// Return plugin metadata as JSON
char* aro_plugin_info(void);
// Execute an action, return JSON result
char* aro_plugin_execute(const char* action, const char* input_json);
// Execute a qualifier transformation (optional)
char* aro_plugin_qualifier(const char* qualifier, const char* input_json);
// Free memory allocated by plugin
void aro_plugin_free(char* ptr);Plugins can register custom qualifiers that transform values. Qualifiers work on types like List, String, Int, etc.
Plugin qualifiers are namespaced via the handler: field in plugin.yaml. Access them as <value: handler.qualifier>:
(* Plugin qualifiers use handler namespace *)
Compute the <random-item: collections.pick-random> from the <items>.
Compute the <sorted-list: stats.sort> from the <numbers>.
Log <numbers: collections.reverse> to the <console>.
Declaring the namespace handle in plugin.yaml:
name: plugin-collection
version: 1.0.0
handle: Collections # root-level PascalCase handle (canonical, ARO-0095)
provides:
- type: swift-plugin
path: Sources/
handler: collections # legacy fallback — use root-level handle: insteadThe root-level handle: field (PascalCase) is the canonical way to declare the namespace.
- Qualifiers are accessed as
handle.qualifier(e.g.,Collections.pick-random) - Actions are invoked as
Handle.Verb(e.g.,Markdown.ToHTML) - The legacy
handler:insideprovides:still works but emits a deprecation warning
Qualifiers are declared in aro_plugin_info() JSON with plain names (no namespace prefix).
The runtime automatically registers them as handle.qualifier in QualifierRegistry.
Key Files:
- QualifierRegistry (
Qualifiers/QualifierRegistry.swift): Central registry for plugin qualifiers - PluginQualifierHost (
Plugins/PluginQualifierHost.swift): Protocol for executing qualifiers
Plugins work in both interpreter (aro run) and compiled binary (aro build) modes:
- During
aro build, plugins inPlugins/are compiled and bundled - Swift/C plugins are compiled to dynamic libraries
- Python plugins are copied with their source files
- The binary loads plugins from
Plugins/directory at runtime
(Feature Name: Business Activity) {
Extract the <result: qualifier> from the <source: qualifier>.
Compute the <output> for the <input>.
Return an <OK: status> for a <valid: result>.
Publish as <alias> <variable>.
}
Application lifecycle handlers:
(* Entry point - exactly one per application *)
(Application-Start: My App) {
Log "Starting..." to the <console>.
Start the <http-server> with <contract>.
Return an <OK: status> for the <startup>.
}
(* Exit handler for graceful shutdown - optional, at most one *)
(Application-End: Success) {
Log "Shutting down..." to the <console>.
Stop the <http-server> with <application>.
Return an <OK: status> for the <shutdown>.
}
(* Exit handler for errors/crashes - optional, at most one *)
(Application-End: Error) {
Extract the <error> from the <shutdown: error>.
Log <error> to the <console>.
Return an <OK: status> for the <error-handling>.
}
The Compute action transforms data using built-in operations:
| Operation | Description | Example |
|---|---|---|
length / count |
Count elements | Compute the <len: length> from <text>. |
uppercase |
Convert to UPPERCASE | Compute the <upper: uppercase> from <text>. |
lowercase |
Convert to lowercase | Compute the <lower: lowercase> from <text>. |
hash |
Compute hash value | Compute the <hash: hash> from <password>. |
| Arithmetic | +, -, *, /, % | Compute the <total> from <price> * <qty>. |
Qualifier-as-Name Syntax: When you need multiple results of the same operation, use the qualifier to specify the operation while the base becomes the variable name:
(* Old syntax: 'length' is both the variable name AND the operation *)
Compute the <length> from the <message>.
(* New syntax: variable name and operation are separate *)
Compute the <first-length: length> from the <first-message>.
Compute the <second-length: length> from the <second-message>.
(* Now both values are available *)
Compare the <first-length> against the <second-length>.
See Proposals/ARO-0001-language-fundamentals.md for the full specification.
For applications that need to stay alive and process events (servers, file watchers, etc.), use the Keepalive action:
(Application-Start: File Watcher) {
Log "Starting..." to the <console>.
Start the <file-monitor> with ".".
(* Keep the application running to process events *)
Keepalive the <application> for the <events>.
Return an <OK: status> for the <startup>.
}
The Keepalive action:
- Blocks execution until a shutdown signal is received (SIGINT/SIGTERM)
- Allows the event loop to process incoming events
- Enables graceful shutdown with Ctrl+C
public struct MyAction: ActionImplementation {
public static let role: ActionRole = .own
public static let verbs: Set<String> = ["MyVerb"]
public static let validPrepositions: Set<Preposition> = [.with, .from]
public init() {}
public func execute(
result: ResultDescriptor,
object: ObjectDescriptor,
context: ExecutionContext
) async throws -> any Sendable {
// Get input from context
let input: String = try context.require(object.identifier)
// Process and bind result
let output = process(input)
context.bind(result.identifier, value: output)
// Emit event
context.emit(MyEvent(value: output))
return output
}
}
// Register
ActionRegistry.shared.register(MyAction.self)See the Action Developer Guide for full guide.
Sources/
├── AROParser/ # Core parser library
├── ARORuntime/ # Runtime execution (interpreter)
│ ├── Actions/ # Action protocol, registry, built-ins
│ ├── Core/ # ExecutionEngine, Context
│ ├── Events/ # EventBus, event types
│ ├── HTTP/ # Server (SwiftNIO), Client (AsyncHTTPClient)
│ ├── FileSystem/ # File operations, FileMonitor
│ ├── Sockets/ # TCP server/client
│ ├── OpenAPI/ # Contract-first routing (OpenAPISpec, RouteRegistry)
│ ├── Plugins/ # Plugin hosts (Native, Python, Swift)
│ ├── Services/ # PluginLoader, UnifiedPluginLoader
│ └── Application/ # App lifecycle, ApplicationLoader
├── AROCompiler/ # Native compilation (LLVM code generation)
│ ├── LLVMCodeGenerator.swift # AST to LLVM IR transformation
│ └── Linker.swift # Compilation and linking
├── AROCRuntime/ # C-callable Swift runtime bridge
│ ├── RuntimeBridge.swift # Core runtime C interface
│ ├── ActionBridge.swift # All 50+ actions via @_cdecl
│ └── ServiceBridge.swift # HTTP/File/Socket C interface
└── AROCLI/ # CLI (run, compile, check, build commands)
Examples/ # 65 examples organized by category (run `ls Examples/` for full list)
│
│ # Getting Started
├── HelloWorld/ # Minimal single-file example
├── HelloWorldAPI/ # Simple HTTP API
├── Calculator/ # Basic arithmetic operations
│
│ # Core Language
├── Computations/ # Compute operations and qualifier-as-name syntax
├── Expressions/ # Arithmetic, comparison, and logical operators
├── Conditionals/ # When guards and conditional execution
├── Iteration/ # For-each loops and collection iteration
├── Scoping/ # Publish as, business activity scope, framework vars, pipeline, loop isolation
├── Immutability/ # Immutable bindings, new-name pattern, qualifier-as-name
├── ErrorHandling/ # Error philosophy demonstration
│
│ # Events & Lifecycle
├── EventExample/ # Custom event emission and handling
├── EventListener/ # Event subscription patterns
├── ApplicationEnd/ # Graceful shutdown handlers
├── StateMachine/ # State transitions with Accept action
├── OrderService/ # Full state machine example
│
│ # HTTP & WebSocket
├── HTTPServer/ # HTTP server with Keepalive
├── HTTPClient/ # HTTP client requests
├── WeatherClient/ # Request action fetching live external API data
├── UserService/ # Multi-file REST API application
├── SimpleChat/ # WebSocket real-time messaging
├── WebSocketDemo/ # WebSocket server patterns
│
│ # File System
├── FileWatcher/ # File system monitoring
├── FileOperations/ # File I/O (read, write, copy, move)
├── FileMetadata/ # File stats and attributes
├── FormatAwareIO/ # Auto-detect JSON, YAML, CSV
├── DirectoryReplicator/ # Directory operations
│
│ # Data Processing
├── DataPipeline/ # Filter, transform, aggregate
├── SetOperations/ # Union, intersect, difference
├── CollectionMerge/ # Merging collections and objects
├── RepositoryObserver/ # Repository change observers
├── SQLiteExample/ # Database plugin usage
│
│ # Dates & Time
├── DateTimeDemo/ # Date/time operations
├── DateRangeDemo/ # Date ranges and recurrence
│
│ # Sockets & Services
├── EchoSocket/ # TCP socket server
├── SocketClient/ # TCP client connections
├── MultiService/ # Multiple services in one app
├── ExternalService/ # External service integration
│
│ # Templates & Output
├── TemplateEngine/ # Mustache-style templates
├── ContextAware/ # Human/machine/developer formatting
├── MetricsDemo/ # Prometheus metrics export
│
│ # CLI & Parameters
├── Parameters/ # Command-line argument parsing
├── ConfigurableTimeout/ # Runtime configuration
│
│ # Plugins (multi-language)
├── GreetingPlugin/ # Swift plugin example
├── HashPluginDemo/ # C plugin example
├── CSVProcessor/ # Rust plugin example
├── MarkdownRenderer/ # Python plugin example
├── ZipService/ # Plugin with external dependencies
│
│ # Plugin Qualifiers
├── QualifierPlugin/ # Swift plugin with qualifiers (pick-random, shuffle, reverse)
├── QualifierPluginC/ # C plugin with qualifiers (first, last, size)
├── QualifierPluginPython/ # Python plugin with qualifiers (sort, unique, sum, avg, min, max)
│
│ # Store Files
└── StoreFileDemo/ # File-backed repositories via .store files
Proposals/ # Language specifications
├── ARO-0001-language-fundamentals.md
├── ARO-0002-control-flow.md
├── ARO-0003-type-system.md
├── ARO-0004-actions.md
├── ARO-0005-application-architecture.md
├── ARO-0006-error-philosophy.md
├── ARO-0007-events-reactive.md
├── ARO-0008-io-services.md
├── ARO-0009-native-compilation.md
├── ARO-0010-advanced-features.md
├── ARO-0011-html-xml-parsing.md
├── ARO-0014-domain-modeling.md
├── ARO-0015-testing-framework.md
├── ARO-0016-interoperability.md
├── ARO-0018-query-language.md
├── ARO-0019-standard-library.md
├── ARO-0022-state-guards.md
├── ARO-0030-ide-integration.md
├── ARO-0031-context-aware-formatting.md
├── ARO-0034-language-server-protocol.md
├── ARO-0035-configurable-runtime.md
├── ARO-0036-file-operations.md
├── ARO-0037-regex-split.md
├── ARO-0038-list-element-access.md
├── ARO-0040-format-aware-io.md
├── ARO-0041-datetime-ranges.md
├── ARO-0042-set-operations.md
├── ARO-0043-sink-syntax.md
├── ARO-0044-metrics.md
├── ARO-0045-package-manager.md
├── ARO-0050-template-engine.md
├── ARO-0046-typed-event-extraction.md
├── ARO-0047-command-line-parameters.md
├── ARO-0048-websocket.md
├── ARO-0051-streaming-execution.md
└── ARO-0073-store-files.md
The Proposals/ directory contains language specifications:
| Proposal | Topics |
|---|---|
| 0001 Language Fundamentals | Core syntax, literals, expressions, scoping |
| 0002 Control Flow | When guards, match expressions, iteration |
| 0003 Type System | Types, OpenAPI integration, schemas |
| 0004 Actions | Action roles, built-in actions, extensions |
| 0005 Application Architecture | App structure, lifecycle, concurrency |
| 0006 Error Philosophy | "Code is the error message" |
| 0007 Events & Reactive | Events, state, repositories |
| 0008 I/O Services | HTTP, files, sockets, system objects |
| 0009 Native Compilation | LLVM, aro build, plugins in binaries |
| 0010 Advanced Features | Regex, dates, exec |
| 0011 HTML/XML Parsing | Parse action for HTML/XML documents |
| 0014 Domain Modeling | DDD patterns, entities, aggregates |
| 0015 Testing Framework | Colocated tests, Given/When/Then |
| 0016 Interoperability | External services, Call action, plugins |
| 0018 Data Pipelines | Filter, transform, aggregate collections |
| 0019 Standard Library | Primitive types, utilities |
| 0022 State Guards | Event handler filtering with field:value syntax |
| 0030 IDE Integration | Syntax highlighting, snippets |
| 0031 Context-Aware Formatting | Adaptive output for machine/human/developer |
| 0034 Language Server Protocol | LSP server, diagnostics, navigation |
| 0035 Configurable Runtime | Configure action for timeouts and settings |
| 0036 Extended File Operations | Exists, Stat, Make, Copy, Move actions |
| 0037 Regex Split | Split action with regex delimiters |
| 0038 List Element Access | first, last, index, range specifiers |
| 0040 Format-Aware I/O | Auto format detection for JSON, YAML, CSV |
| 0041 Date/Time Ranges | Date arithmetic, ranges, recurrence patterns |
| 0042 Set Operations | intersect, difference, union on collections |
| 0043 Sink Syntax | Expressions in result position |
| 0044 Runtime Metrics | Execution counts, timing, Prometheus format |
| 0045 Package Manager | Plugin installation, aro add/remove, plugin.yaml |
| 0046 Typed Event Extraction | Schema-validated event data extraction |
| 0047 Command-Line Parameters | CLI argument parsing, Parameters action |
| 0048 WebSocket | WebSocket server support, real-time messaging |
| 0050 Template Engine | Mustache-style templates, Render action |
| 0051 Streaming Execution | Lazy evaluation, Stream Tee, Aggregation Fusion |
| 0073 Store Files | File-backed repositories, YAML seed data, permission-based writability |
All core types (SymbolTable, Token, AST nodes, ActionImplementation) are Sendable for Swift 6.2 concurrency safety.
When creating git commits, do NOT include the Claude Code signature or co-author attribution in commit messages.