diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fa98518..4c5551f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,9 +2,9 @@ name: CI
on:
push:
- branches: [main]
+ branches: [stable, develop]
pull_request:
- branches: [main]
+ branches: [stable, develop]
jobs:
linux:
diff --git a/.gitignore b/.gitignore
index 052239e..be4e422 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,5 @@
/.vs
.generated/
output/
-imgui.ini
\ No newline at end of file
+imgui.ini
+.atto/
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a622fe4..997b720 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
-project(nanolang LANGUAGES C CXX)
+project(attolang LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -12,32 +12,36 @@ if(NOT WIN32)
endif()
endif()
-option(NANOLANG_BUILD_EDITOR "Build the nanoflow visual editor (requires SDL3 + imgui)" ON)
+option(ATTOLANG_BUILD_EDITOR "Build the attoflow visual editor (requires SDL3 + imgui)" ON)
-# nanolang: core language library (no UI dependencies)
-add_library(nanolang STATIC
- src/nano/types.cpp
- src/nano/args.cpp
- src/nano/expr.cpp
- src/nano/type_utils.cpp
- src/nano/serial.cpp
- src/nano/inference.cpp
+# attolang: core language library (no UI dependencies)
+add_library(attolang STATIC
+ src/atto/types.cpp
+ src/atto/args.cpp
+ src/atto/expr.cpp
+ src/atto/type_utils.cpp
+ src/atto/serial.cpp
+ src/atto/inference.cpp
+ src/atto/graph_index.cpp
+ src/atto/shadow.cpp
+ src/atto/symbol_table.cpp
+ src/atto/graph_builder.cpp
)
-target_include_directories(nanolang PUBLIC
+target_include_directories(attolang PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
- ${CMAKE_CURRENT_SOURCE_DIR}/src/nano
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/atto
)
-# nanoc: standalone compiler
-add_executable(nanoc
- src/nanoc/main.cpp
- src/nanoc/codegen.cpp
+# attoc: standalone compiler
+add_executable(attoc
+ src/attoc/main.cpp
+ src/attoc/codegen.cpp
)
-target_include_directories(nanoc PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/src/nanoc
+target_include_directories(attoc PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/attoc
)
-target_link_libraries(nanoc PRIVATE
- nanolang
+target_link_libraries(attoc PRIVATE
+ attolang
)
# test_inference: unit tests
@@ -45,26 +49,48 @@ add_executable(test_inference
tests/test_inference.cpp
)
target_link_libraries(test_inference PRIVATE
- nanolang
+ attolang
)
-# nanoflow: visual flow editor (optional, requires SDL3 + imgui)
-if(NANOLANG_BUILD_EDITOR)
- set(NANO_NEEDS_IMGUI ON)
- include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/NanoDeps.cmake)
+# attoflow: visual flow editor (optional, requires SDL3 + imgui)
+if(ATTOLANG_BUILD_EDITOR)
+ set(ATTO_NEEDS_IMGUI ON)
+ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/AttoDeps.cmake)
- add_executable(nanoflow
- src/nanoflow/main.cpp
- src/nanoflow/editor.cpp
+ # Embed Liberation Mono font as C array
+ set(FONT_TTF "${CMAKE_CURRENT_SOURCE_DIR}/src/attoflow/fonts/LiberationMono-Regular.ttf")
+ set(FONT_HDR "${CMAKE_CURRENT_BINARY_DIR}/generated/LiberationMono_Regular.h")
+ file(READ "${FONT_TTF}" FONT_HEX HEX)
+ string(LENGTH "${FONT_HEX}" FONT_HEX_LEN)
+ math(EXPR FONT_SIZE "${FONT_HEX_LEN} / 2")
+ string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," FONT_BYTES "${FONT_HEX}")
+ file(WRITE "${FONT_HDR}"
+ "// Liberation Mono Regular - SIL Open Font License (auto-generated)\n"
+ "#pragma once\n"
+ "static const unsigned int LiberationMono_Regular_size = ${FONT_SIZE};\n"
+ "static const unsigned char LiberationMono_Regular_data[] = {\n"
+ "${FONT_BYTES}\n};\n"
)
- target_include_directories(nanoflow PRIVATE
+
+ add_executable(attoflow
+ src/attoflow/main.cpp
+ src/attoflow/window.cpp
+ src/attoflow/editor2.cpp
+ src/attoflow/nets_editor.cpp
+ src/attoflow/visual_editor.cpp
+ src/attoflow/node_renderer.cpp
+ src/attoflow/tooltip_renderer.cpp
+ src/attoflow/editor_style.cpp
+ )
+ target_include_directories(attoflow PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
- ${CMAKE_CURRENT_SOURCE_DIR}/src/nanoflow
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/attoflow
+ ${CMAKE_CURRENT_BINARY_DIR}/generated
)
if(WIN32)
- target_link_libraries(nanoflow PRIVATE nanolang SDL3::SDL3 imgui::imgui)
+ target_link_libraries(attoflow PRIVATE attolang SDL3::SDL3 imgui::imgui)
else()
- target_link_libraries(nanoflow PRIVATE nanolang SDL3::SDL3-static imgui_all)
+ target_link_libraries(attoflow PRIVATE attolang SDL3::SDL3-static imgui_all)
endif()
- add_dependencies(nanoflow nanoc)
+ add_dependencies(attoflow attoc)
endif()
diff --git a/README.md b/README.md
index 2ef43b3..079791a 100644
--- a/README.md
+++ b/README.md
@@ -1,28 +1,36 @@
-# nanolang
+# Organic Assembler
-A visual dataflow programming language with a node-based editor, standalone compiler, and runtime. Programs are authored as flow graphs in `.nano` files and compiled to C++. See an [example program](scenes/klavier/main.nano) and the full [language specification](nanolang.md).
+An Operating System for Instruments (Όργανα), written in attolang. Instruments are multimodal dataflow programs — authored as node graphs possibly using the **attoflow** editor, compiled, and run in real time.
-
+Each instrument is a self-contained `.atto` program that defines its Functionality. The System compiles these programs runs them with hot-reload support.
+
+
+
+[](https://www.youtube.com/watch?v=ymzuD-oekFM)
+
+Listen to the [introductory podcast](docs/podcasts/introducing-orgasm.md) — *Growing Instruments with the Organic Assembler* ([SoundCloud](https://soundcloud.com/poiitidis/growing-instruments-with-the), [YouTube](https://youtu.be/ymzuD-oekFM)).
+
+See an [example instrument](scenes/klavier/main.atto) and the full [language specification](docs/attolang.md).
## Components
| Target | Description |
|--------|-------------|
-| **nanolang** | Core library — type system, expression parser, type inference, serialization |
-| **nanoflow** | Visual node editor (SDL3 + Dear ImGui) |
-| **nanoc** | Standalone compiler (`.nano` → C++) |
-| **nanoruntime** | Runtime with GUI and ImGui bindings |
+| **attolang** | Core language library — type system, expression parser, type inference, serialization |
+| **attoflow** | Visual node editor for authoring instruments (SDL3 + Dear ImGui) |
+| **attoc** | Standalone compiler (`.atto` → C++) |
+| **attoruntime** | Instrument runtime with GUI and audio bindings |
## Language Highlights
-- **Sigil-based value categories** — `%` data, `&` reference, `^` iterator, `@` lambda, `#` enum, `!` bang (trigger), `~` event
- **Rich type system** — scalars (`u8`–`s64`, `f32`/`f64`, `bool`, `string`), containers (`vector`, `map`, `list`, `set`, `queue`), fixed-size arrays, tensors, named struct types, function types
+- **First-class literals, symbols, and types** — `literal`, `symbol`, `type` as compile-time values
- **Bidirectional type inference** with automatic integer upcasting and iterator-to-reference decay
- **Bang-driven control flow** — nodes postfixed with `!` have explicit execution ordering via bang signals
- **Inline expressions** — node arguments can embed literals, variable refs, and sub-expressions directly
- **Lambda construction** — expression nodes can be captured as callable lambdas with automatic capture/parameter resolution
- **FFI support** — declare external C functions and call them from the graph
-- **Standard library modules** — e.g. `decl_import std/imgui` for ImGui bindings
+- **Standard library modules** — e.g. `decl_import "std/imgui"` for ImGui bindings
## Building
@@ -48,6 +56,12 @@ cmake -B build -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake
cmake --build build --parallel --config Release
```
+## Instructions
+
+New to the project? Start with the [Instructions](docs/instructions.md) — a guide to interpreting and following instructions, operating on the codebase, and building instruments with the Organic Assembler. It covers everything from the build system and architectural layers to the anatomy of an instrument and the audio callback pattern.
+
+For naming philosophy, see [Names](docs/names.md). For the full documentation suite: [Architecture](docs/architecture.md), [Language Spec](docs/attolang.md), [Patterns](docs/patterns.md), [Thinking](docs/thinking.md), [Style](docs/style.md), [Coding](docs/coding.md), [Changelog](docs/changelog.md).
+
## License
MIT — see [LICENSE](LICENSE).
diff --git a/nanostd/gui.nano b/attostd/gui.atto
similarity index 91%
rename from nanostd/gui.nano
rename to attostd/gui.atto
index 18a9932..d1d3f2b 100644
--- a/nanostd/gui.nano
+++ b/attostd/gui.atto
@@ -1,4 +1,4 @@
-# GUI/AV runtime FFI bindings for nanolang
+# GUI/AV runtime FFI bindings for attolang
# Import with: decl_import std/gui
# Create a window with audio and video callbacks.
diff --git a/nanostd/imgui.nano b/attostd/imgui.atto
similarity index 99%
rename from nanostd/imgui.nano
rename to attostd/imgui.atto
index 0059941..450886d 100644
--- a/nanostd/imgui.nano
+++ b/attostd/imgui.atto
@@ -1,4 +1,4 @@
-# ImGui FFI bindings for nanolang
+# ImGui FFI bindings for attolang
# Import with: decl_import std/imgui
# Window management
diff --git a/cmake/NanoDeps.cmake b/cmake/AttoDeps.cmake
similarity index 90%
rename from cmake/NanoDeps.cmake
rename to cmake/AttoDeps.cmake
index 2cefdec..29925e9 100644
--- a/cmake/NanoDeps.cmake
+++ b/cmake/AttoDeps.cmake
@@ -1,13 +1,13 @@
-# NanoDeps.cmake — Fetch SDL3 + imgui via FetchContent (non-Windows) or vcpkg (Windows)
+# AttoDeps.cmake — Fetch SDL3 + imgui via FetchContent (non-Windows) or vcpkg (Windows)
#
# Provides:
# SDL3::SDL3 — SDL3 target
-# imgui_all — imgui core + SDL3 backends (only if NANO_NEEDS_IMGUI is set)
+# imgui_all — imgui core + SDL3 backends (only if ATTO_NEEDS_IMGUI is set)
if(WIN32)
# On Windows, use vcpkg (user must set CMAKE_TOOLCHAIN_FILE)
find_package(SDL3 CONFIG REQUIRED)
- if(NANO_NEEDS_IMGUI)
+ if(ATTO_NEEDS_IMGUI)
find_package(imgui CONFIG REQUIRED)
endif()
else()
@@ -25,7 +25,7 @@ else()
set(SDL_TESTS OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(SDL3)
- if(NANO_NEEDS_IMGUI)
+ if(ATTO_NEEDS_IMGUI)
FetchContent_Declare(imgui
GIT_REPOSITORY https://github.com/ocornut/imgui.git
GIT_TAG v1.92.6
diff --git a/docs/2026-04-06.md b/docs/2026-04-06.md
new file mode 100644
index 0000000..c887747
--- /dev/null
+++ b/docs/2026-04-06.md
@@ -0,0 +1,135 @@
+# Continuation — Organic Assembler Session Context
+
+*Date: 2026-04-06*
+
+This file captures the active context, open threads, and memory state for the Organic Assembler project, for use as a handoff document or NotebookLM/LLM context seed.
+
+---
+
+## Project Identity
+
+**Organic Assembler (orgasm)** is an **Operating System for Instruments** — a platform where instruments are multimodal dataflow programs authored as `.atto` node graphs, compiled by `attoc`, and run in real time by `attoruntime`. The visual editor is `attoflow`. The language is `attolang`.
+
+- "Instrument" = a `.atto` program (not just audio — multimodal)
+- "OS" = the runtime + editor + compiler ecosystem managing instrument lifecycle
+- Repo: `nilware-io/orgasm` (GitHub)
+
+---
+
+## Session Work (this conversation)
+
+### Podcast documentation
+- Created [docs/podcasts/introducing-orgasm.md](docs/podcasts/introducing-orgasm.md) — the podcast landing page
+ - Links: [SoundCloud](https://soundcloud.com/poiitidis/growing-instruments-with-the), [YouTube](https://youtu.be/ymzuD-oekFM), and the local [m4a file](docs/podcasts/Growing_instruments_with_the_Organic_Assembler.m4a)
+ - References [notes/introducing-orgasm.md](docs/podcasts/notes/introducing-orgasm.md) as the NotebookLM source
+- Updated [README.md](README.md) to surface the podcast with both SoundCloud and YouTube links, right after the screenshot
+
+---
+
+## Active Project Threads (from memory)
+
+### 1. Type System Redesign (partially complete as of 2026-03-25)
+
+**Completed:**
+- `literal` type representation; expression parser produces `ExprKind::Literal` for all literals
+- Removed all legacy ExprKind values (IntLiteral, F32Literal, etc.)
+- `symbol` and `undefined_symbol` types
+- `TypeApply`: `$0<$1,$2>` parsed as speculative `<>` on identifiers resolving to types
+- All nodes except `label` get shadow nodes; `decl_var` descriptor redesigned
+- `build_context` and `build_registry` removed — replaced by future `decl` bang chain
+
+**TODO:**
+- Implement `decl` bang chain evaluation (compile-time interpreter)
+- `decl_type` outputs `type`
+- Event names without `~` prefix
+- Namespace `::` operator in expressions
+- Type construction via calling (e.g. `f32(42)` as cast)
+- Rewrite tests for new declaration/inference flow
+
+---
+
+### 2. Editor2 & GraphBuilder Refactor
+
+**Completed:**
+- `BuilderEntry` inheritance base with `IdCategory` (Node/Net)
+- `FlowArg2` inheritance hierarchy: `ArgNet2`, `ArgNumber2`, `ArgString2`, `ArgExpr2`
+- Dirty tracking: `GraphBuilder::mark_dirty()` / `is_dirty()`
+- Sentinels: `$empty` (FlowNodeBuilder), `$unconnected` (NetBuilder)
+- `NodeKind2`: Flow, Banged, Event, Declaration, Special
+- v0→v1 migration: name-based port mapping, shadow folding, lambda `-as_lambda` stripping
+- Hover system: `hover_item_` variant, `detect_hover()`, `draw_hover_effects()`
+- Pin shapes: Circle (data), Square (bang), Triangle (lambda), Diamond (va_args/optional)
+- Liberation Mono font embedded via CMake `file(READ HEX)`
+
+---
+
+### 3. DLL Host & Wire Architecture (design phase)
+
+**attohost.exe:**
+- Separate host process — editor spawns it, it owns SDL window/audio/ImGui
+- attoc generates `.dll` (SHARED); attohost does `LoadLibrary` → `on_start`
+- Crash isolation; hot-reload without restarting editor
+
+**wire\:**
+- Release: typedef to `T` (zero overhead)
+- Inspect: wraps value with metadata, notifies IPC channel
+- Enables live inspection, value injection, oscilloscope view per wire
+
+**First-class wires in .atto format:**
+- `[[wire]]` top-level entities with `guid`, `from`, `to`
+- Replace current `connections` array on nodes
+- guid stable across node renames — used for inspector subscriptions
+
+**IPC:**
+- attoflow owns named pipe; attohost connects on startup
+- attohost publishes wire table on connect; sends dirty updates per frame
+- attoflow sends back: value overrides, reload signal, shutdown
+
+---
+
+### 4. Nested Lambda Scope Bug (open)
+
+**Problem:** `collect_lambda_params` doesn't respect lambda boundaries — outer stored lambda params leak into inner `lock`/`iterate` lambdas. A `param` node reachable through an inner lambda's subgraph is incorrectly treated as belonging to the inner lambda.
+
+**Proper fix:** Pre-inference pass that:
+1. Identifies all lambda boundaries (every `as_lambda` → Lambda pin connection)
+2. Assigns each node to its innermost lambda scope
+3. `collect_lambda_params` only collects from nodes owned by the current scope
+
+---
+
+### 5. node.args Elimination (future work)
+
+`node.args` is still a string tokenized at runtime ~40+ times across codegen, inference, type_utils, editor, serial. Goal: pre-extract all metadata into structured fields at load time; `node.args` becomes display/serialization only.
+
+Migration order: codegen first (highest call count), then inference, then editor.
+
+---
+
+### 6. Web Target (deferred design)
+
+- Editor compiled to Emscripten, runs in browser
+- "Run" posts `.atto` to compile server on hardened Pi
+- Server: attoc → C++ → emcc → returns `.wasm`
+- Container: no network inside, 60s timeout, 512MB RAM, read-only rootfs
+- Attack surface bounded to `.atto` input (no arbitrary C++ injection)
+
+---
+
+## Key Files
+
+| Path | Purpose |
+|------|---------|
+| [README.md](README.md) | Project overview, components, build instructions |
+| [docs/attolang.md](docs/attolang.md) | Full language specification |
+| [docs/architecture.md](docs/architecture.md) | Architectural layers |
+| [docs/instructions.md](docs/instructions.md) | Guide for operating on the codebase |
+| [docs/patterns.md](docs/patterns.md) | Instrument patterns |
+| [docs/thinking.md](docs/thinking.md) | Design philosophy |
+| [docs/style.md](docs/style.md) | Code style |
+| [docs/coding.md](docs/coding.md) | Coding conventions |
+| [docs/changelog.md](docs/changelog.md) | Change history |
+| [docs/names.md](docs/names.md) | Naming philosophy |
+| [docs/podcasts/introducing-orgasm.md](docs/podcasts/introducing-orgasm.md) | Podcast landing page |
+| [docs/podcasts/notes/introducing-orgasm.md](docs/podcasts/notes/introducing-orgasm.md) | NotebookLM source notes |
+| [scenes/klavier/main.atto](scenes/klavier/main.atto) | Example instrument |
diff --git a/docs/architecture.md b/docs/architecture.md
new file mode 100644
index 0000000..e02c0d9
--- /dev/null
+++ b/docs/architecture.md
@@ -0,0 +1,400 @@
+# Organic Assembler — Architecture
+
+## Overview
+
+Organic Assembler (orgasm) is an **Operating System for Instruments**. An "instrument" is a
+multimodal dataflow program authored as a node graph in a `.atto` file using the attolang
+language. The system comprises four major subsystems: the core language library, the compiler,
+the visual editor, and the runtime. Each is independently buildable and has well-defined
+boundaries.
+
+```
+┌─────────────────────────────────────────────────────────┐
+│ User / Developer │
+│ │
+│ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ │
+│ │ attoflow │ │ attoc │ │ attohost │ │
+│ │ (editor) │───>│ (compiler) │───>│ (runtime) │ │
+│ └──────┬──────┘ └──────┬──────┘ └──────┬─────┘ │
+│ │ │ │ │
+│ └──────────────────┼──────────────────┘ │
+│ │ │
+│ ┌────────┴────────┐ │
+│ │ attolang │ │
+│ │ (core library) │ │
+│ └─────────────────┘ │
+└─────────────────────────────────────────────────────────┘
+```
+
+## Build Targets
+
+The project uses CMake 3.25+ with C++20. There are four build targets:
+
+| Target | Type | Description | Dependencies |
+|-------------------|------------|------------------------------------------|----------------------|
+| `attolang` | Static lib | Core language: types, parsing, inference | C++20 stdlib only |
+| `attoc` | Executable | Standalone compiler (.atto → C++) | attolang |
+| `test_inference` | Executable | Unit tests for type inference | attolang |
+| `attoflow` | Executable | Visual node editor (optional) | attolang, SDL3, ImGui|
+
+The editor (`attoflow`) is optional and gated behind `ATTOLANG_BUILD_EDITOR`. The core
+library and compiler have zero external dependencies beyond the C++20 standard library.
+
+## Directory Layout
+
+```
+orgasm/
+├── CMakeLists.txt # Top-level build configuration
+├── cmake/AttoDeps.cmake # SDL3 + ImGui fetch (vcpkg on Windows, FetchContent otherwise)
+├── vcpkg.json # Windows dependency manifest
+│
+├── src/
+│ ├── atto/ # Core language library (attolang)
+│ │ ├── model.h # FlowGraph, FlowNode, FlowLink, FlowPin
+│ │ ├── types.h / types.cpp # Type system: TypeExpr, TypeParser, TypePool
+│ │ ├── expr.h / expr.cpp # Expression AST: tokenizer, parser, ExprNode
+│ │ ├── inference.h / .cpp # Bidirectional type inference engine
+│ │ ├── graph_builder.h / .cpp # Structured graph editing with dirty tracking
+│ │ ├── graph_index.h / .cpp # Fast pin/node lookup by ID
+│ │ ├── serial.h / serial.cpp # .atto file serialization (TOML-like)
+│ │ ├── shadow.h / shadow.cpp # Shadow expression nodes (deref, internal)
+│ │ ├── symbol_table.h / .cpp # Compile-time symbol resolution
+│ │ ├── type_utils.h / .cpp # Type compatibility, upcasting rules
+│ │ ├── args.h / args.cpp # Argument tokenization utilities
+│ │ ├── node_types.h / .cpp # Node type descriptors (v1)
+│ │ ├── node_types2.h # Extended node type descriptors (v2)
+│ │ └── graph_editor_interfaces.h # Observer interfaces for editor integration
+│ │
+│ ├── attoc/ # Standalone compiler
+│ │ ├── main.cpp # Entry point: load → infer → codegen
+│ │ ├── codegen.h / .cpp # C++ code generation (types, header, impl, cmake)
+│ │
+│ ├── attoflow/ # Visual editor
+│ │ ├── main.cpp # SDL3 window init, 60 FPS event loop
+│ │ ├── window.h / .cpp # Tab management, project browser, build toolbar
+│ │ ├── editor2.h / .cpp # Editor2Pane: wraps GraphBuilder, wire connection
+│ │ ├── visual_editor.h / .cpp # Canvas: pan/zoom, grid, hover detection
+│ │ ├── node_renderer.h / .cpp # Node visualization: pins, args, errors
+│ │ ├── nets_editor.h / .cpp # Named nets panel
+│ │ ├── editor_style.h / .cpp # Colors, fonts, spacing constants
+│ │ ├── tooltip_renderer.h/.cpp# Hover tooltip rendering
+│ │ ├── sdl_imgui_window.h # SDL3 + ImGui integration layer
+│ │ └── fonts/ # Liberation Mono (embedded via CMake hex read)
+│ │
+│ ├── attoruntime/ # Instrument runtime
+│ │ ├── attoruntime.h # Runtime API declarations
+│ │ ├── atto_gui.cpp # GUI bindings (imgui calls)
+│ │ ├── nano_imgui.cpp # High-level ImGui wrappers
+│ │ └── main.cpp # Stub entry point
+│ │
+│ └── legacy/ # Deprecated editor1 code
+│
+├── attostd/ # Standard library (.atto modules)
+│ ├── gui.atto # AV/audio FFI: av_create_window, audio_tick
+│ └── imgui.atto # ImGui FFI: buttons, sliders, text, windows
+│
+├── scenes/ # Example instruments
+│ ├── klavier/main.atto # Piano/synthesizer (29KB, 100+ nodes)
+│ └── multifader/main.atto # Fader mixing instrument (25KB)
+│
+├── tests/
+│ └── test_inference.cpp # Type inference unit tests
+│
+└── docs/
+ └── attolang.md # Full language specification (44KB)
+```
+
+## Subsystem Deep Dives
+
+### 1. attolang — Core Language Library
+
+The core library is a static C++ library with **zero external dependencies**. It defines
+the data model, type system, expression parser, inference engine, serialization, and
+graph builder. Everything in `src/atto/` belongs here.
+
+#### Data Model (`model.h`)
+
+The fundamental representation is a **FlowGraph**: a directed graph of nodes connected
+by typed links.
+
+```
+FlowGraph
+├── nodes: vector
+│ ├── guid: string (stable identifier)
+│ ├── type: NodeTypeID (one of 38 built-in types)
+│ ├── args: string (inline arguments, legacy)
+│ ├── position: vec2 (editor layout)
+│ ├── inputs: vector (pin IDs for incoming connections)
+│ └── outputs: vector (pin IDs for outgoing connections)
+│
+└── links: vector
+ ├── from: string (output pin ID)
+ ├── to: string (input pin ID)
+ └── net_name: string (optional named net)
+```
+
+Nodes are passive data containers. All semantic meaning comes from the node's `type`
+field, which indexes into the node type registry.
+
+#### Type System (`types.h`, `type_utils.h`)
+
+The type system is the backbone of attolang. Every value has a **TypeExpr** with two
+orthogonal dimensions:
+
+1. **TypeKind** — what the value is (Void, Bool, Scalar, Container, Function, Symbol, etc.)
+2. **TypeCategory** — how the value is accessed (Data, Reference, Iterator, Lambda, etc.)
+
+Categories are denoted by sigils in the wire format:
+
+| Sigil | Category | Meaning |
+|-------|------------|-----------------------------------|
+| `%` | Data | Plain value (default) |
+| `&` | Reference | Reference to a mutable location |
+| `^` | Iterator | Iterator into a container |
+| `@` | Lambda | Callable function reference |
+| `#` | Enum | Enumeration value |
+| `!` | Bang | Trigger signal (carries no data) |
+| `~` | Event | Event source |
+
+Type expressions are parsed by `TypeParser` (recursive descent) and interned in
+`TypePool` for deduplication. The pool caches every parsed type string → `TypePtr`
+mapping.
+
+Key type features:
+- **Literal types**: `literal` — compile-time constants with type domain T and value V
+- **Symbol types**: `symbol` — first-class named references with decay
+- **Meta types**: `type` — types as compile-time values
+- **Generic types**: `unsigned>`, `float` — resolved via backpropagation
+- **Automatic upcasting**: u8 → u16 → u32 → u64, s8 → s32 → s64, integer → float
+
+#### Expression Parser (`expr.h`, `expr.cpp`)
+
+Expressions are inline code within nodes (e.g., `$0 + $1 * sin($2)`). The parser is a
+recursive-descent parser producing an `ExprNode` AST.
+
+Expression kinds include:
+- `Literal` — all constants (integers, floats, booleans, strings)
+- `PinRef` — `$N` references to input pins
+- `BinaryOp` — arithmetic, comparison, logical operators
+- `UnaryOp` — negation, logical not
+- `FunctionCall` — `name(args...)` including type constructors
+- `FieldAccess` — `expr.field`
+- `IndexOp` — `expr[index]`
+- `TypeApply` — `$0<$1,$2>` speculative generic application
+
+The tokenizer handles TOML string escaping, nested parentheses, and the distinction
+between struct types (`{x:f32 y:f32}`) and struct literals (`{x:1.0f, y:2.0f}`) via
+comma detection.
+
+#### Inference Engine (`inference.h`, `inference.cpp`)
+
+Type inference is **bidirectional** and **multi-pass**:
+
+```
+Phase 1: clear_all() — Reset all pin types
+Phase 2: resolve_pin_type_names() — Parse type annotations via TypePool
+Phase 3: propagate_connections() — Forward: flow types through wires
+Phase 4: infer_expr_nodes() — Recursive inference on expression ASTs
+Phase 5: propagate_pin_ref_types()— Backward: backprop from consumers
+Phase 6: resolve_lambdas() — Validate lambda capture and parameters
+Phase 7: fixup_expr_derefs() — Insert Deref nodes for iterators
+Phase 8: insert_deref_nodes() — Materialize shadow deref nodes
+```
+
+The engine runs to a fixed point for phases 3-5, iterating until no types change.
+This handles mutual dependencies between nodes (A depends on B depends on A).
+
+#### Graph Builder (`graph_builder.h`, `graph_builder.cpp`)
+
+The GraphBuilder is the **high-level editing API** layered over the raw FlowGraph model.
+It provides:
+
+- **Structured entries**: `FlowNodeBuilder` and `NetBuilder` with `BuilderEntry` base
+- **Pin model**: `FlowArg2` hierarchy (ArgNet2, ArgNumber2, ArgString2, ArgExpr2)
+- **Dirty tracking**: mutations bubble up from arg → node → graph
+- **Observer pattern**: `IGraphEditor` / `INodeEditor` / `INetEditor` interfaces
+- **Mutation batching**: `edit_start()` / `edit_commit()` for transactional edits
+- **Sentinels**: `$empty` (node) and `$unconnected` (net) — always valid, never null
+
+The builder also handles v0→v1 format migration, auto-generated IDs (`$auto-xxx` → `$a-N`),
+and shadow node folding during import.
+
+#### Serialization (`serial.h`, `serial.cpp`)
+
+The `.atto` file format is TOML-like with section headers:
+
+```toml
+version = "instrument@atto:0"
+
+[viewport]
+x = -6131.11
+y = -1999.86
+zoom = 1.4641
+
+[[node]]
+guid = "934e3b98bb914e95"
+type = "decl_type"
+args = ["osc_res", "s:f32", "e:bool"]
+position = [757.077, 266.729]
+
+[[link]]
+from = "$auto-df6e4aa3d0d8d2bc-out0"
+to = "$auto-831e483b4e4602dc_s1-out0"
+net_name = "$osc-signal"
+```
+
+Version history: `nanoprog@0` → `nanoprog@1` → `attoprog@0` → `attoprog@1` → `instrument@atto:0`.
+Auto-migration on load handles all legacy formats.
+
+### 2. attoc — Compiler
+
+The compiler is a standalone executable that transforms `.atto` files into self-contained
+C++ projects. The pipeline:
+
+```
+.atto file
+ │
+ ▼
+load_atto() ──────────────── Parse TOML → FlowGraph
+ │
+ ▼
+resolve_type_based_pins() ── Populate dynamic pins for new/event! nodes
+ │
+ ▼
+GraphInference::run() ────── Multi-pass bidirectional type inference
+ │
+ ▼
+validate() ──────────────── Collect type errors, pin mismatches
+ │
+ ▼
+CodeGenerator::generate_*()
+ ├── _types.h ───── Struct definitions from decl_type nodes
+ ├── _program.h ─── Class declaration with event handlers
+ ├── _program.cpp ─ Implementation: node logic, expression eval
+ ├── CMakeLists.txt ───── Build script for the instrument
+ └── vcpkg.json ───────── Dependency manifest
+```
+
+The generated C++ is a complete, standalone project. Each instrument compiles
+independently with its own CMakeLists.txt.
+
+### 3. attoflow — Visual Editor
+
+The editor has a three-layer architecture:
+
+```
+FlowEditorWindow (top-level)
+├── Tab management (multiple .atto files)
+├── Project file browser
+├── Build/run toolbar
+├── Child process management
+│
+└── Editor2Pane (per-tab)
+ ├── Wraps GraphBuilder (semantic model)
+ ├── Implements IGraphEditor observer
+ ├── Wire connection logic (drag, connect, reconnect)
+ ├── NodeEditorImpl per node (layout cache)
+ ├── NetEditorImpl per net
+ │
+ └── VisualEditor (rendering base)
+ ├── Canvas state (pan, zoom, grid)
+ ├── Hover detection (wires → nodes → pins)
+ ├── Node rendering (pins, inline args, errors)
+ └── Wire drawing (bezier curves, WireInfo)
+```
+
+The hover system uses a distance-based priority: wires → nodes → pins, with pins
+getting a priority bias for easier selection.
+
+Pin shapes encode type categories:
+- **Circle** — Data
+- **Square** — Bang
+- **Triangle** — Lambda
+- **Diamond** — Variadic args / optional
+
+### 4. attohost — Runtime (Planned)
+
+The runtime architecture separates the editor from user program execution:
+
+```
+attoflow.exe attohost.exe
+(editor process) (host process)
+ │ │
+ │ spawn + pipe name arg │
+ ├──────────────────────────────>│
+ │ │ LoadLibrary(instrument.dll)
+ │ │ resolve on_start()
+ │ IPC: wire table │ run on_start()
+ │<──────────────────────────────┤
+ │ │
+ │ IPC: dirty wire updates │ per-frame/tick updates
+ │<──────────────────────────────┤
+ │ │
+ │ IPC: value override │
+ ├──────────────────────────────>│ inject values for debugging
+ │ │
+ │ IPC: reload signal │
+ ├──────────────────────────────>│ unload dll, load new, restart
+```
+
+Key design decisions:
+- **Process isolation**: user program crash doesn't take down the editor
+- **Hot-reload**: unload DLL, load new one, call `on_start` again
+- **wire**: zero-cost in release (typedef to T), inspectable in debug mode
+- **Named pipes**: editor is always the server, host is always the client
+
+## Cross-Cutting Concerns
+
+### Node Type System
+
+There are 38 built-in node types organized into categories:
+
+| Category | Nodes |
+|---------------|----------------------------------------------------------|
+| Data | expr, new, dup, str, select, cast, void |
+| Collections | append/append!, erase/erase!, iterate/iterate!, next |
+| Control | select!, lock!, iterate!, store!, output_mix! |
+| Declarations | decl_type, decl_var, decl_event, decl_import, ffi, decl |
+| Events | on_key_down!, on_key_up!, event! |
+| Special | call/call!, lock/lock!, label, error |
+
+Bang (`!`) nodes have execution ordering — they fire in the order of their bang chain,
+providing deterministic side-effect sequencing in a dataflow graph.
+
+### Standard Library
+
+The `attostd/` directory contains `.atto` module files that declare FFI bindings:
+
+- **gui.atto**: `av_create_window(title, audio_tick, sample_rate, channels, video_tick, width, height, on_close)` — creates a window with audio and video callbacks
+- **imgui.atto**: 25+ ImGui bindings (buttons, sliders, text, windows, layout)
+
+These are imported via `decl_import` nodes in user instruments.
+
+### Web Target (Planned)
+
+Future web deployment via a compile server:
+
+```
+Browser (Emscripten build of editor)
+ │
+ │ POST /compile (sends .atto)
+ ▼
+Compile Server (hardened Pi)
+ │ attoc → C++ → emcc → .wasm
+ ▼
+Browser loads result as side module
+```
+
+The server is containerized with no network access inside, 60s timeout, 512MB RAM limit,
+read-only rootfs. Only `.atto` goes in (small attack surface), controlled C++ comes out.
+
+## Design Principles
+
+1. **Zero-dependency core**: attolang has no external dependencies. Only the editor needs SDL3/ImGui.
+2. **Graph IS the program**: no separate AST. The FlowGraph is the canonical representation, serialized directly.
+3. **Type-driven everything**: inference, validation, codegen, and editor rendering all flow from the type system.
+4. **Bidirectional inference**: types propagate both forward (producers → consumers) and backward (consumers → producers).
+5. **Observer not polling**: GraphBuilder notifies editors of changes via interfaces, not polling for dirty state.
+6. **Sentinels over nulls**: `$empty` and `$unconnected` are always-valid stand-ins, eliminating null checks.
+7. **Process isolation**: the editor and runtime are separate processes communicating via IPC.
+8. **Instruments are self-contained**: each compiled instrument is a standalone C++ project with its own build system.
diff --git a/docs/attolang.md b/docs/attolang.md
new file mode 100644
index 0000000..3517e99
--- /dev/null
+++ b/docs/attolang.md
@@ -0,0 +1,843 @@
+# attolang Language Specification
+
+## Type System
+
+### Value Categories
+
+A value in AttoProg has a **category**:
+
+| Category | Description |
+|-----------|--------------------------------------|
+| Data | Plain value |
+| Reference | Reference to a value (`&T`) |
+| Iterator | Iterator into a container (`^T`) |
+| Lambda | Callable function reference |
+| Enum | Enumeration value |
+| Bang | Trigger signal (no data) |
+| Event | Event source |
+
+Value categories are part of the type system but are not indicated by prefix sigils during access. The only prefix syntax retained is `$N` for pin references in expressions (see [Input References](#input-references)).
+
+### Literal Type
+
+`literal` is a unified compile-time value type, parameterized by a type domain `T` and a compile-time value `V`. All compile-time constants — numbers, booleans, and strings — are represented as literals. The canonical format uses no spaces: `literal`.
+
+| Expression | Type | Notes |
+|---|---|---|
+| `0` | `literal,0>` | Type-generic: resolves to concrete unsigned type from context |
+| `-1` | `literal,-1>` | Type-generic: resolves to concrete signed type from context |
+| `42` | `literal,42>` | Type-generic: resolves to concrete unsigned type from context |
+| `3.14f` | `literal` | Concrete f32 literal |
+| `3.14` | `literal` | Concrete f64 literal |
+| `true` | `literal` | Parsed directly as a boolean literal |
+| `false` | `literal` | Parsed directly as a boolean literal |
+| `"hello"` | `literal` | String literal |
+
+`true` and `false` are parsed as boolean literals by the expression parser — they are not symbols.
+
+Bare identifiers (`sin`, `pi`, `myvar`, etc.) produce **symbol types**, not literals — see [Symbol Types](#symbol-types).
+
+#### Literal Typing
+
+Literal types have two flags:
+
+- **`is_generic`** — The **type** is unresolved (e.g., `0` could be `u8`, `u16`, `u32`, `f32`, etc.). Resolved via backpropagation from context.
+- **`is_unvalued_literal`** — The **value** is not yet provided (used for input pins that expect a literal). Displayed as `literal` (e.g., `literal`).
+
+| Example | `is_generic` | `is_unvalued_literal` | Display |
+|---|---|---|---|
+| `0` (unresolved int) | true | false | `literal,0>` |
+| `1.0f` (concrete) | false | false | `literal` |
+| input pin expecting string | false | true | `literal` |
+| `vector>` | true | false | `vector>` |
+
+#### Literal Decay
+
+Literals decay to their resolved types when consumed by operations:
+
+- **Operations** (binary ops, function calls, `select`, builtins) on literals produce **non-literal runtime types**. `0 + 1` produces `literal,?>`, not a literal. `sin(1.0f)` produces `f32`, not `literal`.
+- **Connections and passthrough** (dup, wire connections) preserve literal types — literals flow as-is through wires.
+- **Type-generic literals** (`unsigned>`, `float>`) resolve via backpropagation when a concrete type is known from context.
+
+Integer literals coerce to `f32` or `f64` from context, but only if the value can be represented exactly (f32: |v| <= 2^24 = 16777216, f64: |v| <= 2^53). Values that exceed these limits produce an error.
+
+#### Literal Syntax in Expressions
+
+`literal` can be typed directly in expression nodes:
+
+```
+expr literal
+expr literal,42>
+expr literal,-5>
+expr literal
+```
+
+This produces the same result as the shorthand forms (`"abc"`, `42`, `-5`, `true`).
+
+`literal`, `symbol`, and `undefined_symbol` are **reserved keywords** in the expression parser — they cannot be used as identifiers.
+
+### Symbol Types
+
+Bare identifiers in expressions produce **symbol types**, not literals. Symbols are first-class values that carry both a name and a decay type.
+
+- **`symbol`** — A defined symbol found in the symbol table. `name` is the symbol name, `type` is the decay type (what it resolves to when consumed). Example: `expr sin` produces `symbolf32>`. `expr myvar` (where `myvar` is declared as `f32`) produces `symbol`.
+- **`undefined_symbol`** — A bare identifier not (yet) in the symbol table. Valid to pass around at compile time (e.g., as a name input to `decl_var`). Does not produce an error at inference time. Errors only if something tries to **evaluate** it (emit runtime code).
+
+#### Symbol Decay
+
+Symbols decay automatically when **consumed** by operations:
+
+- **Operations** (binary ops, function calls, builtins, store, select, field access, indexing, unary ops) decay symbols to their wrapped type before processing.
+- **Connections** decay symbols when propagating through wires — the receiving pin gets the decayed type.
+- **Non-expr nodes** (store!, iterate!, append!, etc.) decay all symbol types from inline expressions before validation.
+- **Expr node outputs** preserve symbol types — `expr sin` outputs `symbolf32>`, not the decayed function type.
+- **Type utility functions** (`is_numeric`, `is_float`, `is_collection`, `types_compatible`, etc.) auto-decay symbols transparently.
+
+#### Symbol Table
+
+The symbol table maps symbol names to their meanings. It is populated by:
+
+1. **Built-in entries** (predefined):
+
+| Symbol | Decays to |
+|--------|-----------|
+| `sin` | `(float) -> float` |
+| `cos` | `(float) -> float` |
+| `pow` | `(float, float) -> float` or `(literal, unsigned) -> unsigned` |
+| `exp` | `(float) -> float` |
+| `log` | `(float) -> float` |
+| `or` | `(integer, integer) -> integer` |
+| `xor` | `(integer, integer) -> integer` |
+| `and` | `(integer, integer) -> integer` |
+| `not` | `(integer) -> integer` |
+| `mod` | `(numeric, numeric) -> numeric` |
+| `rand` | `(numeric, numeric) -> numeric` |
+| `pi` | `float>` (value 3.14159265358979323846) |
+| `e` | `float>` (value 2.71828182845904523536) |
+| `tau` | `float>` (value 6.28318530717958647692) |
+| `true` | `bool` |
+| `false` | `bool` |
+| `f32` | `type` |
+| `f64` | `type` |
+| `u8` | `type` |
+| `u16` | `type` |
+| `u32` | `type` |
+| `u64` | `type` |
+| `s8` | `type` |
+| `s16` | `type` |
+| `s32` | `type` |
+| `s64` | `type` |
+| `bool` | `type` |
+| `string` | `type` |
+| `void` | `type` |
+| `mutex` | `type` |
+| `vector` | `type>` |
+| `map` | `type