This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Enu is a 3D sandbox environment for creating and exploring voxel worlds using a Logo-inspired programming API. It's built with Nim and the Godot game engine (v3.5), enabling users to program interactive 3D environments using Nim scripts that run in the Nim VM.
Prefer the standard, supported path over hand-wiring. Builds, submodules, setup,
and dependency management go through the built-in nim/atlas tasks (nim prereqs, nim build, nim import_assets, atlas install, ...). Don't shell out
to scons, hand-git clone submodules, or symlink/copy prebuilt artifacts (the
Godot binary, deps/, vmlib/stdlib, app/.import, ...) from another checkout
to skip a step — those shortcuts drift from what real users and CI do, hide build
breakage, and entangle checkouts. Lock files are regenerated by their tool, never
edited by hand. Deviate only for a specific, stated reason, and prefer fixing the
task over working around it.
atlas install && atlas rep- Install dependencies (first-time setup)nim prereqs- Build Godot, download fonts, generate API bindings and stdlib
atlas.lockpins exact dependency versionsatlas pin <package>- Update lock file for a specific package after changing its version in deps/atlas install- Install dependencies from lock fileatlas rep- Regenerate nim.cfg paths from lock file- When changing dependencies in enu.nimble, run
atlas install && atlas pinto update the lock file
Never manually edit files that are meant to be produced by tools (lock files, sentinel files, zip archives, etc.), even if you know how to make the required changes. We need to verify our tools work correctly and eliminate potential failure vectors. If a tool isn't producing the expected output, investigate why. Confirm with the user before making any exceptions.
nim build- Build the main application (required after code changes)nim start- Run Enu in development modenim build_and_start- Build and run in one commandnim edit- Open project in Godot editor
nim dist- Build complete distribution package for current platformnim dist_prereqs- Build debug/release Godot versions and fontsnim dist_package- Package distribution binaries
nim test- Run the fast default tests (unit + VM) — use while iteratingnim test_all- Run the full suite (unit + VM + world + MCP) — before opening a PRnim test_unit- Run unit testsnim test_vm- Run VM script testsnim test_world- Run in-world tests (boots Godot)nim test_mcp- Run MCP integration tests (launches a private Enu)nim docs- Build documentation using nimibooknim clean- Remove build artifacts
Relevant tests must pass before calling a feature done.
nim ios- Build iOS packagenim ios_prereqs- Build Godot for iOS (requires macOS)
Pass amd64 or arm64 to nim prereqs to set the target architecture. See docs/notes/linux-cross-compile.md for detailed setup instructions and required packages.
Core Application (src/)
src/enu.nim- Entry point that imports all UI and node componentssrc/core.nim- Core utilities, globals, and common importssrc/game.nim- Main game loop and Godot integrationsrc/types.nim- Type definitions for game state, tools, and model flagssrc/models/- Data models (bots, builds, players, signs, units, colors, ground)src/controllers/- Game logic controllers (node and script controllers)src/ui/- UI components (editor, console, toolbar, settings, etc.)src/nodes/- Godot node wrappers (player, bot, build, ground, sign nodes)
Virtual Machine Environment (vmlib/)
vmlib/enu/- Enu-specific API for scripts (bots, builds, loops, state machine)vmlib/stdlib/- Copy of Nim stdlib for VM execution (auto-generated, don't modify)vmlib/worlds/- Default world templates and tutorials
Godot Integration (app/)
app/project.godot- Godot project configurationapp/scenes/- Godot scene files (.tscn)app/components/- Godot node scripts (.gdns) and scenesapp/textures/,app/materials/,app/shaders/- Game assets
Build System
generated/- Auto-generated Godot API bindings (created by build process)vendor/- Godot engine submoduletools/build_helpers.nim- Build automation utilities
Dual Type System: The project has two parallel type systems:
- Types in
src/for the main application - Corresponding types in
vmlib/enu/for VM scripts - These represent the same objects but in different contexts
VM Integration: User scripts run in the Nim VM, isolated from the main application. The VM has access to a curated API through vmlib/enu/.
Godot Binding: Uses nim-godot with auto-generated bindings from Godot 3.5 API. Use snake_case when calling these bindings.
Model-View Architecture:
- Models handle data and state (using model_citizen library)
- Controllers manage game logic and coordinate between models and UI
- UI components handle presentation and user interaction
This project follows Ruby-like casing conventions. Nim is style-insensitive for identifiers (ignoring case and underscores), so these are style guidelines rather than compiler requirements:
- Types:
UpperCamelCase(e.g.,VoxelRenderer,GameState,Build) - Enum values:
SCREAMING_SNAKE_CASE(e.g.,ERASER,BLUE,CODE_MODE,PLAYING) - Constants:
SCREAMING_SNAKE_CASE(e.g.,CHUNK_DIM,ACTION_COLORS,IR_BLACK) - Everything else:
snake_case(procs, variables, fields, parameters, etc.) - Third-party identifiers starting with lowercase: use
snake_case(e.g.,writeVu64→write_vu64)
Only use lowerCamelCase when snake_case doesn't work, which should only happen with third-party macros that don't properly normalize identifiers.
- Naming Conventions: Never use
camelCasefor Nim code. Enu strictly usessnake_casefor everything (variables, procs, types in some parts, but standard Nim types are strictlyPascalCase). - Exceptions: Do not use
newException(ExceptionType, "msg"). Use the helper methodExceptionType.init("msg")(e.g.,ValueError.init("Circular dependency detected")).
- Use
nim buildto verify changes compile correctly - The project uses ZenContext for metrics and threading
- Scripts are Logo-inspired but use Nim syntax
- World data is stored as JSON with accompanying Nim scripts
- If you're not on
mainor a0.xbranch, try to keep a clean history. Prefer rebasing and ammending commits to keep work in logical chunks and --force-with-lease push them to origin. Confirm with the user before pulling. - Never include "Generated by Claude", "Co-Authored-By: Claude", or similar attribution in commits. Keep commit messages concise. Try not to include details that are obvious by quickly looking at the diff.
- If rebasing or squashing commits, confirm with the user before merging 10 or more commits.
- Avoid nil checks, unless there is a known, non-bug reason why something could be nil. Asserting something isn't nil is fine.
- Things that are fairly obvious shouldn't have comments.