Skip to main content

moonbit-agent-guide

Guide for writing, refactoring, and testing MoonBit projects, including exclusive use of `.mbtx` for agent-authored automation. Use when working in MoonBit modules or packages, organizing MoonBit files, using moon tooling (build/check/run/test/doc/ide etc.), or following MoonBit-specific layout, scripting, documentation, and testing conventions.

Ir a la instalación

Datos de origen

Repositorio
moonbitlang/moonbit-agent-guide
Última actividad en el origen
1 de septiembre de 2026 a las 06:10
Idioma detectado de SKILL.md
inglés
Estrellas
75
Forks
11

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
9 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
moonbit-agent-guide
description
Guide for writing, refactoring, and testing MoonBit projects, including exclusive use of `.mbtx` for agent-authored automation. Use when working in MoonBit modules or packages, organizing MoonBit files, using moon tooling (build/check/run/test/doc/ide etc.), or following MoonBit-specific layout, scripting, documentation, and testing conventions.
# MoonBit Task Checklist - Locate the enclosing `moon.mod` and relevant `moon.pkg` files before editing. - Discover APIs with `moon ide doc`; use `outline`, `peek-def`, `find-references`, `hover`, and `rename` for semantic navigation and refactoring. - Use `.mbtx` exclusively for agent-authored automation; keep automation logic out of shell scripts and other scripting languages. - Keep changes within the correct package. Files do not define namespaces; separate top-level items with `///|`. - Add regression tests for bug fixes. Add black-box tests and docstring examples for new public APIs. - Validate with `moon check` and the narrowest relevant `moon test`; use `moon test --update` only for intended snapshot changes. Use `moon explain --diagnostic` to list warnings and `--warn-list` to enable selected warnings (for example, `+unnecessary_annotation`). - Run `moon fmt` and `moon info` before handoff. Review generated `.mbti` changes, especially when the public API should remain stable. # MoonBit Project Layouts MoonBit uses the `.mbt` extension for source code files and interface files with the `.mbti` extension. At the top-level of a MoonBit project there is a `moon.mod` file specifying the metadata of the project. The project may contain multiple packages, each with its own `moon.pkg`. Subdirectories may also contain `moon.mod` files indicating that a different set of dependencies can be used for that subdir. Legacy projects may still contain `moon.mod.json`; treat it as the old module metadata format and migrate/update guidance to `moon.mod` instead of creating new `moon.mod.json` files. ## Example layout ``` my_module ├── moon.mod # Module metadata; source option can specify the source directory ├── moon.pkg # Package metadata (each directory is a package like Golang) ├── README.mbt.md # Markdown with tested code blocks (`test "..." { ... }`) ├── README.md -> README.mbt.md ├── cmd # Command line directory │ └── main │ ├── main.mbt │ └── moon.pkg # executable package with `options("is-main": true)` ├── liba/ # Library packages │ └── moon.pkg # Referenced by other packages as `@username/my_module/liba` │ └── libb/ # Library packages │ └── moon.pkg # Referenced by other packages as `@username/my_module/liba/libb` ├── user_pkg.mbt # Root packages, referenced by other packages as `@username/my_module` ├── user_pkg_wbtest.mbt # White-box tests (only needed for testing internal private members, similar to Golang's package mypackage) └── user_pkg_test.mbt # Black-box tests └── ... # More package files, symbols visible to current package (like Golang) ``` - **Module**: characterized by a `moon.mod` file in the project root directory. A MoonBit *module* is like a Go module; it is a collection of packages in subdirectories, usually corresponding to a repository or project. Module boundaries matter for dependency management and import paths. - **Package**: characterized by a `moon.pkg` file in each directory. All subcommands of `moon` will still be executed in the directory of the module (where `moon.mod` is located), not the current package. A MoonBit *package* is the actual compilation unit (like a Go package). All source files in the same package are concatenated into one unit and thereby share all definitions throughout that package. The `name` in the `moon.mod` file combined with the relative path to the package source directory defines the package name, not the file name. Imports refer to module + package paths, NEVER to file names. - **Files**: A `.mbt` file is just a chunk of source code inside a package. File names do NOT create modules, packages, or namespaces. You may freely split/merge/move declarations between files in the same package. Any declaration in a package can reference any other declaration in that package, regardless of file. ## Coding/layout rules you MUST follow: 1. Prefer many small, cohesive files over one large file. - Group related types and functions into focused files (e.g. http_client.mbt, router.mbt). - If a file is getting large or unfocused, create a new file and move related declarations into it. 2. You MAY freely move declarations between files inside the same package. - Each block is separated by `///|`. Moving a function/struct/trait between files does not change semantics, as long as its name and pub-ness stay the same. The order of each block is irrelevant too. - It is safe to refactor by splitting or merging files inside a package. 3. File names are purely organizational. - Do NOT assume file names define modules, and do NOT use file names in type paths. - Choose file names to describe a feature or responsibility, not to mirror type names rigidly. 4. When adding new code: - Prefer adding it to an existing file that matches the feature. - If no good file exists, create a new file under the same package with a descriptive name. - Avoid creating giant "impl", “misc”, or “util” files. 5. Tests: - Place tests in dedicated test files (e.g. `*_test.mbt`) within the appropriate package. For a package (besides `*_test.mbt`files), `*.mbt.md` files are also blackbox test files in addition to Markdown files. The code blocks (separated by triple backticks) `mbt check` are treated as test cases and serve both purposes: documentation and tests. You may have `README.mbt.md` files with `mbt check` code examples. You can also symlink `README.mbt.md` to `README.md` to make it integrate better with GitHub. - It is fine — and encouraged — to have multiple small test files. 6. Interface files (`pkg.generated.mbti`) `pkg.generated.mbti` files are compiler-generated summaries of each package's public API surface. They provide a formal, concise overview of all exported types, functions, and traits without implementation details. They are generated using `moon info` and useful for code review. When you have a commit that does not change public APIs, `pkg.generated.mbti` files will remain unchanged, so it is recommended to put `pkg.generated.mbti` in version control when you are done. Do not modify `pkg.generated.mbti` directly, including whitespace-only cleanup; regenerate it with `moon info` and review its diff as the public API signal. For IDE navigation and symbol lookup commands, see the dedicated `moon ide` section below. # Common Pitfalls to Avoid - **Don't use uppercase for variables/functions** - compilation error - **Don't forget `mut` for mutable record fields** - immutable by default (note that Arrays typically do NOT need `mut` unless completely reassigning to the variable - simple push operations, for example, do not need `mut`) - **Don't ignore error handling** - either handle errors explicitly, or declare `raise` on the caller and let checked errors propagate - **Don't use `return` unnecessarily** - the last expression is the return value - **Don't create methods without Type:: prefix** - methods need explicit type prefix - **Don't forget to handle array bounds** - use `get()` for safe access - **Don't forget @package prefix when calling functions from other packages** - **Don't use ++ or -- (not supported)** - use `i = i + 1` or `i += 1` - **Don't add explicit `try` for error propagation** - inside a `raise` function, call error-raising functions normally; use `catch` to handle locally and `try!` only when aborting is intended - **Legacy syntax**: Legacy code may use `function_name!(...)` or `function_name(...)?` - these are deprecated; use normal calls for propagation. - **Don't write an empty parameter list for `main`** - use `fn main { ... }` or `fn main raise { ... }`, not `fn main() { ... }` or `fn main() raise ... { ... }` - **Don't write record-style enum or error constructor fields** - labeled constructor fields use `label~ : Type`, e.g. `InvalidNumber(input~ : String)`, not `InvalidNumber(input: String)` - **Prefer range `for` loops over C-style** - `for i in 0..<(n-1) {...}` and `for j in 0..=6 {...}` are more idiomatic in MoonBit - **Don't use `for { ... }` for infinite loops** - write `for ;; { ... }` instead - **Don't `derive(Show)` for debugging** - derive `Debug` and use `debug_inspect()` for test/diagnostic output (`\{Repr(value)}` for interpolation of composed values). Reserve a manual `impl Show` for specialized display formats (JSON, XML, domain text) - **Don't call `@json.inspect()`** - use the prelude `json_inspect(value, ...)` without a package prefix - **Async** - MoonBit has no `await` keyword; do not add it. Async functions default to raising, so do not add `raise`; add `noraise` only when the async body must not raise. Async functions and tests are characterized by those which call other async functions. To identify a function or test as async, simply add the `async` prefix (e.g. `[pub] async fn ...`, `async test ...`). # `moon` Essentials ## Script Mode (`.mbtx`) Use `.mbtx` exclusively for agent-authored automation. Keep loops, conditionals, parsing, transformation, and process orchestration in MoonBit instead of shell scripts or another scripting language. The outer shell should only launch the script or run a direct, single-purpose command. An `.mbtx` file is an optional `import { ... }` block followed by ordinary MoonBit code, including a `main` function. Run it directly with: ```bash moon run path/to/script.mbtx [args...] ``` Choose `main` by the effects the script actually uses: - `fn main { ... }` is synchronous and does not propagate errors. - `fn main raise { ... }` is synchronous and may propagate checked errors. - `async fn main { ... }` is for scripts that call async APIs. Import `"moonbitlang/async"`; do not add `raise` or `await`. All three work on the default Wasm target. Do not mark a purely synchronous script `async`; MoonBit reports `unused_async`. When automation runs commands, import `"moonbitlang/async/shell"` and use `@shell.Cmd` or `@shell.Pipeline`. They keep the executable and arguments separate and never invoke a shell, so characters such as `|`, `$()`, and `*` are passed literally. Use ordinary MoonBit control flow instead of `&&`, shell loops, or command substitution. Script mode defaults to Wasm. Supplying `--wasm-policy policy.json` enables deny-by-default control over MoonBit host APIs; grant only the required filesystem, environment, network, or process access. For process automation, prefer a narrow `process.allow` rule with an exact program and argument prefix over `process.spawn: true`. The policy authorizes a child process but does not sandbox the child itself, so the host must also confine child processes when they are not trusted. Minimal script (`hello.mbtx`): ```mbtx fn main { println("Hello from MoonBit script mode") } ``` Command-line automation (`sum_args.mbtx`): ```mbtx import { "moonbitlang/core/env", "moonbitlang/core/string", } fn main raise { let args = @env.args() for arg in args[1:]; total = 0 { continue total + @string.parse_int(arg) } nobreak { println(total) } } ``` Running `moon run sum_args.mbtx 10 20 12` prints `42`. Package imports work directly in the script header (`format_json.mbtx`): ```mbtx import { "moonbitlang/core/json", } fn main raise { let source = #|{ #| "project": "moonbit", #| "enabled": true #|} let value = @json.parse(source) println(value.stringify(indent=2)) } ``` Async automation works on the default Wasm target. For example, run `moon run async_job.mbtx` for: ```mbtx import { "moonbitlang/async", } async fn main { @async.sleep(10) println("async automation complete") } ``` ## Essential Commands - `moon new my_project` - Create new project - `moon run cmd/main` - Run main package - `moon run - < hello.mbtx` - Run script code from stdin (useful for quick experiments) - `moon run -e "code snippet"` - Run code from command line argument (good for one-liners) ``` moon run -e 'fn main { println("Hello, MoonBit!") }' ``` - `moon build` - Build project (`moon run` and `moon build` both support `--target`; `moon build` also supports `--diagnostic-limit <N>`) - `moon check` - Type check without building, use it REGULARLY, it is fast (`moon check` also supports `--target` and `--diagnostic-limit <N>`) - `moon info` - Type check and generate `mbti` files. Run it to see if any public interfaces changed. (`moon info` also supports `--target`.) - `moon check --target all` - Type check for all backends Process structured diagnostics with a saved `.mbtx` script rather than a shell pipeline or another scripting language. For example, save this as `filter_diagnostics.mbtx`; `@shell.Cmd::each_line` runs `moon check` directly, streams its JSON output, and returns its exit status: ```mbtx import { "moonbitlang/async", "moonbitlang/async/shell", "moonbitlang/core/json", } async fn main { let seen : Map[String, Unit] = Map([]) let exit_code = @shell.Cmd( "moon", ["check", "--target", "all", "--output-json"], ).each_line(line => { try @json.parse(line) catch { _ => () } noraise { { "level": "warning", "path": String(path), .. } => if !seen.contains(path) { seen[path] = () println(path) } _ => () } }) if exit_code != 0 { fail("moon check exited with code \{exit_code}") } } ``` Run it with a policy that allows that command prefix: ```json { "process": { "allow": [ { "program": "moon", "args_prefix": ["check", "--target", "all", "--output-json"] } ] } } ``` ```bash moon run --wasm-policy moon-check-policy.json filter_diagnostics.mbtx ``` - `moon explain` - Show built-in documentation for compiler diagnostics and language topics. - `moon explain --diagnostic` lists warning mnemonics and IDs. - `moon explain --diagnostic 31` explains warning 31 (`unused_optional_argument`). - `moon explain --diagnostic unused_optional_argument` explains the same warning by mnemonic. - `moon explain --attribute` lists supported attributes such as `#deprecated`, `#alias`, `#cfg`, `#coverage.skip`, and `#warnings`. - `moon explain --attribute deprecated` explains the `#deprecated` attribute and its supported forms. - `moon add package` - Add dependency - `moon remove package` - Remove dependency - `moon fmt` - Format code - should be run periodically - note that the files may be rewritten Note you can also use `moon -C dir check` to run commands in a specific directory. ### Profiling Hot Paths (`moon run --profile`) `moon run --profile --target native --release cmd/<main>` runs a native release build under a sampling profiler and prints ranked **self-time** and **inclusive-time** tables plus a "runtime leaf costs attributed to MoonBit callers" section (which maps allocation, reference-counting, and string-equality costs back to *your* functions), alongside a `profile.json` and a `.trace` you can open in Instruments. On macOS it needs Xcode's `xcrun xctrace`, so install the full Xcode (not just the command-line tools) first. A single parse or compute is far too short to sample meaningfully, so point the profiled `main` at a loop that exercises the hot path a few hundred times over a representative fixture; this loop harness is throwaway and should never be committed. Read **self-time** for *which function burns cycles* and **inclusive-time** for *which call subtree dominates*, then work a tight loop: profile, fix the top item, re-profile. Always re-baseline before trusting a delta — sampled timings drift with machine load, so build and benchmark the branch and `main` back-to-back (interleaved) rather than comparing against a number from an earlier session. ### Test Commands - `moon test` - Run all tests (`moon test` also supports `--target`) - `moon test --update` - Update snapshots - `moon test -v` - Verbose output with test names - `moon test [dirname|filename]` - Test specific directory or file - `moon coverage analyze` - Analyze coverage
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub