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.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
moonbitlang/skills
آخر نشاط في المصدر
٤ سبتمبر ٢٠٢٦ في ٠١:٢٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٣١
التفرعات
٥

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
9 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
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
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub