AGENTS.md - Beamtalk Development Guidelines (Expanded)
July 31, 2026 Β· View on GitHub
This document provides guidance for AI coding agents working on the beamtalk compiler and ecosystem.
Repository Information
Always use these values for GitHub API calls:
| Property | Value |
|---|---|
| Owner | jamesc |
| Repository | beamtalk |
| Full name | jamesc/beamtalk |
| URL | https://github.com/jamesc/beamtalk |
Example gh CLI usage:
gh api repos/jamesc/beamtalk/pulls
gh pr create --repo jamesc/beamtalk
Project Overview
Beamtalk is a Smalltalk/Newspeak-inspired programming language that compiles to the BEAM virtual machine. The compiler is written in Rust and generates Core Erlang, which is then compiled to BEAM bytecode via erlc.
Key principle: Beamtalk is an interactive-first language. The live environment and hot code reloading are core to the design, not afterthoughts.
Important: While heavily inspired by Smalltalk, Beamtalk makes pragmatic departures from Smalltalk syntax and semantics to work well with BEAM and modern development practices. We're "Smalltalk-like," not Smalltalk-compatible. See beamtalk-syntax-rationale.md for specific differences, beamtalk-principles.md for design philosophy, and beamtalk-language-features.md for full language specification.
Syntax Verification - Preventing Hallucinations π¨
CRITICAL: AI agents must verify all Beamtalk syntax before using it in code, tests, or examples. Do not invent or assume syntax patterns exist.
Common Hallucination Patterns
| Pattern | Example | Reality |
|---|---|---|
| Inline class syntax | Counter := Actor [...] | Only Actor subclass: Counter works |
| Ruby/Python-style | Point.new(x: 3) | Beamtalk uses Point new: #{x => 3} |
| Compound assignment | self.value += 1 | Use self.value := self.value + 1 (ADR 0001) |
| Missing constraints | Counter new on Actor | Error β actors use spawn, not new |
| Sealed subclassing | Integer subclass: MyInt | Primitives are sealed, cannot subclass |
| Smalltalk verbatim | Object subclass: #Counter | Beamtalk uses identifiers, not symbols |
| Load syntax confusion | @load in REPL | Use :load in REPL, @load only in test files |
| Pragma confusion | @primitive blockValue | Structural intrinsics use @intrinsic; @primitive is for quoted selectors only |
Test File Rules
In test files (stdlib/bootstrap-test/*.btscript and tests/repl-protocol/cases/*.btscript):
- Every expression MUST have a
// =>assertion (even// => _for wildcard) - No assertion = no execution β expressions are silently skipped
- Missing assertions fail CI (BT-249)
- Pattern matching in assertions:
_within a pattern is a wildcard segment (e.g.,Actor(Counter, _)) @loadis a test directive;:loadis a REPL command β don't mix them up
β οΈ Dangerous pattern β this looks fine but DOESN'T RUN:
x := 0
3 timesRepeat: [x := x + 1] // No assertion β SKIPPED, never executes!
x
// => 3 // Fails! x was never set
Safe pattern β always add assertions:
x := 0
// => _
3 timesRepeat: [x := x + 1]
// => nil
x
// => 3
Verification Before Using Syntax
Before using ANY Beamtalk syntax, verify it exists in at least one of:
- Language spec: docs/beamtalk-language-features.md
- Examples:
examples/*.bt - Tests:
stdlib/bootstrap-test/*.btscript,tests/repl-protocol/cases/*.btscript - Parser tests:
crates/beamtalk-core/src/source_analysis/parser/
If it doesn't appear in any of these β it's likely hallucinated. Search the codebase or ask.
Pattern Lookup Protocol β Required Before Any New Implementation
Before writing new .bt code or Erlang FFI, run these searches and review 3+ hits:
# Find existing examples of a class/method pattern in Beamtalk source
grep -r "subclass:" stdlib/test/ stdlib/src/ examples/ --include="*.bt" -l
grep -r "state:.*::" stdlib/src/ --include="*.bt" | head -10 # type annotations
grep -r "ifTrue:\|ifFalse:\|whileTrue:" stdlib/test/ --include="*.bt" | head -10
# Find Erlang FFI primitives for a domain area
grep -r "beamtalk_\|@primitive\|(Erlang " stdlib/src/ --include="*.bt" | head -10
grep -r "beamtalk_http\|beamtalk_system\|beamtalk_file" runtime/apps/ --include="*.erl" -l
# Confirm type annotation syntax (always ::, never :)
grep -r " :: " stdlib/src/ --include="*.bt" | head -5
# Confirm ^ usage (early return only, never on last expression)
grep -rn "\^" stdlib/src/ stdlib/test/ --include="*.bt" | grep -v "// =>" | head -10
Do this lookup before proposing an approach. Show the examples found, identify the pattern they follow, then implement consistently with them. If no examples exist, check the language spec before writing any code.
Domain-Driven Design (DDD)
The beamtalk architecture follows Domain-Driven Design. Use domain terms consistently (e.g., CompletionProvider not completions). The codebase has four bounded contexts: Language Service (IDE features), Compilation (lexerβcodegen), Runtime (actors, OTP), and REPL (interactive dev).
All new modules should include a DDD Context header near the top of the file. Use the correct comment style for the language:
- Rust:
//! **DDD Context:** ContextName - Erlang:
%%% **DDD Context:** ContextName(triple%β module-level doc style)
See docs/beamtalk-ddd-model.md for the full domain model.
Erlang Documentation β EEP-59 Attributes
All Erlang modules use EEP-59 structured doc attributes (not EDoc comments):
-moduledoc "Module summary here.".
-doc "Function purpose here.".
-spec my_function(Arg) -> Result.
my_function(Arg) -> ....
-moduledoc "..."replaces%%% @docat module level-doc "..."before each exported function replaces%%% @docbefore functions- Do not use
-doc falsefor internal helpers β keep docs visible for developers and tooling - DDD Context stays as a regular
%%%comment (not part of EEP-59) - These attributes compile directly into EEP-48 doc chunks in
.beamfiles (OTP 27+), making docs available via:h Erlang <module>
See erlang-guidelines.md for full details.
Development Architecture Principles
The beamtalk codebase follows strict architectural principles for code organization, error handling, testing, security, and dependencies. Full details in docs/development/architecture-principles.md.
Core principles:
- Layered Architecture - Dependencies flow down only (core never depends on CLI)
- Error Recovery - Return partial results + diagnostics (don't stop at first error)
- Testing Pyramid - Unit 60-70%, Integration 20-30%, E2E 10%
- Security-First - Input validation at boundaries, no unsafe without justification
- Minimal Dependencies - Prefer std library, document why each dependency exists
Critical rules:
β NEVER:
beamtalk-coreimportingbeamtalk-cliorbeamtalk-lsp- Panic on user input (malformed source, invalid args, missing files)
- Add dependencies without security review and commit message justification
- Use
unwrap()on user input - Use bare tuple errors in user-facing code - Public API errors MUST use
#beamtalk_error{}records (internal runtime helpers may use{ok, Value} | {error, Reason}if translated at boundaries)
β ALWAYS:
- Return
(Result, Vec<Diagnostic>)or equivalent for user-facing operations - Validate file paths and buffer boundaries
- Document unsafe code with
// SAFETY:comment explaining invariants - Run
cargo auditbefore releases - Use structured errors at public API boundaries -
beamtalk_error:new/3+with_hint/with_detailsfor all user-facing error paths
See full guide: docs/development/architecture-principles.md
Error Handling - CRITICAL RULES
All user-facing/public API errors MUST use the structured #beamtalk_error{} system. Internal runtime helpers (in runtime/**/*.erl) may use bare {ok, Value} | {error, Reason} tuples, but these MUST be translated to #beamtalk_error{} at public API boundaries before reaching user code.
Structured Error System
All errors use #beamtalk_error{} records defined in runtime/include/beamtalk.hrl:
-record(beamtalk_error, {
kind :: atom(), % does_not_understand | immutable_value | type_error | instantiation_error | ...
class :: atom(), % 'Integer', 'Counter', 'Actor'
selector:: atom() | undefined, % method that failed
message :: binary(), % human-readable explanation
hint :: binary() | undefined,% actionable suggestion
details :: map() % additional context
}).
In Runtime Erlang Code
Use beamtalk_error module helpers:
Error0 = beamtalk_error:new(does_not_understand, 'Integer', 'foo'),
Error1 = beamtalk_error:with_hint(Error0, <<"Check spelling">>),
error(Error1)
In Generated Core Erlang Code
Codegen MUST use beamtalk_error calls:
%% β WRONG - bare tuple (never do this!)
call 'erlang':'error'({'some_error', 'message'})
%% β
RIGHT - structured error
let Error0 = call 'beamtalk_error':'new'('instantiation_error', 'Actor', 'new') in
let Error1 = call 'beamtalk_error':'with_hint'(Error0, <<"Use spawn instead">>) in
call 'erlang':'error'(Error1)
Error Kinds
| Kind | When | Example |
|---|---|---|
does_not_understand | Unknown method | 42 foo |
immutable_value | Mutation on primitive | 42 fieldAt:put: |
type_error | Wrong argument type | "hello" + 42 |
arity_mismatch | Wrong argument count | Missing/extra args |
instantiation_error | Wrong instantiation | Actor new (use spawn) |
future_not_awaited | Message to Future | (future) size |
timeout | Operation timeout | Await exceeds deadline |
Benefits of Structured Errors
- Consistent tooling - Pattern match on kind/class/selector
- Better UX - Actionable hints guide users
- Rich context - Details map for debugging
- Future-proof - Easy to add metadata without breaking changes
See full error taxonomy: docs/internal/design-self-as-object.md
Logging - CRITICAL RULES
Erlang runtime: Use OTP logger macros (?LOG_ERROR, ?LOG_WARNING, ?LOG_INFO, ?LOG_DEBUG), never io:format or logger:error() function calls. Macros auto-include caller MFA metadata. Every .erl file that logs must include -include_lib("kernel/include/logger.hrl"). Always use structured metadata maps, not format strings.
Rust CLI: Use the tracing crate (trace!, debug!, info!, warn!, error!). Use println! for user-facing output, tracing for diagnostics. Enable with RUST_LOG=beamtalk_cli=debug.
See docs/development/erlang-guidelines.md for full logging guidelines.
User Experience & Developer Experience (DevEx) First
A feature is not done until the user can interact with it in the REPL. Building internal infrastructure is necessary but insufficient β always complete the loop to user-facing integration.
Before marking any feature complete, verify:
- Feature works in the REPL β can demonstrate in 1-2 lines
- Error messages are user-friendly and actionable (use
selfnotSelf) - Examples in
examples/or docs show real usage - Failure modes tested and produce helpful output
π© Red flags: "Infrastructure is done" but no user sees it. "Tests pass" but no examples. "Error handling works" but messages are raw tuples.
Scope Control
Fix inline: formatting/typos in files you're modifying, test failures from your changes, clippy warnings in your code, docs for features you just added.
Create follow-up issue: bugs in unrelated code, performance optimization opportunities, missing tests in other modules, refactoring not required for current issue.
π© Scope creep red flags: PR grows beyond 10 files, "just one more thing", acceptance criteria met but still coding.
Debugging
See docs/development/debugging.md for step-by-step debugging guides covering compiler crashes, runtime errors, test failures, E2E failures, codegen debugging, and performance profiling.
If stuck for >30 minutes: Stop and ask. Summarize what you tried, share the error, ask for direction.
Work Tracking
We use Linear for task management. Project prefix: BT
Referencing Issues
Include the Linear issue ID in commits and PR titles:
git commit -m "Implement lexer tokens BT-123"
Issue Lifecycle
| State | Meaning |
|---|---|
| Backlog | Idea captured, not yet specified |
| Ready | Fully specified with acceptance criteria; agent can pick up |
| In Progress | Actively being worked on |
| In Review | Code complete, needs human verification |
| Done | Merged and verified |
Labels
We use several label groups to categorize issues:
Agent State
Tracks workflow status:
agent-ready- Task is fully specified, agent can start immediatelyneeds-spec- Requires human to clarify requirements before work beginsblocked- Waiting on external dependency or another issuehuman-review- Agent completed work, needs human verificationdone- Issue is complete and closed
Item Area
Identifies which component of the codebase the issue affects:
| Label | Description | Key Directories |
|---|---|---|
class-system | Class definition, parsing, codegen, and runtime | crates/beamtalk-core/src/ast.rs, crates/beamtalk-core/src/source_analysis/ |
stdlib | Standard library: collections, primitives, strings (compiled from stdlib/src/*.bt via pragmas β see ADR 0007) | stdlib/src/ |
repl | REPL backend and CLI interaction | runtime/src/beamtalk_repl.erl, crates/beamtalk-cli/src/repl/ |
cli | Command-line interface and build tooling | crates/beamtalk-cli/ |
codegen | Code generation to Core Erlang/BEAM | crates/beamtalk-core/src/erlang.rs |
runtime | Erlang runtime: actors, futures, OTP integration | runtime/src/ |
parser | Lexer, parser, AST | crates/beamtalk-core/src/source_analysis/, crates/beamtalk-core/src/ast.rs |
Issue Type
Categorizes the kind of work:
Epic- Large initiatives that group related issues (5+ child issues)Feature- A chunk of customer visible workBug- Bugs, broken tests, broken codeImprovement- Incremental work on top of a featureDocumentation- Words that explain thingsInfra- Tools, CI, dev environment configurationLanguage Feature- New Beamtalk language syntax/semanticsRefactor- Code cleanups, tech debtResearch- Research projects, code spikesSamples- Code, examples, things to help devs get started
Item Size
T-shirt sizing for estimates: S, M, L, XL
When creating issues: Always set:
- An Agent State label (
agent-readyorneeds-spec) - An Item Area label (what part of codebase)
- An Issue Type label (what kind of work)
- An Item Size label (how big)
Epics
Epics group 5+ related issues for large initiatives. Use Epic: title prefix, Epic label, and size XL or L. Link child issues with "blocks" relationships. Include overview, goals, status summary, and child issue list in description.
Query Linear for epic status with the Linear MCP tools (e.g. list_issues filtered to the Epic label and In Progress state).
Writing Agent-Ready Issues
For an issue to be agent-ready, include:
- Context - Why this work matters, background info
- Acceptance Criteria - Specific, testable requirements (checkboxes)
- Files to Modify - Explicit paths to relevant files
- Dependencies - Other issues that must complete first
- References - Links to specs, examples, or related code
- Blocking Relationships - Use Linear's "blocks" relationship for dependencies
Example:
Title: Implement basic lexer token types
Context:
The lexer is the first phase of compilation. It needs to tokenize
Smalltalk-style message syntax including identifiers, numbers, and keywords.
Acceptance Criteria:
- [ ] Tokenize identifiers (letters, digits, underscores)
- [ ] Tokenize integers and floats
- [ ] Tokenize single and double quoted strings
- [ ] Tokenize message keywords ending in `:`
- [ ] Tokenize block delimiters `[` `]`
- [ ] All tokens include source span
Files to Modify:
- crates/beamtalk-core/src/source_analysis/token.rs
- crates/beamtalk-core/src/source_analysis/lexer.rs
Dependencies: None
References:
- See Gleam lexer: github.com/gleam-lang/gleam/blob/main/compiler-core/src/parse/lexer.rs
Creating Issue Blocking Relationships
When creating issues with dependencies, always set up Linear's "blocks" relationships:
// After creating issues BT-X and BT-Y, where BT-X blocks BT-Y:
mutation {
issueRelationCreate(input: {
issueId: "<BT-X issue ID>"
relatedIssueId: "<BT-Y issue ID>"
type: blocks
}) {
success
}
}
Rules:
- If issue A must be completed before issue B can start, then A "blocks" B
- Always create blocking relationships when dependencies are mentioned
- Linear automatically shows blocked/blocking status in the UI
- Use GraphQL to create relationships after issue creation
- Set agent-state label when creating issues:
agent-readyif fully specified with all acceptance criterianeeds-specif human clarification needed first
Example: For stdlib implementation issues:
- BT-21 (API definitions) blocks BT-32, BT-33, BT-34, BT-35, BT-36, BT-37
- BT-32 (block evaluation) blocks BT-35 (iteration uses blocks) and BT-37 (collections use blocks)
- All new issues marked with
agent-readylabel
Architecture Decision Records (ADRs)
Significant design decisions are documented as ADRs in docs/ADR/. Create an ADR when a decision affects language design, core architecture, interoperability, or user-facing behavior.
Format: docs/ADR/NNNN-kebab-case-title.md with Status, Context, Decision, Consequences, References sections. Number sequentially, update docs/ADR/README.md index. See existing ADRs for format examples.
Agent Skills
Agent skills are defined as personal skills in ~/.claude/skills/ (Claude Code) or ~/.copilot/skills/ (Copilot). They are not stored in the repository.
Available skills include: pick-issue, done, resolve-pr, resolve-merge, create-issue, refresh-issue, update-issues, whats-next, draft-adr, plan-adr, plan-refactor, do-refactor, review-code, review-adr.
Repository Structure
runtime/
βββ rebar.config # Umbrella project config (ADR 0007, 0009)
βββ apps/
β βββ beamtalk_runtime/ # Core runtime OTP application (ADR 0009)
β β βββ src/ # Runtime source (primitives, object system, actors, futures)
β β βββ include/ # Header files (beamtalk.hrl)
β β βββ test/ # Runtime unit tests (*.erl)
β β βββ config/ # OTP sys.config
β β βββ test_fixtures/ # Fixtures for runtime tests (BT-239)
β β βββ logging_counter.bt
β β βββ compile_fixtures.escript # Auto-compiles fixtures via rebar3 pre-hook
β β βββ README.md
β βββ beamtalk_workspace/ # Workspace and interactive development OTP application (ADR 0009) β NEW
β β βββ src/ # REPL source (repl eval, server, workspace supervision, session management)
β β βββ test/ # REPL unit tests (*.erl)
β βββ beamtalk_stdlib/ # Standard library OTP application (ADR 0007)
β βββ src/ # Application metadata (beamtalk_stdlib.app.src)
β βββ ebin/ # Generated .beam files (Actor, Block, Integer, etc.) created by build-stdlib
stdlib/
βββ bootstrap-test/ # Bootstrap expression tests (ADR 0014)
β βββ arithmetic.btscript # 12 test files β run via `just test-stdlib`
β βββ booleans.btscript
β βββ ...
βββ test/ # BUnit TestCase tests
βββ actor_test.bt # 151 test files β run via `just test-bunit`
βββ array_test.bt
βββ ...
tests/
βββ e2e/
βββ cases/ # REPL integration tests (54 .btscript files)
βββ fixtures/ # Shared test fixtures
βββ counter.bt # CANONICAL counter implementation (BT-239)
examples/
βββ getting-started/ # Beginner tutorial project
βββ bank/ # Banking example with actors
βββ chat-room/ # Multi-actor chat example
βββ otp-tree/ # Supervision tree example
βββ repl-tutorial.md # REPL tutorial (BT-239)
Dependency direction (ADR 0009):
beamtalk_workspace (interactive dev)
β depends on
beamtalk_runtime (core language runtime)
β depends on
beamtalk_stdlib (compiled stdlib)
Test Organization - CRITICAL DISTINCTION
IMPORTANT: The test suite has multiple layers. Be precise about which tests you're referring to:
1. Runtime Unit Tests
Location: runtime/apps/beamtalk_runtime/test/*_tests.erl (e.g., beamtalk_actor_tests.erl)
- Tests individual runtime modules in isolation
- Uses hand-written test fixtures (e.g.,
test_counter.erl) - Calls
gen_serverprotocol directly with raw pids - Appropriate for testing low-level runtime behavior
2. REPL Unit Tests
Location: runtime/apps/beamtalk_workspace/test/*_tests.erl (ADR 0009)
- Tests REPL evaluation, protocol, server, workspace management
- Includes session supervision and idle monitoring tests
- Moved from
beamtalk_runtime/test/in BT-351
3. Codegen Simulation Tests
Location: runtime/apps/beamtalk_runtime/test/beamtalk_codegen_simulation_tests.erl
- Tests using real compiled Beamtalk code from
tests/repl-protocol/fixtures/counter.bt(unified fixture - BT-239) - The
spawn/0andspawn/1tests usecounter:spawn()from compiled module - Other tests use simulated state structures for complex scenarios
- Test fixtures compile automatically via rebar3 pre-hook (no manual step needed)
- Fixtures:
logging_counter.btstored inruntime/apps/beamtalk_runtime/test_fixtures/,counter.btsourced from REPL-protocol fixtures - Compiled by
runtime/apps/beamtalk_runtime/test_fixtures/compile_fixtures.escript(rebar3 pre-hook) - See
docs/development/testing-strategy.mdfor compilation workflow details
4. Stdlib Tests (Compiled Expression Tests) β ADR 0014
Location: stdlib/bootstrap-test/*.btscript (12 files)
- Pure language feature tests compiled directly to EUnit (no REPL needed)
- Uses same
// =>assertion format as REPL-protocol tests - Runs via
just test-stdlib(fast, ~14s vs ~50s for REPL-protocol) - Tests arithmetic, strings, blocks, closures, collections, object protocol, etc.
- Supports
@loaddirectives for fixture-dependent tests (actors, sealed classes) - Use this for any new test that doesn't need REPL/workspace features
5. BUnit Tests (TestCase Classes) β ADR 0014 Phase 2
Location: stdlib/test/*.bt (project test directory)
- SUnit-style test classes that subclass
TestCase - Methods starting with
testare auto-discovered and run with fresh instances setUp/tearDownlifecycle methods for test fixtures- Assertion methods:
assert:,assert:equals:,deny:,should:raise:,fail: - Runs via
beamtalk test(compiles to EUnit, fast) - Can also run interactively in REPL:
CounterTest runAllorCounterTest run: #testName - Use this for stateful tests, complex actor interactions, multi-assertion scenarios
6. REPL-Protocol Tests (REPL Integration)
Location: tests/repl-protocol/cases/*.btscript (54 files)
- Require a running REPL daemon (started automatically by test harness)
- Test workspace bindings, REPL commands, variable persistence, auto-await
- Test
ERROR:assertion patterns and@load-errordirectives - Runs via
just test-repl-protocol(~50s) - Only use for tests that genuinely need the REPL
When choosing between stdlib, BUnit, and REPL-protocol tests:
| Test needs... | Where |
|---|---|
| Pure language features (arithmetic, strings, blocks) | stdlib/bootstrap-test/ |
| Collections (List, Dictionary, Set, Tuple) | stdlib/bootstrap-test/ |
Actor spawn + messaging (with @load) | stdlib/bootstrap-test/ |
| Stateful tests with setUp/tearDown | stdlib/test/*.bt (BUnit) |
| Complex actor interactions, multiple assertions | stdlib/test/*.bt (BUnit) |
| Workspace bindings (Transcript, Beamtalk) | tests/repl-protocol/cases/ |
| REPL commands, variable persistence | tests/repl-protocol/cases/ |
Auto-await, ERROR: assertions | tests/repl-protocol/cases/ |
Test Fixture Organization (BT-239)
Runtime fixtures: runtime/apps/beamtalk_runtime/test_fixtures/
- Colocated with runtime tests for better locality
- Compiled by
apps/beamtalk_runtime/test_fixtures/compile_fixtures.escript(rebar3 pre-hook) - Currently:
logging_counter.bt(super keyword tests) - Note:
counter.btconsolidated to REPL-protocol fixture
REPL-protocol fixtures: tests/repl-protocol/fixtures/
- Used by REPL-protocol test cases
counter.btis the canonical Counter implementation- Also used by runtime tests (unified fixture)
Development Guidelines
Detailed coding standards are in docs/development/:
| Guide | Description |
|---|---|
| Rust Guidelines | Naming, traits, error handling, testing, compiler patterns |
| Erlang Guidelines | Code generation, OTP patterns, BEAM interop |
| Common Tasks | Adding AST nodes, CLI commands, stdlib features |
| Debugging | Step-by-step debugging for all failure types |
| Language Features | Full Beamtalk syntax specification |
CI Commands
just ci # Run all CI checks (build, lint, test, test-integration, test-mcp, test-parity, test-repl-protocol, check-corpus, check-surface-drift)
just build # Build Rust + Erlang runtime
just test # Rust + stdlib + BUnit + runtime tests
just test-stdlib # Compiled language feature tests (~14s)
just test-bunit # BUnit TestCase tests
just test-repl-protocol # Run REPL TCP-protocol tests (~50s)
just fmt # Format all code
just clippy # Lints (warnings = errors)
just dialyzer # Erlang type checking
License Headers
All source code files (.rs, .erl, .bt, .hrl) must include:
// Copyright 2026 James Casey
// SPDX-License-Identifier: Apache-2.0
Do not add license headers to .md files. The repo LICENSE file covers all documentation content.
Beamtalk Style
- Implicit returns: Use
^ONLY for early returns, never on last expression - No periods: Newlines separate statements, not
. - Comments: Use
//and/* */, not Smalltalk's"..."
Blocks Passed Into Class Methods
A class method runs in its class object's gen_server process, so a block passed into one runs there, not where it was written. Values and non-local returns (^) cross that boundary fine; process-local side effects do not β a block that writes the process dictionary or reads self() affects the class process, and a block that messages the same class back raises dispatch_error rather than deadlocking (BT-3022).
Practical rule: a Collection subclass may implement do: via a class-side helper (the inherited protocol works), but that helper must not reach back into its own class. See Passing Blocks Through Class Methods.
Code Generation β Document API Only
All Core Erlang codegen MUST use Document / docvec! API. Never use format!() or string concatenation. If you see existing string-based patterns, convert them.
Clippy Discipline
Never suppress clippy warnings without a comment explaining why. Split long functions, remove dead code, fix return types. Goal: under 30 suppressions codebase-wide.
File Conventions
| Extension | Description |
|---|---|
.bt | Beamtalk source files |
.core | Generated Core Erlang |
.beam | Compiled BEAM bytecode |
.erl | Erlang source (helpers, tests) |
.hrl | Erlang header files |
Resources
Beamtalk Design
- Design Principles - Core philosophy guiding all decisions
- Language Features - Planned syntax and features
- Syntax Rationale - Why we keep/change Smalltalk conventions
- Architecture - Compiler, runtime, and live development flow
- Agent-Native Development - AI agents as developers and live actor systems
Rust Guidelines
- Microsoft Rust Guidelines - Pragmatic patterns for safety and maintainability
- Rust API Guidelines - Naming, traits, documentation standards
- Rust Style Guide - Formatting conventions
- Rust Design Patterns - Common patterns and idioms
BEAM/Erlang
Reference Implementations
- Gleam compiler - Rust-to-BEAM reference
- Newspeak language - Module system inspiration
- TypeScript compiler - Tooling-first architecture