# Enma Style Guide

> Conventions for writing Enma scripts, embedding the Enma SDK, and building single-player scripts on Perception.

Revision 2026.10, plus edits not yet released. This URL always serves the latest text; pin a revision with https://style.chopper.dev/enma@2026.10/llms.txt. Changelog: https://style.chopper.dev/enma/changelog.md.

Rule levels: MUST / MUST NOT (non-negotiable), SHOULD / SHOULD NOT (the default; deviate only with a short comment saying why), MAY (allowed when it helps), AVOID (allowed but a smell). In this document they appear as a bracketed prefix on each rule, after its stable ID, e.g. "`ENMA-02.1` [MUST] ...". Cite a rule by its ID (ENMA-02.1): IDs never change or get reused, and https://style.chopper.dev/enma#ENMA-02.1 links to the rule. Examples use a fictional host, `Project`, whose prefix is `PRJ`.

## Starter project

A Windows Premake host that embeds the Enma SDK through RAII engine, module and context owners, a script package laid out per the guide with tests beside each script, budget, permission and .emb round-trip tests, the clang-format config, and a CI workflow. It is generated from this guide and follows it, so prefer it over scaffolding a new codebase by hand.

Download it as a zip, renamed to the user's names, with a GET request (query parameters are optional; missing ones take their defaults, invalid ones return HTTP 400 with a message):

```bash
curl -fsSL "https://style.chopper.dev/enma/template/download?name=Project&code=PRJ" -o Project.zip && unzip Project.zip
```

Parameters:

- `name`: Project name. PascalCase. Names the host app, its namespace and the script package. Must match `^(?:[A-Z][A-Za-z0-9]{1,31})$`. Default `Project`.
- `code`: Host prefix. 2 or 3 letters. Prefixes the host's macros. Must match `^(?:[A-Z]{2,3})$`. Default `PRJ`.

After unzipping:

1. **Vendor the SDK.** Copy the Enma SDK's shipped/ folder into vendor/enma/, then run tools\Setup.bat to add doctest and generate the solution.
2. **Build and test.** Build the solution in Visual Studio, then run the -Tests executable and the app from the repository root.

## Contents

- 01. Purpose and how to read this guide
- 02. Baseline and toolchain
- 03. Project layout
- 04. Naming
- 05. Formatting and linting
- 06. Types and values
- 07. Functions, lambdas and control flow
- 08. Structs, classes and templates
- 09. Memory and ownership
- 10. Errors and exceptions
- 11. Modules, namespaces and the preprocessor
- 12. Annotations and data layout
- 13. Embedding: engine, module and context lifecycle
- 14. Native functions and addons
- 15. Threading and contexts
- 16. Safety: permissions, budgets and containment
- 17. Performance
- 18. Perception: scope, script structure and lifecycle
- 19. Perception: process access and permissions
- 20. Perception: rendering and overlays
- 21. Perception: API conventions and tooling
- 22. Testing
- 23. Git, releases and review
- A. Appendix

## 01. Purpose and how to read this guide

[Enma](https://enma.studio/docs/enma) is an embeddable, ahead-of-time compiled language with C++ semantics and script-grade containment: whole modules compile to native x64, with no bytecode and no interpreter, and scripts can reach only what the host registers. This guide covers both sides of an Enma project:

- **Script authors** writing `.em` modules.
- **Host authors** embedding the Enma SDK in a C++ application, registering natives and addons, and running scripts.

Enma is deliberately C++-faithful, so the [**C++ Style Guide**](https://style.chopper.dev/cpp) applies to Enma scripts wherever the language allows it, and in full to host code. This guide adds what is specific to Enma: its sized types, its ownership and escape rules, its module system, and the rules for embedding it safely. Examples use a fictional host, `Project`, whose prefix is `PRJ`. Sections 18–21 cover Perception, the host these scripts are primarily written for.

### Rule levels

| Level | Meaning |
| --- | --- |
| [MUST] / [MUST NOT] | Required. CI or review blocks the change. |
| [SHOULD] / [SHOULD NOT] | The default. Deviate only with a short comment explaining why. |
| [MAY] | Allowed when it helps; no justification needed. |
| [AVOID] | Legal but discouraged; expect a review question. |

### Principles

- **Write Enma, not C++.** Enma is C++-shaped but has its own spellings (`int64`, not `long`) and its own standard surface. Code that only compiles as C++ is a bug.
- **The host decides.** Scripts get exactly the natives, addons and permissions the host grants, and nothing else.
- **Deterministic ownership.** No garbage collector: every allocation has an owner and a scope.
- **Fail inside the script.** A script fault fails `execute()`; it never takes the host down.
- **Measure before tuning.** Enma is already native code; profile before reaching for annotations and intrinsics.

## 02. Baseline and toolchain

| Area | Standard |
| --- | --- |
| Language | Enma, tracking the newest C++ standard semantics (no pinned edition); pin the SDK release in the host repo |
| Platform | Windows x64 (the compiler emits x64 machine code) |
| Host compiler | MSVC `cl` or `clang-cl`, C++20 or newer (needed for `ENMA_SIG`) |
| SDK libraries | MSVC-ABI static libraries; one matching the host's CRT (`/MT` or `/MD`) |
| Host build | Premake5, per the [C++ guide](https://style.chopper.dev/cpp#build-system) |
| Scripts | `.em` source; `.emb` precompiled artifacts for shipping |
| Editor | Enma Studio or an editor wired to the Enma language server (diagnostics, completion, navigation) |

### Rules

- `ENMA-02.1` [MUST] link the SDK library that matches the host's CRT setting. Mixing `/MT` and `/MD` fails at link time; pick one for the whole host.
- `ENMA-02.2` [MUST] give every thread that calls `compile()` (or `compile_file`, `link`, `reload`) at least **2 MB** of stack. Raise the main thread's reserve with the linker's `/STACK` option and create compile threads with an explicit stack size.
- `ENMA-02.3` [MUST] compile only the addon source files the host registers; unused addons stay out of the build.
- `ENMA-02.4` [MUST] keep the SDK version pinned (vendored or by exact release) and upgrade it deliberately, reading the changelog, since the language tracks the newest C++ semantics.
- `ENMA-02.5` [SHOULD] turn on the language server in every editor used for `.em` files, and treat its diagnostics as build errors.
- `ENMA-02.6` [SHOULD] keep `set_optimize(e, true)` (the default) in every build; use `set_debug(e, true)` only in development hosts.

## 03. Project layout

```text
project/
  premake5.lua
  Project/                    # Host application (C++)
    src/Project/
      Scripting/
        ScriptEngine.cpp      # Owns the engine: config, addons, permissions
        ScriptEngine.test.cpp # Tests beside the code
        Natives/              # One file per native area: InputNatives.cpp
        Addons/               # Custom addons
  scripts/                    # Enma sources
    Lib/                      # Shared modules imported by others
      MathUtils.em
      MathUtils.test.em       # Script tests beside the script
    Gameplay/
      Spawner.em
    Main.em                   # Entry module: int64 main()
  build/emb/                  # Generated .emb artifacts (not committed)
  vendor/enma/                # Pinned SDK: headers, static libs, addon sources
```

### Rules

- `ENMA-03.1` [MUST] keep Enma sources under one `scripts/` root and register it with `add_module_path`, so imports resolve the same way in every build.
- `ENMA-03.2` [MUST] keep tests beside the code they test: `<name>.test.em` for scripts and `<File>.test.cpp` for host code.
- `ENMA-03.3` [MUST NOT] commit `.emb` artifacts; build them in CI from `.em` sources and ship them as release assets.
- `ENMA-03.4` [MUST] keep every native registration in the host's `Scripting/Natives/` folder, one file per area, so the full script-visible surface can be reviewed in one place.
- `ENMA-03.5` [SHOULD] keep one module per file and name the file after the namespace it provides (`MathUtils.em` → `MathUtils::`).
- `ENMA-03.6` [SHOULD] keep `Main.em` (or the host's named entry functions) thin: it wires modules together and holds no game or business logic.

## 04. Naming

Scripts use the [**C++ guide's naming**](https://style.chopper.dev/cpp#naming), so host and script code read the same. The Enma standard surface (`println`, `to_string`, `push_back`) stays snake_case because it is Enma's, not ours; the contrast shows at a glance which calls are your own.

| Thing | Convention | Example |
| --- | --- | --- |
| Module file | PascalCase `.em`, one module per file | `MathUtils.em`, `MathUtils.test.em` |
| Module namespace | PascalCase, comes from the file name | `MathUtils::Clamp()` |
| Struct / class / enum / alias | PascalCase noun | `SpawnPoint`, `enum class WaveState` |
| Enumerator | PascalCase | `WaveState::Running` |
| Function / method | PascalCase verb phrase | `SpawnWave()`, `GetHealth()` |
| Boolean query | `Is` / `Has` / `Can` | `IsAlive()`, `HasTarget()` |
| Local / parameter | camelCase | `waveSize`, `outPoints` |
| Data member | `m_` + PascalCase | `m_Health`, `m_NextId` |
| Plain-data struct field | PascalCase, no `m_` | `struct Hit { int64 Damage; };` |
| Static member / global | `s_` / `g_` + PascalCase (and rare, §9) | `s_Instance`, `g_Score` |
| Compile-time constant | PascalCase `constexpr` | `constexpr int64 MaxWaves = 10;` |
| Template parameter | `T` or `T` + PascalCase | `T`, `TItem` |
| Macro | Host prefix + UPPER_SNAKE | `PRJ_DEBUG` |
| Host-registered native | PascalCase, area first | `InputIsDown`, `AudioPlay` |
| Custom addon | PascalCase area | `Net`, `Telemetry` |
| Test function | `Test` + behaviour | `TestWaveSizeGrows()` |

### Rules

- `ENMA-04.1` [MUST NOT] name anything with a leading double underscore; `__` is reserved for Enma intrinsics (`__asm_rdtsc`, `__reflect_count`).
- `ENMA-04.2` [MUST NOT] shadow standard-surface names or builtins (`println`, `assert`, `time_ms`, `set_budget`).
- `ENMA-04.3` [MUST] start every native's name with its area (`Input`, `Audio`, `World`) and register each area from one host file, so a reader knows the call crosses into the host.
- `ENMA-04.4` [MUST] keep the module file name and its namespace identical; an `import` alias (`import "Lib/MathUtils.em" as Mu;`) is only for resolving a clash.

## 05. Formatting and linting

- `ENMA-05.1` [MUST] format `.em` files with `clang-format` using the same `.clang-format` as the host (2-space indent, 100 columns, attached braces); Enma's syntax is close enough to C++ that the formatter handles it. Exclude files that use `match` expressions if the formatter mangles them, and format those by hand to the same style.
- `ENMA-05.2` [MUST] treat every compiler and language-server diagnostic as an error. A script that compiles with warnings does not merge.
- `ENMA-05.3` [MUST] run a compile of every `.em` file in CI, through the same host configuration (addons, permissions, defines) that ships.
- `ENMA-05.4` [MUST] run the review checklist from Enma's own guidance on every change (Appendix C): no `short` / `long` / `unsigned`, no standard-header `#include`, no `->` on values, only `std::` names the STD Library page lists, every `new` paired with a `delete`.
- `ENMA-05.5` [SHOULD] brace every `if`, `for` and `while` body, even one-liners.
- `ENMA-05.6` [SHOULD] keep one declaration per line; Enma allows `int64 x = 1, y, z = 3;` but it hides the uninitialised `y`.
- `ENMA-05.7` [SHOULD] order a module: imports, `#include`s, `using` aliases, constants, types, then functions, with `main` last in an entry module.

## 06. Types and values

### Sized types

- `ENMA-06.1` [MUST] use Enma's sized types: `int8`–`int64`, `uint8`–`uint64`, `float32`, `float64`, `bool`, `char`, `wchar`. [MUST NOT] write `short`, `long`, `unsigned` or `signed`; they are not type names.
- `ENMA-06.2` [SHOULD] use `int64` for counts, sizes, IDs and anything returned to the host; use narrower types only for storage that is packed or sent somewhere.
- `ENMA-06.3` [AVOID] the aliases `int`, `float` and `double` in new code. They are legal (`int32`, `float32`, `float64`), but writing the width removes any doubt about what size a value is. Use the `<cstdint>` spellings (`int32_t`, `size_t`) only in code shared with C++.
- `ENMA-06.4` [MUST] remember unsuffixed literals: integers are `int32`, `1.5` is `float64`, `1.5f` is `float32`. Suffix wide constants (`18446744073709551615ull`).

### Conversions

Enma converts more freely than C++: signed/unsigned conversions wrap, `float` to `int` truncates, and `int64` to `int32` wraps at 32 bits, all implicitly.

- `ENMA-06.5` [MUST] make every narrowing or sign-changing conversion explicit with `static_cast`, even where Enma would accept it silently. The cast is the reviewer's signal that the wrap is intended.
- `ENMA-06.6` [MUST] use brace initialisation for new variables (`int32 x{42};`). Braces reject narrowing (`uint8 u{-1};` is a compile error), which catches the silent wraps above.
- `ENMA-06.7` [MUST] use `enum class` for new enums; convert to integers only with `static_cast`.

### Strings, optionals and atomics

- `ENMA-06.8` [MUST] use `std::string` / `std::wstring` for owned text; there is no bare `string`. `const char*` is only for literals and native signatures.
- `ENMA-06.9` [MUST] build output text before printing: `println` takes one `std::string` or `const char*`, so use `std::format` or `std::to_string`.
- `ENMA-06.10` [SHOULD] use raw strings for paths and patterns: `R"(C:\dir\file)"`.
- `ENMA-06.11` [SHOULD] return `std::optional<T>` for "maybe a value" instead of sentinel values like `-1`.
- `ENMA-06.12` [MUST] use `aint8`–`aint64` for integer globals touched by more than one context (§15); compound operations on them are atomic.

```enma
using EntityId = int64;

enum class WaveState { Idle, Running, Done };

std::optional<EntityId> FindTarget(const std::vector<EntityId>& ids, EntityId wanted) {
  for (const EntityId& id : ids) {
    if (id == wanted) {
      return id;
    }
  }
  return {};
}

int64 main() {
  int32 waves{3};
  int64 total = static_cast<int64>(waves) * 1000;
  println(std::format("total {}", total));
  return 0;
}
```

## 07. Functions, lambdas and control flow

### Functions

- `ENMA-07.1` [MUST] declare the entry point as `int64 main()` (or `int32 main()`): no parameters, not `static`.
- `ENMA-07.2` [SHOULD] keep functions short (about 40 lines) with at most four parameters; group more into a struct.
- `ENMA-07.3` [MUST] pass large structs and containers by `const&`; Enma structs are value types and copy on pass-by-value.
- `ENMA-07.4` [MUST] keep deduced (`auto`) return types consistent across every `return`. When a function mixes widths, declare the return type instead of relying on deduction.
- `ENMA-07.5` [MUST NOT] declare overloads that differ only in return type.
- `ENMA-07.6` [MUST NOT] rely on argument evaluation order even though Enma fixes it left to right (unlike C++); a call like `Pair(Next(), Next())` reads as a bug to anyone who knows C++. Evaluate into named locals first.
- `ENMA-07.7` [SHOULD] use default parameters only for genuinely optional settings, and never refer to a later parameter.

### Lambdas

- `ENMA-07.8` [MUST] use `auto` or `delegate` to hold capturing lambdas; only non-capturing lambdas convert to function pointers (`+[]{ ... }`).
- `ENMA-07.9` [MUST NOT] return a lambda that captures a local by reference; the compiler rejects it, and the by-value case with a pointer to a local is not caught. Capture values, or own the data with `new`.
- `ENMA-07.10` [SHOULD] keep lambdas under about ten lines; name anything longer.

### Control flow

- `ENMA-07.11` [SHOULD] use `match` for value-to-value mappings, always with a `_` arm:

```enma
int32 PointsFor(int32 tier) {
  return match (tier) {
    1 => 10,
    2 => 25,
    3 => 50,
    _ => 0
  };
}
```

- `ENMA-07.12` [SHOULD] use range `for` with `const&` (`for (const auto& [name, score] : scores)`) instead of index loops when the index is not needed.
- `ENMA-07.13` [SHOULD] use `defer { ... }` right after acquiring a resource that has no destructor of its own; it runs at scope exit and during unwinding.
- `ENMA-07.14` [MUST NOT] use `goto` except to break out of nested loops, and never into a `try`, handler or `defer` body (the compiler refuses it).
- `ENMA-07.15` [MUST] return early instead of nesting; no `else` after `return`.

## 08. Structs, classes and templates

### Structs and classes

- `ENMA-08.1` [MUST] use `struct` for plain data with public PascalCase fields and no invariants, and `class` for types with private state (`m_` members) and methods that keep invariants. They differ only in default access, so the keyword is how you signal intent.
- `ENMA-08.2` [MUST] declare objects on the stack as `T x;` or `T x{...};`, and on the heap as `T* x = new T(...);`. `T x = new T();` is rejected; `T x();` declares a function.
- `ENMA-08.3` [MUST] use `.` on values and references and `->` only on pointers or types that declare `operator->()`; the wrong one is a compile error.
- `ENMA-08.4` [MUST] give every member a default initialiser or set it in the constructor's initialiser list; aggregates with excess initialisers are rejected.
- `ENMA-08.5` [SHOULD] keep inheritance single and shallow. Use `virtual` only when you need runtime dispatch, mark overrides with `override`, and give polymorphic bases a `virtual` destructor.
- `ENMA-08.6` [AVOID] multiple and virtual inheritance; Enma supports them, but a non-virtual diamond silently creates two base subobjects.
- `ENMA-08.7` [MUST] convert class types at the call site; Enma does not apply class-to-class user conversions to function arguments.
- `ENMA-08.8` [MUST NOT] make const data members in classes that need copy assignment; Enma removes copy assignment from such classes.

```enma
class Spawner {
public:
  explicit Spawner(int64 maxAlive) : m_MaxAlive(maxAlive) {}

  bool CanSpawn() const { return m_Alive < m_MaxAlive; }

  void OnSpawned() { m_Alive += 1; }

private:
  int64 m_MaxAlive = 0;
  int64 m_Alive = 0;
};
```

### Templates

- `ENMA-08.9` [SHOULD] use templates for genuinely generic code (containers, math over numeric types) and constrain them with concepts.
- `ENMA-08.10` [MUST] write `typename` before a dependent type name inside a template (`typename T::Type`).
- `ENMA-08.11` [MUST] remember that two instantiations of one template are different types: a value crossing a parameter, return or `new` boundary must match exactly.
- `ENMA-08.12` [AVOID] deep template metaprogramming; Enma caps instantiations at 16,384 per compile and nesting at 1,024, and every instantiation is monomorphised into machine code.
- `ENMA-08.13` [SHOULD] prefer `constexpr` functions and `if constexpr` over recursive template tricks for compile-time work.

## 09. Memory and ownership

Enma has no garbage collector. Stack objects, `std` containers and class members are destroyed deterministically at scope exit, including during exception unwinding.

- `ENMA-09.1` [MUST] prefer stack values and `std` containers. Reach for `new` only when an object must outlive its scope or be shared by address.
- `ENMA-09.2` [MUST] pair every `new` with exactly one `delete` and every `new T[N]` with `delete[]`, and make the owner obvious: one struct or function owns each heap object and deletes it in its destructor or with `defer`.
- `ENMA-09.3` [SHOULD] put `defer { delete p; }` on the line after a `new` whose object never leaves the function.
- `ENMA-09.4` [MUST NOT] return, store in a global or field, or capture by reference the address of a local. The compiler rejects the obvious cases; its escape analysis is conservative, so do not lean on it for the rest.
- `ENMA-09.5` [SHOULD] mark functions that must never leak allocations with `[[noescape]]`; the compiler then rejects any allocation that outlives the call.
- `ENMA-09.6` [MUST] index with `.at(i)` when the index comes from input or computation that could be wrong. `v[i]`, `a[i]` and `p[i]` are **not** bounds-checked; a near miss is undefined behaviour.
- `ENMA-09.7` [MUST] treat a pointer from a native as borrowed unless the native is documented as transferring ownership, and never `delete` it.
- `ENMA-09.8` [AVOID] mutable globals. They are shared by every context of a module (§15); keep state in structs passed by reference, or in context userdata set by the host.
- `ENMA-09.9` [SHOULD] check `heap_count()` in tests before and after a scenario to catch leaks.

```enma
int64 SumWave(const std::vector<int64>& damage) {
  int64* scratch = new int64[damage.size()];
  defer { delete[] scratch; };

  int64 total = 0;
  for (int64 i = 0; i < damage.size(); i++) {
    scratch[i] = damage.at(i) * 2;
    total += scratch[i];
  }
  return total;
}
```

## 10. Errors and exceptions

### In scripts

- `ENMA-10.1` [MUST] throw exceptions for failures the caller cannot reasonably ignore, and return `std::optional<T>` (or a `bool` plus out-parameter) for expected misses such as "not found".
- `ENMA-10.2` [MUST] throw types derived from `std::runtime_error` with a message that names what failed and the value involved.
- `ENMA-10.3` [MUST] catch by reference (`catch (const std::runtime_error& e)`), most specific first, with `catch (...)` last; Enma rejects misordered handlers.
- `ENMA-10.4` [MUST] catch only where you can recover or add context; otherwise let the exception reach the host, where `execute()` reports it.
- `ENMA-10.5` [MUST NOT] use exceptions for control flow in per-frame code.
- `ENMA-10.6` [MUST] treat null dereference and division by zero as bugs, even though they are catchable checked faults. Check first; do not write code that catches them on purpose.
- `ENMA-10.7` [MUST] remember that stack overflow, wild out-of-bounds writes and use-after-free that hits unmapped memory are **not** catchable: they end the run without unwinding.

### In hosts

- `ENMA-10.8` [MUST] check the result of every SDK call: `compile()` and `deserialize()` return `nullptr`, `execute()` and `call()` return `false` on failure.
- `ENMA-10.9` [MUST] report compile failures with `last_error()` — code, message, file, line and column — so the script author sees where the problem is.
- `ENMA-10.10` [MUST] keep the host running when a script fails: log the error, mark the script as failed, and carry on.
- `ENMA-10.11` [MUST] report faults from natives with `runtime_error(message)` (or `runtime_exception`) rather than C++ exceptions, and keep every native `noexcept` at its boundary.
- `ENMA-10.12` [MUST] call `mark_native_raises(e, name, false)` only for natives that genuinely can never raise; the per-call exception check is cheap insurance.

```cpp
enma::module_t* mod = enma::compile(m_Engine, source.data(), source.size(), "Spawner.em");
if (mod == nullptr) {
  const auto& err = enma::last_error(m_Engine);
  PRJ_LOG_ERROR("{}:{}:{}: {}", err.file, err.line, err.column, err.message);
  return std::unexpected(ScriptError::CompileFailed);
}
```

## 11. Modules, namespaces and the preprocessor

### Imports

- `ENMA-11.1` [MUST] share code between files with `import`, not `#include`. Imported declarations keep their exact types and are reached through the module's namespace (`MathUtils::Clamp`).
- `ENMA-11.2` [MUST] import by module name (`import MathUtils`) when the module is on a host-registered module path, and by quoted relative path (`import "Lib/MathUtils.em";`) only for files that are not.
- `ENMA-11.3` [SHOULD] alias an import (`as Mu`) only to resolve a name clash or to shorten a deep path; never alias the same file twice.
- `ENMA-11.4` [MUST NOT] `#include` standard headers; the standard surface is always available. `#include` is only for sharing macros between your own files.
- `ENMA-11.5` [MUST] keep a module's private helpers `static` or in an anonymous namespace so they do not leak to importers.

### Namespaces

- `ENMA-11.6` [MUST] keep each module's public declarations inside the namespace its file name gives it; do not add extra top-level namespaces in a module.
- `ENMA-11.7` [SHOULD] use `using namespace` only inside function bodies, and namespace aliases (`namespace Rd = Engine::Render::Detail;`) for long paths. A namespace alias cannot point at an imported module.

### Preprocessor

- `ENMA-11.8` [AVOID] macros in scripts. Use `constexpr` constants, `if constexpr` and functions instead.
- `ENMA-11.9` [MAY] use `#ifdef` on host-supplied defines (`define(e, "PRJ_DEBUG", "1")`) to compile debug-only checks.
- `ENMA-11.10` [MUST] prefix any macro with the host prefix (`PRJ_`), and keep macros in one shared include file.

### Precompiled modules

- `ENMA-11.11` [MUST] ship scripts as `.emb` artifacts built in CI with `serialize()`, and load them with `deserialize()`, checking for `nullptr`.
- `ENMA-11.12` [SHOULD] build `.emb` files with `keep_debug = true` for development and internal builds, and `false` only for public releases where the source must not be recoverable.
- `ENMA-11.13` [MUST] rebuild every `.emb` when the SDK version changes.

## 12. Annotations and data layout

Enma accepts a closed set of annotations, each only in its own position; anything else is a compile error.

| Annotation | On | Use it when |
| --- | --- | --- |
| `[[packed]]` | struct | Matching a wire or file format byte for byte |
| `[[align(N)]]` | struct, member | Data handed to SIMD code or hardware that needs alignment |
| `[[offset(N)]]` | member | Mirroring a native struct layout exactly |
| `[[reflect]]` | struct | Tools, editors or serializers that enumerate fields |
| `[[serialize]]` | struct | Generating `to_bytes` / `from_bytes` for flat records |
| `[[no_vtable]]` | struct | Rare; dropping the dispatch table from a type with virtuals |
| `[[inline]]` / `[[noinline]]` | function | A profile shows the call matters |
| `[[noopt]]` | function | Debugging only; never committed |
| `[[noescape]]` | function | Guaranteeing a function leaks no allocation |
| `[[dll(...)]]` | `extern` function | Binding a DLL export; needs `PERM_FFI` |

- `ENMA-12.1` [MUST] use layout annotations (`[[packed]]`, `[[align]]`, `[[offset]]`) only for types that cross a boundary (files, network, natives), with a comment naming the format they match.
- `ENMA-12.2` [MUST NOT] commit `[[noopt]]`.
- `ENMA-12.3` [SHOULD] add `[[reflect]]` to structs that host tools or editors inspect, instead of hand-written field tables.
- `ENMA-12.4` [MUST] keep `[[serialize]]` structs flat: no bit-fields, inline arrays or nested structs, and no pointers (their addresses would be written out).
- `ENMA-12.5` [MUST NOT] use `[[dll(...)]]` in gameplay or user scripts. FFI belongs in host natives, where it can be reviewed; scripts that need it are compiled only by engines granted `PERM_FFI`.
- `ENMA-12.6` [MUST] remember that the standard attributes (`[[nodiscard]]`, `[[likely]]`, `[[deprecated]]` and others) are parsed and **ignored**; do not rely on them to enforce anything.

```enma
// Matches the 6-byte packet header sent by the host's net layer.
[[packed]] struct PacketHeader {
  uint8 Type;
  uint8 Flags;
  int32 Length;
};
```

## 13. Embedding: engine, module and context lifecycle

| Object | Created by | Owns | Lifetime |
| --- | --- | --- | --- |
| **Engine** (**`engine_t`**) | `enma::create()` | Configuration, registered natives and addons, permissions, compile state | The host's scripting subsystem |
| **Module** (**`module_t`**) | `compile`, `compile_file`, `deserialize`, `link` | Compiled code, script globals, instruction budget, debug hook, breakpoints | Until reloaded or destroyed |
| **Context** | `create_context(mod)` | Heap, stack, RNG, in-flight exception, 16 userdata slots | One per thread that runs the module |

### Rules

- `ENMA-13.1` [MUST] wrap the engine, each module and each context in an RAII owner in the host (`ScriptEngine`, `ScriptModule`, `ScriptContext`) that releases in reverse order: contexts, then modules, then the engine.
- `ENMA-13.2` [MUST] configure the engine completely — optimisation, debug, defines, include and module paths, resolvers, permissions, addons, natives — **before** the first compile. Configuration after compiling is a bug.
- `ENMA-13.3` [MUST] destroy every module and context before `destroy(engine)`; the engine does not track its children.
- `ENMA-13.4` [MUST] call `enma::shutdown()` once when the scripting subsystem is torn down; in a DLL that may unload, call it from `DLL_PROCESS_DETACH` and run no script code afterwards.
- `ENMA-13.5` [SHOULD] load scripts through `set_import_resolver` / `set_include_resolver` backed by the host's virtual file system, so packaged builds and development builds resolve the same way.
- `ENMA-13.6` [MUST] run entry points by name with `execute()` or `call()`, and read results with the matching `return_value`, `return_string` or `return_float`.
- `ENMA-13.7` [SHOULD] use `reload` for hot reload in development builds only, and drop every cached pointer into the old module (function addresses, annotation info, strings) after a reload.

```cpp
namespace Project {

std::expected<void, ScriptError> ScriptEngine::Init() {
  m_Engine = enma::create();
  enma::set_optimize(m_Engine, true);
  enma::set_debug(m_Engine, PRJ_DEBUG_BUILD);
  enma::set_permissions(m_Engine, 0);                       // nothing extra by default
  enma::register_addon_core(m_Engine);                      // only the addons scripts use
  enma::register_addon_std(m_Engine);
  enma::add_module_path(m_Engine, "scripts");
  RegisterInputNatives(m_Engine);
  RegisterAudioNatives(m_Engine);
  return {};
}

ScriptEngine::~ScriptEngine() {
  m_Modules.clear();                                         // destroys contexts, then modules
  if (m_Engine != nullptr) {
    enma::destroy(m_Engine);
  }
}

}  // namespace Project
```

## 14. Native functions and addons

Natives are the script-visible API of the host. Review them like a public API: each one is a door out of the sandbox.

### Registering natives

- `ENMA-14.1` [MUST] register natives with `enma::register_typed<&Fn>(e, signature)` where possible, and wrap every signature in `ENMA_SIG("...")` so a malformed signature fails the host build instead of logging at run time.
- `ENMA-14.2` [MUST] use Enma's sized types in signatures (`int64`, `float64`, `const char*`) and keep them to plain values, pointers and references; signatures with `struct`, `class`, lambdas or varargs are refused.
- `ENMA-14.3` [MUST] keep every native function alive for as long as any module that calls it exists; the engine does not own `fn_ptr`.
- `ENMA-14.4` [MUST] validate every argument inside the native: natives are not protected by Enma's checks. Use `heap_is_tracked(ptr)` before trusting a pointer that claims to be script heap memory.
- `ENMA-14.5` [MUST] declare ownership: `mark_native_returns_borrow` for handles the host keeps, `mark_native_deallocates` for natives that free a parameter. Undeclared ownership is a leak or a double free waiting to happen.
- `ENMA-14.6` [MUST] gate natives that touch files, the network, processes or other unsafe areas with a permission flag at registration (`PERM_FILE`, `PERM_FFI`, or a host-defined bit), so scripts compiled without the grant fail to compile.
- `ENMA-14.7` [SHOULD] keep natives coarse: one call that does a whole job (`WorldSpawnWave(count)`) beats ten fine-grained calls per frame.

```cpp
namespace Project::Natives {

static bool InputIsDown(int64_t key) noexcept {
  if (key < 0 || key >= Input::KeyCount) {
    enma::runtime_error("InputIsDown: key out of range");
    return false;
  }
  return Input::IsDown(static_cast<Key>(key));
}

void RegisterInputNatives(enma::engine_t* e) {
  enma::register_typed<&InputIsDown>(e, ENMA_SIG("bool InputIsDown(int64 key)"));
}

}  // namespace Project::Natives
```

### Addons

- `ENMA-14.8` [MUST] register only the addons a product needs (`register_addon_core`, `register_addon_std`, ...) instead of `register_all_addons` in shipping hosts, and disable the filesystem addon unless scripts truly need it.
- `ENMA-14.9` [MUST] build host-specific capabilities (networking, telemetry, game systems) as custom addons with their own namespace, not as loose natives, when they have more than a handful of functions.
- `ENMA-14.10` [MUST] document every addon's functions, permission and threading rules in its header and on the docs site.
- `ENMA-14.11` [MUST NOT] expose anything from an addon that lets a script register further natives or change permissions.

## 15. Threading and contexts

- `ENMA-15.1` [MUST] compile on one thread per engine at a time. Concurrent `compile`, `link`, `reload` or `deserialize` calls on one engine are refused; use one engine per compiling thread or serialise compiles.
- `ENMA-15.2` [MUST] give every thread that runs a module its own context from `create_context(mod)`, created before the thread starts and destroyed after it is joined.
- `ENMA-15.3` [MUST NOT] share a context between threads at the same time; a second thread entering a busy context is refused. Hand a context to another thread only after the first has finished and been joined.
- `ENMA-15.4` [MUST] treat script globals as shared by every context of a module. Guard them with `aint*` types or a `mutex` + `lock_guard` from the Thread addon, or write them from one thread only.
- `ENMA-15.5` [MUST] open an `execution_scope` on host threads that call into script memory outside a run (allocating on the script heap, invoking a script function pointer, raising an exception).
- `ENMA-15.6` [SHOULD] give workers that need their own budget, breakpoints or globals their own module; budgets and debug state are per module, not per context.
- `ENMA-15.7` [MUST NOT] use script threads (the Thread addon) for work the host can schedule; prefer host-side job systems that call into contexts.
- `ENMA-15.8` [MUST] remember that async/await, futures and coroutines do not exist in Enma; long work is split across frames or moved to a worker context.

```cpp
// One module, one context per worker.
std::vector<enma::context_t*> contexts;
for (int32_t i = 0; i < workerCount; ++i) {
  contexts.push_back(enma::create_context(mod));
}
// ... start workers, each calling enma::call(contexts[i], ...) ...
// ... join workers ...
for (enma::context_t* ctx : contexts) {
  enma::destroy_context(mod, ctx);
}
```

## 16. Safety: permissions, budgets and containment

Enma's containment comes from the host: scripts reach only what is registered, permission flags gate dangerous features at compile time, and budgets cap what a script can consume.

### Permissions

| Flag | Gates | Default in `PROJECT` |
| --- | --- | --- |
| **`PERM_FFI`** (`0x01`) | `[[dll(...)]]` externs and natives registered with it | Off everywhere; on only for trusted tooling hosts |
| **`PERM_FILE`** (`0x02`) | All Filesystem addon operations | Off for user or untrusted scripts; on for first-party tools |
| **Host-defined bits** | Natives the host gates itself | Documented beside each native |

- `ENMA-16.1` [MUST] start every engine with `set_permissions(e, 0)` and grant flags explicitly, per engine, for the scripts that engine compiles.
- `ENMA-16.2` [MUST] compile untrusted scripts (user content, mods, downloaded code) on a separate engine with no permissions, no filesystem addon and only the natives they are meant to have.
- `ENMA-16.3` [MUST] remember that permissions check what a module binds, not what its machine code does: never load `.emb` files from untrusted sources without checking their origin, since they are native code.

### Budgets

- `ENMA-16.4` [MUST] set an instruction budget (`set_budget`) and a heap budget (`set_memory_budget`) on every module that runs untrusted or user-editable scripts, and treat exceeding them as a failed run.
- `ENMA-16.5` [SHOULD] set budgets from the host, not from the script; a script can call `set_budget` itself, so untrusted scripts must not be able to raise their own limits (do not rely on scripts calling it).
- `ENMA-16.6` [SHOULD] size budgets from measurements of real content plus headroom, and log the measured use in development builds.

### Containment checklist

- Natives validate every argument and never trust script pointers without `heap_is_tracked`.
- No native lets a script register code, change permissions or reach the host's allocator directly.
- Every script run has a timeout path: budgets for untrusted code, a watchdog for long-running trusted code.
- A failed `execute()` disables that script and leaves the host running.

## 17. Performance

Enma compiles whole modules to native x64, so script code runs at C++-like speed. Most slowness comes from crossing the host boundary or from allocation.

- `ENMA-17.1` [MUST] measure before optimising: time with `time_ms()` or `__asm_rdtsc()` in scripts, and the host profiler around `execute()` / `call()`.
- `ENMA-17.2` [SHOULD] compile modules once and cache them (or ship `.emb` files); `compile()` is far more expensive than running.
- `ENMA-17.3` [SHOULD] create contexts once per worker and reuse them, rather than creating one per call.
- `ENMA-17.4` [SHOULD] keep per-frame script code free of heap allocation: reuse vectors (`clear()` keeps capacity), pass by `const&`, and avoid building strings unless they are printed.
- `ENMA-17.5` [SHOULD] batch native calls: one call that processes an array is cheaper than one call per element.
- `ENMA-17.6` [MAY] use the SIMD and Math:3D addons, `[[align(16)]]` data and `[[inline]]` on hot paths, after a profile shows the need.
- `ENMA-17.7` [SHOULD] use `hold_compile_caches(true)` around a batch of compiles (for example, loading a level's scripts), paired with exactly one `hold_compile_caches(false)`.
- `ENMA-17.8` [AVOID] deep template instantiation in hot modules; every instantiation is separate machine code, which grows the module and compile time.

## 18. Perception: scope, script structure and lifecycle

Perception is the host these scripts run in: it loads Enma scripts, gives them a process API, a render API and the default Enma addons, and runs their routines every frame. Sections 18–21 apply to Perception scripts; everything before them still applies.

### Scope

- `ENMA-18.1` [MUST] use Perception scripts only with single-player, offline games and your own software. [MUST NOT] attach to games with online play, shared leaderboards or anti-cheat, or to any process you do not have the right to modify.
- `ENMA-18.2` [MUST] check the target at startup (process name and module) and unload if it is not the expected single-player title.

### Lifecycle

| Stage | Function | Rules |
| --- | --- | --- |
| **Load** | `int64 main()` | Attach to the process, create fonts and resources, register routines. Return `1` to stay loaded, `<= 0` to unload |
| **Every frame** | Routines: `void Callback(int64 data)` | Read state, draw, return promptly |
| **Unload** | `void unload()` (optional) | Runs after every routine has stopped; release what `main` set up and restore anything you changed |

- `ENMA-18.3` [MUST] do one-time work (attaching, pattern scans, font creation, shader and buffer creation) in `main()`, never in a routine.
- `ENMA-18.4` [MUST] return `0` from `main()` with a logged reason when setup fails (process not found, pattern not found), instead of leaving routines running against bad state.
- `ENMA-18.5` [MUST] keep each routine short and non-blocking; split slow work across frames.
- `ENMA-18.6` [MUST] treat routines as concurrent: they may run at the same time and share globals, so shared mutable state is atomic (`aint64`) or behind a `mutex`.
- `ENMA-18.7` [MUST] restore every value a script wrote to the target in `unload()`, so unloading leaves the game as it was.
- `ENMA-18.8` [SHOULD] keep each routine's handle and unregister it when its feature is turned off, rather than branching on a flag every frame.

```enma
std::optional<proc_t> g_Game;
int64 g_HudRoutine = -1;
int64 g_Font = 0;

void DrawHud(int64 data) {
  using namespace render;
  if (!g_Game || !g_Game->alive()) {
    return;
  }
  draw_text("trainer active", vec2(40.0f, 40.0f), color(255, 255, 255, 255), g_Font, 1, 1.0f);
}

int64 main() {
  using namespace render;
  g_Game = ref_process("game.exe");
  if (!g_Game) {
    println("game.exe not running");
    return 0;
  }
  g_Font = create_font("Inter", 20);
  if (g_Font == 0) {
    println(std::format("create_font failed: {}", get_last_render_error()));
    return 0;
  }
  g_HudRoutine = register_routine(reinterpret_cast<int64>(DrawHud), 0);
  return g_HudRoutine == -1 ? 0 : 1;
}

void unload() {
  g_Game.reset();
}
```

Check each call's exact signature against the Perception API pages for your version; the shape above is the pattern to follow.

## 19. Perception: process access and permissions

`proc_t` is a move-only reference to a process that releases itself when it leaves scope. Reads are always available; writes and heavier operations are gated by permissions.

| Permission | Gates | Default for single-player scripts |
| --- | --- | --- |
| **(none)** | Attaching, reading memory, modules, exports, pattern and value scans, memory regions | Allowed |
| **`write_memory`** | `w*` writes, `wvm` | Only for scripts whose purpose is to change values (trainers), and only those values |
| **`virtual_memory_operations`** | `alloc_vm`, `free_vm` in the target | Off; single-player mods rarely need it |
| **`kernel_rw_access`** | The `kernel` namespace, physical memory, DTB overrides | **Off.** Single-player games do not need kernel access |

### Rules

- `ENMA-19.1` [MUST] request only the permissions a script uses, and state why at the top of the script in a comment.
- `ENMA-19.2` [MUST NOT] use `kernel_rw_access`, DTB overrides or physical-memory reads and writes. If a target only works through them, it has protections you should not be working around.
- `ENMA-19.3` [MUST] check `alive()` before using a stored `proc_t` in a routine; the game may have closed.
- `ENMA-19.4` [MUST] check every pointer read from the target with `is_valid_address` before following it, and treat a zero or invalid pointer as "not ready", not as an error to retry every frame.
- `ENMA-19.5` [MUST] locate code and data with `find_code_pattern` (byte signatures with `??` wildcards) and module-relative offsets, never with absolute addresses.
- `ENMA-19.6` [MUST] keep signatures and offsets in one table at the top of the script (or a shared `Offsets.em` module), each with the game version it was verified on, and fail closed in `main()` when any of them is not found.
- `ENMA-19.7` [SHOULD] read structs in one bulk call (`rvm`) instead of many single reads, and cache values that do not change every frame.
- `ENMA-19.8` [MUST] write the smallest change possible, remember the original value, and restore it in `unload()` and when the feature is turned off.

```enma
// Offsets.em: verified on game.exe 1.4.2
namespace Offsets {
constexpr const char* PlayerManager = "48 8B 05 ?? ?? ?? ?? 48 85 C0 74 ?? 8B 40 10";
constexpr int64 Health = 0x10;
constexpr int64 Ammo = 0x24;
}
```

## 20. Perception: rendering and overlays

The render API (namespace `render`) records draw calls during a routine and executes them at the end of the frame.

- `ENMA-20.1` [MUST] create fonts, bitmaps, shaders and buffers once in `main()` and reuse them. Load each font at the size it is drawn; fonts and bitmaps are cached for the whole process and never freed.
- `ENMA-20.2` [MUST] check every `create_*` / `load_*` handle: `0` means failure. Read `get_last_render_error()` and fail setup with its message.
- `ENMA-20.3` [MUST] use `color(...)` for RGBA values and `vec2(...)` for positions and sizes; keep shared colours as named constants (`Colors::Text`, `Colors::Warning`).
- `ENMA-20.4` [SHOULD] batch similar shapes with the batch forms (`draw_rects`, `draw_lines`) instead of one call per item.
- `ENMA-20.5` [SHOULD] upload static geometry once to resident buffers and draw it with `custom_draw_buffer*`; use dynamic buffers only for data that changes every frame.
- `ENMA-20.6` [MUST] set pipeline state (viewport, blend, targets) right before each custom draw, and end every custom sequence with `custom_restore_state()`; state does not carry over between draws or routines.
- `ENMA-20.7` [SHOULD] keep overlays readable and out of the way: one corner by default, outlined or shadowed text (`effect` 1 or 2), and a toggle to hide everything.
- `ENMA-20.8` [SHOULD] measure overlay cost with `get_render_thread_frame_ms()` and GPU timers, and keep a script's drawing well under a millisecond per frame.
- `ENMA-20.9` [MAY] build settings panels with the GUI API rather than hand-drawn widgets, so every script's controls look and behave the same.

## 21. Perception: API conventions and tooling

Perception's own conventions, which every script follows:

- `ENMA-21.1` [MUST] use `static_cast<T>(x)` for numeric conversions and `reinterpret_cast<int64>(fn)` to pass a function as a routine or callback handle.
- `ENMA-21.2` [MUST] suffix `float32` literals with `f` (`0.2f`, `40.0f`); a bare `0.2` is `float64`.
- `ENMA-21.3` [MUST] treat values from `create_*` and `load_*` as opaque handles and pass them only to the matching API.
- `ENMA-21.4` [MUST] use `std::string` for owned text and `const char*` for read-only parameters; convert numbers with `std::to_string` or `std::format`.
- `ENMA-21.5` [MUST] use `std::vector<T>` for dynamic storage and `std::array<T, N>` for fixed-size storage.
- `ENMA-21.6` [MUST] use `print_console` for chatty debug output so the main log stays readable, and `println` for lifecycle messages.

### Tooling

- `ENMA-21.7` [MUST] edit scripts with the Perception language server enabled (diagnostics, hover, completion, go-to-definition) and fix every diagnostic before loading a script.
- `ENMA-21.8` [MAY] use the Perception MCP interface to let an AI agent load, run and inspect scripts locally; review any agent-written script against this guide before running it against a game.
- `ENMA-21.9` [SHOULD] keep each script in its own folder with a short `README.md`: the target game and version, the permissions it requests and why, and how to turn each feature off.

## 22. Testing

### Script tests

- `ENMA-22.1` [MUST] keep tests beside the script as `<Name>.test.em`, importing the module under test.
- `ENMA-22.2` [MUST] write each test as an `int64 Test<Behaviour>()` function that returns `0` on success, using the `assert(cond, msg)` builtin for checks. The host's test runner finds and calls every `Test*` function.
- `ENMA-22.3` [MUST] check for leaks: record `heap_count()` before and after each test and fail if it changed.
- `ENMA-22.4` [MUST] test error paths too: that the right exception is thrown, and that `.at()` throws on a bad index.
- `ENMA-22.5` [SHOULD] run tests on an engine configured like production (same addons, permissions and defines) plus a tighter budget, so runaway loops fail fast.

```enma
import "MathUtils.em";

int64 TestClampKeepsValueInRange() {
  int64 before = heap_count();
  assert(MathUtils::Clamp(15, 0, 10) == 10, "clamps above max");
  assert(MathUtils::Clamp(-3, 0, 10) == 0, "clamps below min");
  assert(MathUtils::Clamp(4, 0, 10) == 4, "keeps values in range");
  assert(heap_count() == before, "no leaks");
  return 0;
}
```

### Host tests

- `ENMA-22.6` [MUST] test every native with good, boundary and bad arguments, from a script, and check that bad arguments raise instead of crashing.
- `ENMA-22.7` [MUST] test that a script without a permission fails to compile when it calls a gated native.
- `ENMA-22.8` [MUST] test budgets: an infinite loop and a runaway allocation each fail `execute()` while the host keeps running.
- `ENMA-22.9` [SHOULD] run host and script tests under the same CI job on Windows x64, with ASan builds of the host where the SDK allows it.
- `ENMA-22.10` [SHOULD] compile every `.em` file and round-trip it through `serialize` / `deserialize` in CI to catch artifact problems before release.

## 23. Git, releases and review

- `ENMA-23.1` [MUST] follow **Conventional Commits**: `type(scope): summary`, imperative, lower case, no trailing period, under 72 characters. Use the module or host area as scope: `feat(spawner): add wave cooldown`, `fix(natives): validate key range`.
- `ENMA-23.2` [MUST] mark breaking changes to natives, addons or module APIs with `!` and a `BREAKING CHANGE:` footer.
- `ENMA-23.3` [MUST] keep commits small and focused, each compiling every script and passing tests.
- `ENMA-23.4` [MUST] record the SDK version in the host's release notes, and rebuild every `.emb` artifact for each release.

### Review checklist: scripts

- Sized types only; no `short`, `long`, `unsigned`, or standard-header `#include`.
- Narrowing and sign changes are explicit casts; new variables use braces.
- `.` on values, `->` only on pointers; only `std::` names the STD Library page lists.
- Every `new` has an owner and a `delete`; no address of a local escapes.
- Untrusted indexes use `.at()`; globals touched by several contexts are atomic or locked.

### Review checklist: hosts

- Every native validates its arguments, declares ownership, and is gated if it touches files, network or processes.
- Signatures use `ENMA_SIG`; natives are `noexcept` and report faults with `runtime_error`.
- Engines are fully configured before compiling; contexts and modules are destroyed before engines.
- Untrusted scripts run on a separate, permissionless engine with budgets set by the host.

## Appendix

### A. Minimal runnable script

```enma
// Main.em
int32 Fib(int32 n) {
  if (n <= 1) {
    return n;
  }
  return Fib(n - 1) + Fib(n - 2);
}

int64 main() {
  println(std::to_string(Fib(30)));
  return 0;
}
```

### B. Host skeleton

```cpp
int main() {
  enma::engine_t* engine = enma::create();
  enma::set_permissions(engine, 0);
  enma::register_addon_core(engine);
  enma::register_addon_std(engine);

  const std::string source = Project::ReadFile("scripts/Main.em");
  enma::module_t* mod = enma::compile(engine, source.data(), source.size(), "Main.em");
  if (mod == nullptr) {
    std::println(stderr, "{}", enma::last_error_message(engine));
    enma::destroy(engine);
    return 1;
  }

  enma::context_t* ctx = enma::create_context(mod);
  const bool ok = enma::execute(ctx, "main");
  const int64_t result = ok ? enma::return_value(ctx) : -1;

  enma::destroy_context(mod, ctx);
  enma::module_destroy(mod);
  enma::destroy(engine);
  enma::shutdown();

  return ok ? static_cast<int>(result) : 1;
}
```

Check exact SDK signatures against the API Reference for your pinned SDK version.

### C. Script review checklist (from Enma's own guidance)

- [ ] No `short`, `long` or `unsigned`.
- [ ] No `#include` of a standard header.
- [ ] No `->` on a value whose type declares no `operator->()`.
- [ ] No `std::` names that the STD Library page does not list.
- [ ] Every `new` has a `delete`; nothing returns the address of a local.

### D. Sources

- [Enma documentation](https://enma.studio/docs/enma)
- [Enma full docs for assistants (llms-full.txt)](https://enma.studio/docs/enma/llms-full.txt)
- [Writing Enma with an Assistant](https://enma.studio/docs/enma/LLMS)
- [Semantics & Limits](https://enma.studio/docs/enma/language-guide/semantics-and-limits)
- [SDK: Native Functions](https://enma.studio/docs/enma/sdk-guide/native-functions)
- [SDK: Threading & Concurrency](https://enma.studio/docs/enma/sdk-guide/concurrency)
- [SDK: Engine Lifecycle](https://enma.studio/docs/enma/sdk-guide/engine-lifecycle)
