{"owner":"loro-dev","repo":"loro","hasSkills":true,"totalSkillsCount":21,"totalTokensCount":25940,"categories":["root-instruction","claude-rule","plugin-manifest","anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md","CLAUDE.md","loro-js/AGENTS.md","loro-js/CLAUDE.md","packages/fractional-index/README.md","skills/loro/SKILL.md","skills/loro/agents/openai.yaml","skills/loro/references/containers-and-encoding.md","skills/loro/references/fit-and-architecture.md","skills/loro/references/mirror-and-react.md","skills/loro/references/performance-and-tradeoffs.md","skills/loro/references/richtext-and-editors.md","skills/loro/references/sync-versioning-and-events.md","skills/loro/references/topic-map.md","skills/moonbit/README.md","skills/moonbit/SKILL.mbt.md","skills/moonbit/SKILL.md","skills/moonbit/ide.md","skills/moonbit/references/advanced-moonbit-build.md","skills/moonbit/references/moonbit-language-fundamentals.mbt.md","skills/moonbit/references/moonbit-language-fundamentals.md"],"skills":{"AGENTS.md":"# Repository Guidelines\n\n## Project Snapshot\n\nLoro is a Rust CRDT workspace with JS/WASM packaging and a MoonBit codec.\n\n- `crates/loro`: public Rust API; avoid breaking downstream users.\n- `crates/loro-internal`: core CRDT logic. Read its\n  [AGENTS.md](crates/loro-internal/AGENTS.md) before changing import/export,\n  encoding, state, diff, checkout, or replay behavior.\n- `crates/loro-wasm`: `loro-crdt` WASM/TypeScript package. Read its\n  [AGENTS.md](crates/loro-wasm/AGENTS.md) before changing bindings, exports,\n  wrappers, or build scripts.\n- `crates/delta`, `crates/rle`, `crates/kv-store`, `crates/fractional_index`,\n  `crates/loro-common`, and `packages/fractional-index`: shared primitives and\n  packages.\n- `moon/`: MoonBit Loro binary codec; use [skills/moonbit/SKILL.md](skills/moonbit/SKILL.md).\n\n## Context Index\n\n- Undo/redo item boundaries when remote edits make an inverse a no-op:\n  [context/undo-history-boundaries.md](context/undo-history-boundaries.md).\n- Rust undo failure rollback and transaction writer serialization:\n  [context/undo-atomicity.md](context/undo-atomicity.md).\n- Encoding/import/export modes, current vs outdated formats, shallow snapshots:\n  [context/internal-encoding.md](context/internal-encoding.md).\n- Mergeable container model, marker/cid rules, tests, and common pitfalls:\n  [context/mergeable-containers.md](context/mergeable-containers.md).\n- `import_batch` force-detach, batch-wide rollback scope, and the never-exit-detached\n  invariant: [context/import-batch-atomicity.md](context/import-batch-atomicity.md).\n- Which root containers are visible (history-touched vs handle-acquired), and\n  why replays materialize empty roots:\n  [context/root-container-visibility.md](context/root-container-visibility.md).\n- Imports that reuse local op ids (a shared peer id): the known-history check,\n  what counts as equal, and what it cannot catch:\n  [context/import-peer-id-reuse.md](context/import-peer-id-reuse.md).\n- `apply_diff`/`revert_to` rollback of a failed batch, reused op ids, other\n  threads: [context/apply-diff-atomicity.md](context/apply-diff-atomicity.md).\n- Movable-list `Move`/`Set` import validation, and why a move of a deleted element\n  is applied rather than rejected:\n  [context/movable-list-op-validation.md](context/movable-list-op-validation.md).\n- Shallow-snapshot dead-style redaction (null-only, both-expand exclusion,\n  root-whitelisted latest state):\n  [context/shallow-snapshot-style-redaction.md](context/shallow-snapshot-style-redaction.md).\n- Rich-text insert positions next to style anchors, the insert cursor cache,\n  and delete `start_id`s: [context/richtext-insert-positions.md](context/richtext-insert-positions.md).\n- Tree diff cache transitions and why their lamport window comes from the two\n  versions, not the replay base: [context/tree-checkout-window.md](context/tree-checkout-window.md).\n- Tree event invariants (revived subtrees get `Create`s) and the two event\n  paths, diff-calculator vs raw ops: [context/tree-events.md](context/tree-events.md).\n- Deep tree traversal, snapshot order, and iterative result disposal:\n  [context/tree-depth.md](context/tree-depth.md).\n- loro.js tree diff item order, index counting, apply resolution, and batch dry-run:\n  [context/loro-js-tree-diff.md](context/loro-js-tree-diff.md).\n- loro.js concurrent tree moves, skipped cycles, replay, checkout, and undo:\n  [context/loro-js-tree-moves.md](context/loro-js-tree-moves.md).\n- User-facing Loro usage, sync, editor integration, and performance guidance:\n  [skills/loro/SKILL.md](skills/loro/SKILL.md).\n- Pure TypeScript runtime indexes, complexity contracts, benchmarks, and remaining gaps:\n  [context/loro-js-performance.md](context/loro-js-performance.md).\n- loro.js vs Rust randomized Text differential tests and the Rust behaviors they\n  work around: [context/loro-js-rust-differential.md](context/loro-js-rust-differential.md).\n- loro.js rich-text style anchors, entity positions, and Rust's insert/delete/mark\n  position rules: [context/loro-js-richtext-anchors.md](context/loro-js-richtext-anchors.md).\n- loro.js multi-peer differential fuzzing against replay, checkout, event, and\n  Rust/WASM oracles: [context/loro-js-differential-fuzz.md](context/loro-js-differential-fuzz.md).\n- loro.js MovableList model, the MovableList Rust differential suite\n  (`loro-js/tests/differential/`), and known loro.js/Rust divergences:\n  [context/loro-js-movable-list.md](context/loro-js-movable-list.md).\n- WASM panic/OOM reporting channels, `__wbindgen_start` glue invariant, and\n  trap-testing recipes:\n  [context/wasm-error-reporting.md](context/wasm-error-reporting.md).\n- WASM container id wrapper identity, lazy caching, and benchmark:\n  [context/wasm-container-id-cache.md](context/wasm-container-id-cache.md).\n- Bounded decoded-value cache in `InnerStore` (second-chance FIFO, eviction\n  safety contract, loro-dev/loro#1092):\n  [context/container-value-cache.md](context/container-value-cache.md).\n- Deep plain value decoding, Drop, and WASM conversion stack safety:\n  [context/deep-value-stack-safety.md](context/deep-value-stack-safety.md).\n- How the arena learns a container's parent (parsed changes, state KV, the op\n  log's creator resolver), its locking (including `ChangeStore`'s lock order),\n  and import rollback: [context/arena-parent-links.md](context/arena-parent-links.md).\n- Why a failed import's rollback keeps arena indices (DocState, caches and handlers\n  are keyed by them) and what it drops instead:\n  [context/failed-import-arena-indices.md](context/failed-import-arena-indices.md).\n- Which deletions `DocState::is_deleted` caches, and how tree/movable-list\n  children are revived: [context/dead-container-cache.md](context/dead-container-cache.md).\n- Movable-list `apply_diff`/undo: delete + re-insert of a child becomes a move,\n  cursor invariant, pitfalls: [context/movable-list-apply-diff.md](context/movable-list-apply-diff.md).\n- Unknown container types (newer-version containers): never created locally,\n  `apply_diff`/undo pre-check, events, test forging:\n  [context/unknown-containers.md](context/unknown-containers.md).\n- Why parsed change blocks keep text and list values out of doc-wide arenas\n  (`ValueSlice`, tracker tables): [context/text-arena-growth.md](context/text-arena-growth.md).\n- User callbacks that panic (subscribers, pre-commit, local updates): no poisoned\n  locks, lost events or hangs: [context/callback-panics.md](context/callback-panics.md).\n- Context backlog: [context/CONTEXT-GAPS.md](context/CONTEXT-GAPS.md).\n\n## Commands\n\n- JS deps: `pnpm install --frozen-lockfile`.\n- Rust build/check/format/lint: `cargo build`, `cargo check -p loro-internal`,\n  `cargo fmt --all`, `pnpm check`.\n- Rust tests: `pnpm test`; internal doctests: `cargo test -p loro-internal --doc`.\n- Loom: `pnpm test-loom`.\n- WASM: `pnpm release-wasm`, or `pnpm -C crates/loro-wasm build-dev`.\n- Bundlers after WASM packaging changes: `pnpm test-bundlers`; browser runtime:\n  `pnpm --dir examples/bundler-smoke-tests run test:browser`.\n- Fractional-index TS: `pnpm test-fractional-index`.\n- Fuzz smoke: `pnpm run-fuzz-corpus`.\n- MoonBit codec, when `moon` is available: from `moon/`, run `moon check`,\n  `moon test`, `moon fmt`.\n\nUse narrow checks first. Ask before broad fuzzing or long browser matrices.\n\n## Working Rules\n\n- Start with `git status --short --branch`; treat uncommitted changes as user\n  work unless you made them.\n- Before editing, read every `AGENTS.md` from root to target directory. Keep\n  `CLAUDE.md` as a symlink to the nearest `AGENTS.md`.\n- Use `rg` / `rg --files` for search.\n- Public API changes in `loro` or `loro-crdt` should be backward-compatible when\n  possible. Prefer new `try_*` APIs over breaking signatures.\n- Internal corruption should fail fast; invalid external input should return\n  `Err`. Returning wrong state is worse than panicking on an impossible internal\n  invariant.\n- Add regression tests near behavior: `crates/loro/tests`,\n  `crates/loro-internal/tests`, module tests, `crates/loro-wasm/tests`, or\n  `moon/loro_codec/*_test.mbt`.\n- Add a changeset for publishing behavior or package output changes.\n- Do not hand-edit generated WASM package output; regenerate it with package\n  scripts.\n\n## Self-Maintained Agent Context\n\n- Treat \"why was that hard to find?\" as a context bug. Add a nearby\n  `AGENTS.md` pointer or a `context/` article, or append a line to\n  [context/CONTEXT-GAPS.md](context/CONTEXT-GAPS.md).\n- Keep root context short. If an `AGENTS.md` grows past about 4000 characters, move\n  detail into a linked `context/` article.\n- Header context articles with `Verified against code YYYY-MM-DD`, anchor claims\n  to files/symbols, and link them from root plus the nearest per-directory\n  `AGENTS.md`.\n- If code changes make an `AGENTS.md` or context article stale, update the docs\n  in the same change.\n- When a commit needs non-obvious rationale, land that rationale in the nearest\n  context file and keep the commit message as a pointer.\n\n## Commit And PR Notes\n\nHistory uses short imperative commits, often prefixed by `fix:`, `test:`,\n`chore:`, or `refactor:`. PRs should include summary, rationale, validation, and\nlinked issues or traces when relevant.\n- Structured WASM reads, node identity, ranges and performance responsibilities:\n  [context/wasm-container-tree.md](context/wasm-container-tree.md).\n","CLAUDE.md":"AGENTS.md","loro-js/AGENTS.md":"# loro.js\n\nPure TypeScript implementation of Loro (`loro-js/src`). It must read and write\nthe same binary and JSON data as Rust (`loro-crdt`) and give the same results.\n\n## Context\n\n- Concurrent tree moves, skipped cycles, replay, checkout, and undo:\n  [context/loro-js-tree-moves.md](../context/loro-js-tree-moves.md).\n- Undo/redo no-op return values and item boundaries:\n  [context/undo-history-boundaries.md](../context/undo-history-boundaries.md).\n- Index structures, complexity contracts, and benchmarks:\n  [context/loro-js-performance.md](../context/loro-js-performance.md).\n- Randomized Text comparison with Rust (build the nodejs WASM package first):\n  [context/loro-js-rust-differential.md](../context/loro-js-rust-differential.md).\n- Multi-peer fuzzing of all containers against replay, checkout, event, and\n  shallow-snapshot oracles, optionally in lockstep with Rust:\n  [context/loro-js-differential-fuzz.md](../context/loro-js-differential-fuzz.md).\n- MovableList model (Rust's positions + LWW elements) and its multi-peer Rust\n  differential suite (`tests/differential/`):\n  [context/loro-js-movable-list.md](../context/loro-js-movable-list.md).\n- Rich text: style anchors live in the Text sequence and op positions count\n  them. Read [context/loro-js-richtext-anchors.md](../context/loro-js-richtext-anchors.md)\n  before changing Text positions, marks, or Text snapshot state.\n- Encoding formats: [context/internal-encoding.md](../context/internal-encoding.md)\n  and `docs/encoding*.md`.\n\n## Interop fixtures\n\n- Rust output read by loro.js: `tests/fixtures/rust/*.blob` and `*.json`.\n- loro.js output read by Rust: `pnpm fixtures:rewrite` runs\n  `scripts/rewrite-rust-fixture.mjs`, which writes `tests/fixtures/rust/*.ts.blob`;\n  `crates/loro/tests/loro_js_interop.rs` imports them. Container state encoders\n  live in `src/runtime/document.ts` (`#containerState`) and must follow\n  `docs/encoding-container-states.md`.\n- loro.js 0.2 output read by later versions: `scripts/write-legacy-fixtures.mjs`\n  writes `tests/fixtures/loro-js-0.2/` with a 0.2 build; `tests/legacy-data.test.ts`\n  pins that loro.js and Rust read it the same way. Later versions read 0.2 data\n  with Rust's semantics, with no version marker (README \"Upgrading from 0.2\"; the\n  decision is in [context/loro-js-rust-differential.md](../context/loro-js-rust-differential.md)).\n\n## Commands\n\nFrom `loro-js/`: `pnpm test`, `pnpm typecheck`, `pnpm lint`, `pnpm format:check`,\n`pnpm build`, or `pnpm check` for all of them. From the root, `pnpm test-loro-js`\nruns the tests and fails if the Rust WASM reference is missing (CI runs it after\n`release-wasm`). Benchmarks: `pnpm bench:b4`,\n`pnpm bench:complexity -- 1000,2000,4000,8000`.\n","loro-js/CLAUDE.md":"AGENTS.md","packages/fractional-index/README.md":"# @loro-dev/fractional-index\n\nTypeScript implementation of Loro's Rust `loro_fractional_index` crate.\n\nThis package creates compact string positions that sort lexicographically. The\npublic API always accepts and returns canonical uppercase hex strings, so indexes\nare easy to store, compare, serialize, and use as object or map keys.\n\n- No runtime dependencies.\n- ESM output with TypeScript declarations.\n- Public indexes are plain strings.\n- Generated strings are byte-for-byte compatible with the Rust crate's\n  `Display` output.\n- Golden tests are generated from the Rust implementation in this repository.\n\n## Install\n\n```sh\npnpm add @loro-dev/fractional-index\n```\n\n```sh\nnpm install @loro-dev/fractional-index\n```\n\n```sh\nyarn add @loro-dev/fractional-index\n```\n\n## Quick Start\n\n```ts\nimport { FractionalIndex, compare } from \"@loro-dev/fractional-index\";\n\nconst first = FractionalIndex.default();\nconst before = FractionalIndex.newBefore(first);\nconst after = FractionalIndex.newAfter(first);\nconst middle = FractionalIndex.newBetween(first, after);\n\nconsole.log(first); // \"80\"\nconsole.log(before); // \"7F80\"\nconsole.log(after); // \"8180\"\nconsole.log(middle); // \"817F80\"\n\nconst ordered = [after, first, before].sort(compare);\nconsole.log(ordered); // [\"7F80\", \"80\", \"8180\"]\n\nJSON.stringify({ position: first }); // \"{\\\"position\\\":\\\"80\\\"}\"\n```\n\nGenerated indexes are canonical uppercase hex strings. For generated values,\nordinary string comparison also follows byte order:\n\n```ts\nbefore < first; // true\nfirst < after; // true\n```\n\nUse `compare(a, b)` when sorting values that may have been parsed from external\ninput, because it compares by bytes after parsing.\n\n## Data Model\n\nAn index string is the uppercase hex encoding of the same bytes used by Rust.\nGenerated indexes include the `0x80` terminator byte.\n\n```ts\nconst index = FractionalIndex.default(); // \"80\"\n```\n\nThe public API does not expose byte arrays. Internally, the implementation still\nuses bytes to stay aligned with the Rust algorithm.\n\n## Creating Indexes\n\n### Default\n\n```ts\nconst index = FractionalIndex.default(); // \"80\"\n```\n\nThis matches `FractionalIndex::default()` in Rust.\n\n### Before And After\n\n```ts\nconst base = FractionalIndex.default();\n\nconst before = FractionalIndex.newBefore(base); // \"7F80\"\nconst after = FractionalIndex.newAfter(base); // \"8180\"\n```\n\n### Between Two Indexes\n\n```ts\nconst left = FractionalIndex.default();\nconst right = FractionalIndex.newAfter(left);\nconst between = FractionalIndex.newBetween(left, right);\n\nif (between) {\n  console.log(left < between); // true for canonical generated strings\n  console.log(between < right); // true\n}\n```\n\n`newBetween()` returns `undefined` when the Rust crate would return `None`.\nFor byte sequences that trigger a Rust panic, this package throws an `Error`\ninstead of returning a misleading value.\n\n### General Constructor\n\n`FractionalIndex.new(lower, upper)` mirrors Rust's `FractionalIndex::new`:\n\n```ts\nFractionalIndex.new(undefined, undefined); // default \"80\"\nFractionalIndex.new(existing, undefined); // after existing\nFractionalIndex.new(undefined, existing); // before existing\nFractionalIndex.new(left, right); // between left and right\n```\n\n`null` and `undefined` are both treated as an absent bound.\n\n## Generating Many Indexes\n\nUse `generateNEvenly()` when you know how many positions you need. It produces\nstrictly sorted indexes inside the open interval `(lower, upper)`.\n\n```ts\nconst values = FractionalIndex.generateNEvenly(undefined, undefined, 5);\n\nconsole.log(values);\n// [\"7E80\", \"7F80\", \"80\", \"817F80\", \"8180\"]\n```\n\nBounded generation:\n\n```ts\nconst lower = FractionalIndex.newBefore(FractionalIndex.default());\nconst upper = FractionalIndex.newAfter(FractionalIndex.default());\n\nconst values = FractionalIndex.generateNEvenly(lower, upper, 100);\n```\n\nThe method returns `undefined` if both bounds are provided and `lower >= upper`.\n\n## Jitter\n\nThe Rust crate can append random bytes after the terminator. This package exposes\nthe same behavior through `JitterOptions`.\n\n```ts\nconst index = FractionalIndex.jitterDefault({ jitter: 3 });\nconsole.log(index.length); // 8 hex chars: 0x80 plus 3 random bytes\n```\n\nFor deterministic tests or replicated fixtures, provide `randomByte`:\n\n```ts\nconst bytes = [1, 2, 3];\nlet offset = 0;\n\nconst index = FractionalIndex.jitterDefault({\n  jitter: 3,\n  randomByte: () => bytes[offset++],\n});\n\nconsole.log(index); // \"80010203\"\n```\n\nJitter variants:\n\n```ts\nFractionalIndex.jitterDefault({ jitter: 2 });\nFractionalIndex.newJitter(lower, upper, { jitter: 2 });\nFractionalIndex.newBeforeJitter(index, { jitter: 2 });\nFractionalIndex.newAfterJitter(index, { jitter: 2 });\nFractionalIndex.newBetweenJitter(left, right, { jitter: 2 });\nFractionalIndex.generateNEvenlyJitter(lower, upper, 10, { jitter: 2 });\n```\n\n`jitter` and `randomByte` must both be integers in `[0, 255]`, matching Rust's\n`u8` boundary.\n\n## Parsing And Serialization\n\n```ts\nconst fromHex = FractionalIndex.fromHexString(\"80ff\");\nconsole.log(fromHex); // \"80FF\"\n```\n\nCompatibility notes:\n\n- `fromHexString()` accepts uppercase or lowercase hex and returns canonical\n  uppercase hex.\n- Like Rust, `fromHexString()` ignores a trailing odd nibble. `\"80A\"` parses as\n  `\"80\"`.\n- Invalid hex pairs throw `SyntaxError`.\n\n## API Reference\n\n```ts\ntype FractionalIndex = string;\n\ninterface JitterOptions {\n  jitter?: number;\n  randomByte?: () => number;\n}\n```\n\n### Namespace API\n\n```ts\nFractionalIndex.TERMINATOR; // 128\n\nFractionalIndex.default(): FractionalIndex;\nFractionalIndex.fromHexString(hex): FractionalIndex;\n\nFractionalIndex.new(lower?, upper?): FractionalIndex | undefined;\nFractionalIndex.newBefore(index): FractionalIndex;\nFractionalIndex.newAfter(index): FractionalIndex;\nFractionalIndex.newBetween(left, right): FractionalIndex | undefined;\nFractionalIndex.generateNEvenly(lower, upper, n): FractionalIndex[] | undefined;\n\nFractionalIndex.jitterDefault(options?): FractionalIndex;\nFractionalIndex.newJitter(lower, upper, options?): FractionalIndex | undefined;\nFractionalIndex.newBeforeJitter(index, options?): FractionalIndex;\nFractionalIndex.newAfterJitter(index, options?): FractionalIndex;\nFractionalIndex.newBetweenJitter(left, right, options?): FractionalIndex | undefined;\nFractionalIndex.generateNEvenlyJitter(\n  lower,\n  upper,\n  n,\n  options?,\n): FractionalIndex[] | undefined;\n\nFractionalIndex.compare(left, right): number;\nFractionalIndex.equals(left, right): boolean;\nFractionalIndex.isFractionalIndex(value): value is FractionalIndex;\n```\n\n### Top-Level Helpers\n\nNamespace methods are also available as named exports. Since `new` is a\nJavaScript keyword, `FractionalIndex.new()` is exported as `newIndex()`:\n\n```ts\ndefaultIndex();\nfromHexString(hex);\ncompare(left, right);\nequals(left, right);\nnewIndex(lower, upper);\nnewBefore(index);\nnewAfter(index);\nnewBetween(left, right);\ngenerateNEvenly(lower, upper, n);\njitterDefault(options);\nnewJitter(lower, upper, options);\nnewBeforeJitter(index, options);\nnewAfterJitter(index, options);\nnewBetweenJitter(left, right, options);\ngenerateNEvenlyJitter(lower, upper, n, options);\nisFractionalIndex(value);\n```\n\n## Testing Against Rust\n\nThe golden fixture used by the TypeScript tests is generated from the Rust crate:\n\n```sh\npnpm --filter @loro-dev/fractional-index fixtures:generate\npnpm --filter @loro-dev/fractional-index check\n```\n\nThe fixture covers:\n\n- Default, before, after, and between generation.\n- Long before/after chains.\n- `generate_n_evenly` for bounded and unbounded ranges.\n- `None` cases.\n- Rust panic edge cases.\n- Jitter byte placement.\n- Hex serialization.\n\n## Development Commands\n\nThis package uses Vite+ (`vp`) for build, test, lint, and format orchestration.\n\n```sh\npnpm --filter @loro-dev/fractional-index format\npnpm --filter @loro-dev/fractional-index lint\npnpm --filter @loro-dev/fractional-index typecheck\npnpm --filter @loro-dev/fractional-index test\npnpm --filter @loro-dev/fractional-index build\npnpm --filter @loro-dev/fractional-index check\n```\n\n`lint` runs oxlint in type-aware mode with warnings denied. `format` and\n`format:check` use oxfmt. `typecheck` uses `tsgo`. `build` runs `vp pack` and\nemits the ESM bundle, declarations, and sourcemap to `dist/`.\n\n## Performance Notes\n\nString indexes are optimized for JavaScript ergonomics: comparison, JSON,\nstorage, and use as keys are all straightforward. The implementation parses\nstrings to byte arrays internally for generation so it can stay aligned with the\nRust byte algorithm. For the expected workload of normal list/tree positioning,\nthis keeps the API simple without a meaningful practical performance cost.\n","skills/loro/SKILL.md":"---\nname: loro\ndescription: \"Practical guide for helping app developers evaluate, adopt, and use Loro for local-first collaboration. Use when Codex needs to answer questions or write examples for `loro-crdt`, `loro`, `loro-prosemirror`, `loro-codemirror`, `loro-mirror`, language bindings such as Swift/Python/C#/Go/React Native, or Loro-powered apps about: (1) Deciding whether Loro fits a product, (2) Getting started in JavaScript/TypeScript, Rust, or another supported binding, (3) Choosing CRDT containers and document structure, (4) Designing sync, persistence, snapshots, versioning, undo, presence, or time travel, (5) Integrating rich-text editors and stable selections, (6) Mirroring app state with React, or (7) Understanding performance and tradeoffs.\"\n---\n\n# Loro\n\nUse this skill to help users build applications with Loro. Start from the user's product goal, then choose the narrowest chapter that answers it. Load a second chapter only when the task crosses domains.\n\n## Select A Chapter\n\n- Read [references/topic-map.md](references/topic-map.md) if the task is broad and you need to route it.\n- Read [references/fit-and-architecture.md](references/fit-and-architecture.md) for product fit, installation, language/package choices, first examples, and core mental models.\n- Read [references/containers-and-encoding.md](references/containers-and-encoding.md) for choosing containers, shaping documents, exporting updates, snapshots, persistence, shallow snapshots, and redaction.\n- Read [references/sync-versioning-and-events.md](references/sync-versioning-and-events.md) for realtime/offline sync, version vectors, frontiers, checkout, undo, presence, timestamps, events, and Inspector.\n- Read [references/richtext-and-editors.md](references/richtext-and-editors.md) for `LoroText`, cursors, `applyDelta`, `updateByLine`, `loro-prosemirror`, Tiptap, and CodeMirror.\n- Read [references/mirror-and-react.md](references/mirror-and-react.md) for `loro-mirror`, `$cid`, `idSelector`, validation, selectors, and React integration.\n- Read [references/performance-and-tradeoffs.md](references/performance-and-tradeoffs.md) for scaling, document/update size, loading speed, and workload tradeoffs.\n\n## Route Common Tasks\n\n- “I am new to Loro / should I use it / show me a first example”\n  - Start with `fit-and-architecture.md`\n- “Which language package or binding should I use?”\n  - Start with `fit-and-architecture.md`\n- “Build a collaborative document model / choose data types / persist history”\n  - Start with `containers-and-encoding.md`\n  - Add `sync-versioning-and-events.md` if version/history behavior matters\n- “Sync devices, store data, use snapshots, time travel, undo, or presence”\n  - Start with `sync-versioning-and-events.md`\n- “Integrate ProseMirror, Tiptap, CodeMirror, or custom rich text”\n  - Start with `richtext-and-editors.md`\n  - Add `sync-versioning-and-events.md` if undo/version/event behavior matters\n- “Model app state with loro-mirror or loro-mirror-react”\n  - Start with `mirror-and-react.md`\n  - Add `containers-and-encoding.md` if schema semantics depend on container choice\n- “Explain performance, large documents, loading, update size, or tradeoffs”\n  - Start with `performance-and-tradeoffs.md`\n- “Decide whether Loro is the right tool”\n  - Start with `fit-and-architecture.md`\n  - Add `performance-and-tradeoffs.md` if workload scale matters\n\n## Execute The Task\n\n1. Classify the task before reading everything.\n2. Load one primary chapter.\n3. Load at most one secondary chapter for cross-domain work.\n4. Keep solutions grounded in Loro semantics:\n   - choose data types by merge behavior,\n   - distinguish state version from history version,\n   - keep ephemeral state out of persisted CRDT data,\n   - use stable cursors for collaborative selections,\n   - design sync around updates and snapshots rather than a central locking protocol.\n\n## Keep Guardrails\n\n- Do not assume CRDTs are the right fit for hard invariants, exclusivity, or authorization-at-write-time problems.\n- Do not model editable text as plain strings when user intent requires merged edits.\n- Do not reuse peer IDs across concurrent sessions.\n- Do not confuse detached documents with detached containers.\n- Do not persist cursor presence, hover state, or connection state inside the main document; use ephemeral state.\n","skills/loro/agents/openai.yaml":"interface:\n  display_name: \"Loro\"\n  short_description: \"Guide for adopting and using Loro in apps\"\n  default_prompt: \"Use $loro to design or explain a Loro-powered app, from choosing a language binding through modeling, sync, editors, React state, and performance.\"\n","skills/loro/references/containers-and-encoding.md":"# Containers And Encoding\n\n## Container Choice\n\n- `LoroMap`: LWW key-value storage. Good for object-like state, coordinates, metadata, URLs, and fields where overwriting is preferable to merging.\n- `LoroList`: ordered sequence with insert/delete semantics.\n- `LoroMovableList`: ordered sequence with native move and set semantics. Prefer for drag-and-drop or reorder-heavy UIs.\n- `LoroTree`: hierarchical moves plus node-local data maps. Prefer for outlines, layers, nested blocks, or parent-child structures.\n- `LoroCounter`: additive numeric CRDT. Use when concurrent increments/decrements must accumulate.\n- `LoroText`: collaborative text. Use `updateByLine(...)` when line-oriented reconciliation is preferable to raw whole-string replacement.\n\n## Behavioral Notes\n\n- `LoroMap` compares concurrent writes by logical time and retains the winning value.\n- Setting a map entry to the same value is a no-op, so it does not create history.\n- `LoroList` and `LoroMovableList` both support stable cursors; use them when positions must survive concurrent edits.\n\n## Choice Pitfalls\n\n- Do not store editable prose as a plain string in a map unless LWW semantics are desired.\n- Do not model coordinates as `[x, y]` in a list. Concurrent delete+insert can create invalid arrays. Use a map.\n- Do not model arbitrary graphs directly. Loro documents compose as trees, not DAGs with shared children.\n\n## Container States And Composition\n\n- Detached containers come from constructors like `new LoroMap()`.\n- Attached containers belong to a document and have stable `ContainerID`s.\n- Adding a detached container to a document returns an attached version; the original object remains detached.\n- Root containers come from `doc.getMap(...)`, `doc.getText(...)`, `doc.getList(...)`, `doc.getTree(...)`, and so on.\n- For map-key children that may be lazily created by multiple peers, use `ensureMergeable*` in JS/TS or `ensure_mergeable_*` in Rust.\n- Use `setContainer(...)` / `insertContainer(...)` for regular child creation or replacement; list-position `insertContainer(...)` is unchanged.\n\n## Mergeable Map Children And Overwrite Hazards\n\n- Root container IDs derive from root name plus type.\n- Regular child container IDs derive from the operation that created them.\n- Mergeable map-key child IDs derive from the parent map, key, and type, so concurrent first creation at the same key converges to the same child.\n- Prefer `ensureMergeableText`, `ensureMergeableMap`, `ensureMergeableList`, `ensureMergeableMovableList`, `ensureMergeableTree`, or `ensureMergeableCounter` for dynamic fields, lazy migrations, per-date lists, and other map-key children that should behave as one shared child.\n- `getOrCreateContainer` / `get_or_create_container` is legacy regular child creation; do not recommend it for lazy map-key children.\n\n## Tree Specifics\n\n- `LoroTree` gives each node an associated `Map` container via `node.data`.\n- Fractional indices order siblings. Use them when child ordering matters.\n- When many peers insert at the same sibling position, peer ID acts as a tiebreaker for equal fractional indices.\n- Fractional index jitter reduces collisions at some encoding-size cost.\n- `getNodes(...)` and node JSON views are useful when a flat inspection of the forest is easier than recursive traversal.\n\n## List Vs Movable List\n\n- Use `LoroList` when delete+insert is acceptable and native move identity is unnecessary.\n- Use `LoroMovableList` for kanban columns, cards, playlist reordering, or any UX where “move this item” is semantically distinct from delete+insert.\n\n## Counter\n\n- `Counter` aggregates applied values from all peers.\n- It is the right choice for additive metrics, not for values with hard invariants.\n\n## Export Modes\n\n- `update`: sync delta payloads.\n- `updates-in-range`: bounded history export.\n- `snapshot`: full state checkpoint.\n- `shallow-snapshot`: current state plus truncated history.\n\n## Import Choices\n\n- `import(...)`: one payload at a time.\n- `importBatch(...)`: preferred for multiple updates or mixed snapshot/update payloads because diffing and event emission are coalesced.\n- Imports can succeed partially when dependencies are missing. Pending ranges mean the document knows about those operations but cannot apply them yet.\n\n## Persistence Pattern\n\n1. Periodically save a snapshot.\n2. Frequently persist updates, often after each local edit or on a debounce.\n3. On load, import the snapshot and outstanding updates.\n4. Recompact by exporting a fresh snapshot and deleting replayed updates.\n\n## Shallow Snapshots And Redaction\n\n- Use shallow snapshots when old history can be archived or discarded.\n- They are often much smaller than full snapshots.\n- Peers can only sync if they have versions after the shallow start point.\n- Archive full history before trimming if old history may still matter.\n- Redaction replaces sensitive payloads while preserving enough structure for future synchronization.\n- If old peers still hold unsanitized history, sensitive data still exists there.\n","skills/loro/references/fit-and-architecture.md":"# Getting Started And Fit\n\n## When Loro Fits\n\n- Collaborative text and structured documents.\n- Offline-first applications that later synchronize.\n- Multi-device sync where eventual consistency is acceptable.\n- Apps that benefit from complete history, time travel, or version checkpoints.\n\n## When Loro Does Not Fit By Itself\n\n- Financial or accounting invariants.\n- Exclusive ownership or booking/locking semantics.\n- Authorization decisions that must be enforced at write time.\n- Arbitrary graph-shaped or non-JSON-like data without an adaptation layer.\n\n## Install\n\n- JavaScript/TypeScript: install `loro-crdt`.\n- Rust: install the `loro` crate.\n- Use editor integrations when available instead of writing editor sync from scratch:\n  - `loro-prosemirror` for ProseMirror and Tiptap-style editors.\n  - `loro-codemirror` for CodeMirror 6.\n- Use `loro-mirror` and `loro-mirror-react` when the app already thinks in immutable state and actions.\n\n## Language And Package Index\n\n- JavaScript/TypeScript: [`loro-crdt`](https://www.npmjs.com/package/loro-crdt). Start here for web apps and most examples in the Loro docs.\n- Rust: [`loro`](https://crates.io/crates/loro) and [`docs.rs/loro`](https://docs.rs/loro). Use for native Rust apps, services, CLIs, and custom infrastructure.\n- Swift: [`loro-swift`](https://github.com/loro-dev/loro-swift). Use for Swift/iOS/macOS experiments and native apps.\n- Python: [`loro-py`](https://github.com/loro-dev/loro-py). Use for Python apps, scripts, and server-side tooling.\n- React Native: [`loro-react-native`](https://github.com/loro-dev/loro-react-native). Use for mobile apps that need native React Native bindings.\n- C#: [`loro-cs`](https://github.com/sensslen/loro-cs). Community-maintained .NET/C# binding; check its README and release state before adopting.\n- Go: [`loro-go`](https://github.com/aholstenson/loro-go). Community-maintained Go binding; check platform support and API completeness before adopting.\n- Cross-language FFI base: [`loro-ffi`](https://github.com/loro-dev/loro-ffi). Use this as the reference for generated/native bindings and as a starting point for new language bindings.\n\nPrefer the official JS/TS or Rust package when there is no product reason to choose another language. For community bindings, verify platform binaries, Loro core version, and API coverage before making product commitments.\n\n## First JavaScript Example\n\n```ts\nimport { LoroDoc } from \"loro-crdt\";\n\nconst docA = new LoroDoc();\nconst listA = docA.getList(\"items\");\nlistA.insert(0, \"A\");\nlistA.insert(1, \"B\");\n\nconst update = docA.export({ mode: \"update\" });\n\nconst docB = new LoroDoc();\ndocB.import(update);\n\nconsole.log(docB.toJSON()); // { items: [\"A\", \"B\"] }\n```\n\n## First Design Questions\n\n1. What parts of the state should merge when edited concurrently?\n2. Which data needs durable history, and which data is only presence or UI state?\n3. Do users need text/rich-text intent preservation, ordered moves, tree moves, or simple last-write-wins fields?\n4. How will peers exchange updates, and where will snapshots or updates be persisted?\n\n## Conceptual Model\n\n- Loro is a CRDT framework for local-first apps.\n- It trades strict coordination for strong eventual consistency.\n- Each peer edits locally, exports updates, imports updates from other peers, and converges after seeing the same operations.\n- Loro records history, so versioning and time travel are core concepts rather than an afterthought.\n\n## Document Shape Constraints\n\n- Loro documents are JSON-like.\n- Map keys are strings.\n- The composed document structure is tree-shaped, not a general graph with shared children.\n\n## Entry Points\n\n- Core packages and language bindings are listed in `Language And Package Index`.\n- Ecosystem integrations include editor bindings, state-mirroring layers, React Native, and Inspector.\n\n## Practical Start Path\n\n1. Pick container types in `containers-and-encoding.md`.\n2. Decide sync and persistence shape in `sync-versioning-and-events.md`.\n3. Add editor or React integration only after the document model is clear.\n4. Use Inspector during development to inspect state and history.\n","skills/loro/references/mirror-and-react.md":"# Mirror And React\n\n## Mirror Intent\n\n- `loro-mirror` keeps an immutable app-state view in sync with a `LoroDoc`.\n- Local `setState(...)` edits become granular CRDT operations.\n- Remote CRDT events patch the mirrored app state back in.\n- The common mental model is still “immutable app state plus typed actions”, not direct mutation of raw CRDT containers everywhere.\n\n## Root Schema\n\n- Build the root with `schema({...})`.\n- Keep root fields as Loro containers: `LoroMap`, `LoroList`, `LoroMovableList`, `LoroText`.\n- Put primitives inside those containers, not at the root.\n\n## Field Types\n\n- `schema.String`, `schema.Number`, `schema.Boolean`: concrete primitive fields.\n- `schema.Any`: dynamic JSON-like payload when the shape is truly unknown.\n- `schema.Ignore`: local-only or derived fields that should not sync to Loro.\n\n## Maps, Lists, And `$cid`\n\n- `schema.LoroMap({...})`: nested object container.\n- `schema.LoroMap(...).catchall(valueSchema)`: add dynamic keys while preserving known keys.\n- `schema.LoroMapRecord(valueSchema)`: homogeneous record-like map.\n- Every mirrored `LoroMap` includes a read-only `$cid`.\n- `$cid` matches the underlying Loro container ID.\n- Use `$cid` as a stable key or default `idSelector`, especially for list items.\n- Never try to persist or mutate `$cid` from app code.\n- Do not invent a `withCid`-style option; mirrored map values already receive `$cid` automatically.\n\n## Lists\n\n- `LoroList(itemSchema, idSelector?)`: ordered collection. Add `idSelector` for stable add/remove/update/move diffs.\n- `LoroMovableList(itemSchema, idSelector)`: native move semantics, ideal for drag-and-drop.\n- If a list item is a map, `(item) => item.$cid` is often the right `idSelector`.\n\n## Defaults And Validation\n\n- Explicit `defaultValue` wins.\n- Required fields without explicit defaults fall back to built-in defaults.\n- `validateUpdates` is enabled by default in `Mirror`. Keep it on unless a measured hot path proves otherwise.\n- Use `validateSchema(...)` when you need an explicit validation pass during migration or debugging.\n\n## React Patterns\n\n- Create a stable `LoroDoc` instance.\n- Create helpers through `createLoroContext(schema)` or `useLoroStore(...)`.\n- Wrap the tree in `LoroProvider` when using the context pattern.\n- Use the narrowest hook that solves the task:\n  - `useLoroState` for the full mirrored state\n  - `useLoroSelector` for focused subscriptions\n  - `useLoroAction` for write paths\n- Keep the provider `doc` stable across renders.\n- Prefer `useLoroSelector` over pulling the full state into every component.\n- Use mirrored list item `$cid` values as React keys.\n\n## Practical Mental Model\n\n- Subscribe to order at collection boundaries.\n- Subscribe to content at item boundaries.\n- Pass `$cid`s downward and reselect locally instead of passing large mirrored objects through the whole tree.\n- Keep view-local state outside the mirror unless collaborators must share it.\n","skills/loro/references/performance-and-tradeoffs.md":"# Performance And Tradeoffs\n\nUse this chapter when users ask whether Loro can handle a workload, how to store data efficiently, or why one sync/storage design is preferable to another.\n\n## What To Compare\n\n- Encoded document size and update size.\n- Snapshot export/import time.\n- Update import time.\n- Memory footprint while editing and loading.\n- Conflict-heavy collaboration versus mostly independent edits.\n- Initial load path versus steady-state sync path.\n\n## Practical Defaults\n\n- Use update exchange for live collaboration.\n- Use snapshots for fast startup checkpoints.\n- Store frequent small updates between snapshots when durable replay is needed.\n- Recompact by exporting a fresh snapshot after enough updates accumulate.\n- Consider shallow snapshots when old history can be archived or discarded.\n\n## Workload-Specific Advice\n\n- Collaborative text: use `LoroText`; do not model text as a plain string just to reduce apparent complexity.\n- Reorder-heavy collections: use `LoroMovableList` instead of delete+insert if move identity matters.\n- Hierarchies: use `LoroTree`; avoid forcing tree-shaped data into ad hoc map/list structures.\n- High-frequency presence or cursor movement: use `EphemeralStore`, not the persisted document.\n- Hard invariants such as balances, bookings, or permissions still need application/server-side validation outside the CRDT merge.\n\n## Benchmark Interpretation\n\n- Treat benchmarks as workload indicators, not universal rankings.\n- A smaller full snapshot does not automatically mean smaller incremental updates.\n- A fast import path matters most for startup and bulk sync.\n- A compact update path matters most for live collaboration and bandwidth-constrained clients.\n- Shallow snapshots reduce retained history, but peers with only older history may need a fresh snapshot or archived history to sync.\n\n## Explain Tradeoffs\n\n- Loro optimizes for local editing, automatic merging, history, and version control.\n- Strong eventual consistency means peers converge after receiving the same operations.\n- Loro does not provide central locking, serializable transactions, or write-time authorization by itself.\n- Pick containers by merge semantics first, then tune storage and sync format for performance.\n","skills/loro/references/richtext-and-editors.md":"# Rich Text And Editors\n\n## Rich Text Rules\n\n- Use `LoroText` for collaboratively edited text.\n- Keep rich text style config in sync across peers:\n  - `after`\n  - `before`\n  - `none`\n  - `both`\n- If two peers use different `configTextStyle(...)`, they can interpret the same boundary insert differently.\n\n## Text API Notes\n\n- `update(...)` rewrites based on a target text snapshot.\n- `updateByLine(...)` is useful when line-oriented reconciliation is more appropriate than raw whole-string replacement.\n- `toDelta()` preserves marks and annotations.\n- `toJSON()` / `toString()` return plain text only.\n\n## `applyDelta(...)` Caveat\n\n- `applyDelta(...)` is ideal for editor bindings because it matches event diffs.\n- Delta inserts must include the full attribute set of the inserted range.\n- If CRDT inheritance would add marks but the delta omits them, `applyDelta(...)` removes those attributes.\n- Out-of-range formatting can cause Loro to materialize newlines to satisfy editor assumptions.\n\n## Stable Selections\n\n- Use `text.getCursor(...)` to create stable positions.\n- Use two cursors for selections: anchor and head.\n- Resolve live offsets with `doc.getCursorPos(...)`.\n- Persist updated cursors returned from resolution to reduce replay cost.\n- JavaScript text offsets are UTF-16 indices.\n\n## ProseMirror And Tiptap\n\n- Start with `loro-prosemirror` for ProseMirror and Tiptap.\n- It already covers document sync, collaborative undo and redo, and cursor presence.\n- The current baseline is `CursorEphemeralStore` plus `LoroEphemeralCursorPlugin`.\n- Give each editor instance its own `containerId` when several editors share one `LoroDoc`.\n- Reuse the same container only if several views intentionally co-edit the exact same content.\n\n## CodeMirror\n\n- Use the official CodeMirror integration when the editor is CM6-based.\n- Keep awareness/presence, undo, and document sync at the Loro layer rather than inventing a separate editor-level protocol.\n\n## Rich Text Internals\n\n- Loro rich text uses style anchors to represent mark boundaries.\n- Overlap and expansion behavior are first-class concerns.\n- Overlappable styles are often best modeled by unique keys with a shared prefix pattern such as `comment:alice` and `comment:bob`.\n\n## Guardrails\n\n- Do not model editable prose as `string` in a `LoroMap`.\n- Do not store collaborative selections as plain indices.\n- Do not mix old and new ProseMirror cursor APIs accidentally; check the installed package version and current API docs first.\n","skills/loro/references/sync-versioning-and-events.md":"# Sync, Versioning, And Events\n\n## General Sync Guarantees\n\n- If two peers eventually hold the same set of operations, they converge to the same state.\n- Delivery order, duplication, and temporary disconnection are transport concerns, not document-consistency failures.\n- For steady-state collaboration, sync updates rather than full snapshots whenever possible.\n\n## Sync Patterns\n\n- Give every peer a unique peer ID. Reusing peer IDs can make updates look duplicated and break convergence.\n- Prefer update exchange over whole snapshots for steady-state sync:\n  - `subscribeLocalUpdates(...)` for push-based transport.\n  - `export({ mode: \"update\", from })` when you track a known sync point.\n- Use `importBatch(...)` for multiple updates or mixed snapshot/update payloads. It performs one diff calculation and emits one combined event.\n- `EphemeralStore` local updates should be transported separately from persisted document updates.\n\n## Version Representations\n\n- `VersionVector`: explicit peer-to-counter map. Best for synchronization, inclusion checks, and self-contained network state.\n- `Frontiers`: compact boundary operations. Best for checkpoints and time travel.\n- Convert between them when needed; vectors are explicit, frontiers are compact.\n\n## State Vs History\n\n- `version()` / `frontiers()`: the current visible DocState.\n- `oplogVersion()` / `oplogFrontiers()`: the latest history known to the OpLog.\n- When attached, state and history usually align.\n- After `checkout(...)`, DocState can diverge from OpLog. That is detached mode.\n\n## Attached Vs Detached\n\n- Detached document state means “viewing history” or otherwise not showing the latest OpLog.\n- Detached container state means “not yet inserted into a document.”\n- These are separate concepts.\n\n## `checkout(...)` Versus `revertTo(...)`\n\n- `checkout(frontiers)`: move document state to an old version. This puts the doc into detached mode.\n- `checkoutToLatest()` or `attach()`: return to the latest attached state.\n- `revertTo(frontiers)`: generate new operations that transform the current document into the target historical state. The doc stays attached.\n\n## Peer IDs\n\n- Every operation ID is `(peerId, counter)`.\n- Never reuse peer IDs across concurrent sessions.\n- Do not use user IDs as peer IDs.\n\n## Operations, Changes, Transactions\n\n- Operations are atomic edits.\n- Changes are logical groups of operations with metadata.\n- Transactions batch operations for event emission and grouping.\n- Loro transactions are not ACID transactions and do not provide rollback semantics.\n- Changes can carry timestamp, commit message, dependencies, peer identity, and other metadata.\n- Consecutive operations may merge into one Change depending on merge rules and timing configuration.\n\n## Import Status\n\n- `ImportStatus.success` tells you what applied.\n- `ImportStatus.pending` tells you what is blocked on missing dependencies.\n- Check pending ranges in out-of-order networks.\n\n## Event Timing Caveat\n\n- Some older examples describe JS events as microtask-delayed.\n- Modern `loro-crdt` dispatches events synchronously at the JS boundary.\n- Check the installed package version and current API docs before relying on old timing examples.\n\n## Event Sources\n\n- Events can be triggered by local commits, imports, and checkouts.\n- Implicit commits happen around operations like export, import, and checkout.\n\n## `subscribePreCommit(...)`\n\n- Use it when commit metadata or change-level hooks must catch both explicit and implicit commits.\n- It is the right place for setting commit message and timestamp.\n- Combined with `exportJsonInIdSpan(...)`, it can drive change hashing or Merkle-DAG-like workflows.\n\n## Timestamps\n\n- Timestamp recording is configurable.\n- `setRecordTimestamp(...)` and `setChangeMergeInterval(...)` affect how changes merge over time.\n- These settings are runtime configuration, not durable document state.\n\n## Inspector\n\n- Use Loro Inspector when you need to browse current state plus full edit history interactively.\n- Prefer it for “what happened to this doc?” debugging before writing custom debug UI.\n\n## Sync Debugging\n\n- If imports arrive out of order, inspect `ImportStatus.pending`.\n- If checkout seems stale, compare DocState version to OpLog version.\n- If commit metadata hooks miss implicit commits, use `subscribePreCommit(...)` rather than adding ad hoc commit calls.\n\n## Undo, Cursor, And Ephemeral Presence\n\n- `UndoManager` is local to one peer. When peer identity changes, the undo and redo stacks reset.\n- Use `onPush` and `onPop` to store selection state together with undo items.\n- Use `groupStart()` and `groupEnd()` when one UX action spans multiple commits.\n- Use `Cursor`, not absolute indices, for selections and carets that must survive concurrent edits.\n- Store two cursors for a selection: anchor and head.\n- Persist the updated cursor returned by `doc.getCursorPos(cursor)` when available; it reduces future replay cost.\n- Use `EphemeralStore` for presence, cursor payloads, hover state, and other collaboration data that must not persist in the CRDT document.\n","skills/loro/references/topic-map.md":"# Topic Map\n\nUse this file to choose the right user-facing chapter inside the unified `loro` skill.\n\n## Route By User Ask\n\n- “I am new to Loro. How do I start?”\n  - Read `fit-and-architecture.md`\n- “Which package, language binding, or platform should I use?”\n  - Read `fit-and-architecture.md`\n- “Should I use Loro here?”\n  - Read `fit-and-architecture.md`\n- “Which container should I choose?”\n  - Read `containers-and-encoding.md`\n- “How should I sync, persist, time-travel, use undo, or debug imports?”\n  - Read `sync-versioning-and-events.md`\n- “How do I integrate rich text editors?”\n  - Read `richtext-and-editors.md`\n- “How do I use loro-mirror with React?”\n  - Read `mirror-and-react.md`\n- “How will Loro behave at scale?”\n  - Read `performance-and-tradeoffs.md`\n\n## Getting Started And Product Fit\n\n- Install choices, language bindings, first example, local-first framing\n  - Read `fit-and-architecture.md`\n- When CRDTs are the wrong fit\n  - Read `fit-and-architecture.md`\n- Package entry points and ecosystem overview\n  - Read `fit-and-architecture.md`\n\n## Containers, Composition, Storage\n\n- Choosing between `LoroMap`, `LoroList`, `LoroMovableList`, `LoroTree`, `LoroCounter`, `LoroText`\n  - Read `containers-and-encoding.md`\n- Composition rules, container states, container IDs, overwrite hazards\n  - Read `containers-and-encoding.md`\n- Snapshot, update, shallow snapshot, updates-in-range\n  - Read `containers-and-encoding.md`\n- Persistence, redaction, history trimming\n  - Read `containers-and-encoding.md`\n\n## Sync, Versions, History, Events\n\n- Peer sync, update exchange, realtime sync, offline merge\n  - Read `sync-versioning-and-events.md`\n- Frontiers, version vectors, OpLog vs DocState\n  - Read `sync-versioning-and-events.md`\n- Checkout, time travel, attached vs detached state\n  - Read `sync-versioning-and-events.md`\n- Peer IDs, import status, transactions, changes, timestamps\n  - Read `sync-versioning-and-events.md`\n- Event timing, `subscribePreCommit`, Inspector\n  - Read `sync-versioning-and-events.md`\n- Undo, cursors, and ephemeral presence\n  - Read `sync-versioning-and-events.md`\n\n## Text, Rich Text, And Editors\n\n- `LoroText`, marks, delta APIs, `updateByLine`, stable selections\n  - Read `richtext-and-editors.md`\n- ProseMirror, Tiptap, CodeMirror, custom editor bindings\n  - Read `richtext-and-editors.md`\n- Rich text internals, style anchors, overlap, expansion rules\n  - Read `richtext-and-editors.md`\n\n## App-State Mirroring\n\n- `loro-mirror`, schemas, `$cid`, `idSelector`, validation\n  - Read `mirror-and-react.md`\n- `loro-mirror-react`, selectors, provider/hooks patterns\n  - Read `mirror-and-react.md`\n\n## Performance And Tradeoffs\n\n- Loading speed, encoded size, memory, update size\n  - Read `performance-and-tradeoffs.md`\n- Conflict-heavy vs low-conflict workloads\n  - Read `performance-and-tradeoffs.md`\n- When to use snapshots, shallow snapshots, or update streams\n  - Read `performance-and-tradeoffs.md`\n","skills/moonbit/README.md":"# MoonBit Agent Skill\n\nThis repository contains a [Agent Skill](https://agentskills.io/home) that teaches AI coding agents the MoonBit language and its toolchain.\n\n## Integrate the Skill into your agent\n\nDifferent AI assistants require different configuration methods. Below are guides for popular coding assistants:\n\n### Codex CLI\n\n```shell\nmkdir -p ~/.codex/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ~/.codex/skills/moonbit\n```\n\nDocumentation: https://developers.openai.com/codex/skills\n\n### Claude Code\n\n```shell\nmkdir -p ~/.claude/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ~/.claude/skills/moonbit\n```\n\nDocumentation: https://code.claude.com/docs/en/skills\n\n### GitHub Copilot for VS Code\n\n```shell\n# enable moonbit skill for current repository\nmkdir -p ./.github/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ./.github/skills/moonbit\n```\n\nNote: Agent Skills support in VS Code is currently in preview and available only in [VS Code Insiders](https://code.visualstudio.com/insiders/). Enable the `chat.useAgentSkills` setting to use Agent Skills. See [Use Agent Skills in VS Code](https://code.visualstudio.com/docs/copilot/customization/agent-skills) for details.\n\n### Cursor & Cursor CLI\n\n> Agent Skills are available only in the Cursor nightly release channel.\n\nDocumentation: https://cursor.com/cn/docs/context/skills\n\n### Gemini CLI\n\nIt seems that Gemini CLI will support agent skills in next release: https://github.com/google-gemini/gemini-cli/issues/15327\n\n","skills/moonbit/SKILL.mbt.md":"SKILL.md","skills/moonbit/SKILL.md":"---\nname: moonbit-agent-guide\ndescription: Guide for writing, refactoring, and testing MoonBit projects. Use when working in MoonBit modules or packages, organizing MoonBit files, using moon tooling (build/check/test/doc/ide), or following MoonBit-specific layout, documentation, and testing conventions.\n---\n\n# MoonBit Project Layouts\n\nMoonBit use the `.mbt` extension and interface files `.mbti`. At\nthe top-level of a MoonBit project there is a `moon.mod.json` file specifying\nthe metadata of the project. The project may contain multiple packages, each\nwith its own `moon.pkg.json` file.\n\n## Example layout\n\n```\nmy_module\n├── moon.mod.json             # Module metadata, source field(optional) specifies the source directory of the module\n├── moon.pkg.json             # Package metadata (each directory is a package like Golang)\n├── README.mbt.md             # Markdown with tested code blocks (`test \"...\" { ... }`)\n├── README.md -> README.mbt.md\n├── cmd                       # Command line directory\n│   └── main\n│       ├── main.mbt\n│       └── moon.pkg.json     # executable package with {\"is_main\": true}\n├── liba/                     # Library packages\n│   └── moon.pkg.json         # Referenced by other packages as `@username/my_module/liba`\n│   └── libb/                 # Library packages\n│       └── moon.pkg.json     # Referenced by other packages as `@username/my_module/liba/libb`\n├── user_pkg.mbt              # Root packages, referenced by other packages as `@username/my_module`\n├── user_pkg_wbtest.mbt       # White-box tests (only needed for testing internal private members, similar to Golang's package mypackage)\n└── user_pkg_test.mbt         # Black-box tests\n└── ...                       # More package files, symbols visible to current package (like Golang)\n```\n\n- **Module**:  `moon.mod.json` file in the project directory.\n  A MoonBit *module* is like a Go module,it is a collection of packages in subdirectories, usually corresponding to a repository or project.\n  Module boundaries matter for dependency management and import paths.\n\n- **Package**: a `moon.pkg.json` file per directory. \n  All subcommands of `moon` will\n  still be executed in the directory of the module (where `moon.mod.json` is\n  located), not the current package.\n  A MoonBit *package* is the actual compilation unit (like a Go package).\n  All source files in the same package are concatenated into one unit.\n  The `package` name in the source defines the package, not the file name.\n  Imports refer to module + package paths, NEVER to file names.\n\n- **Files**:\n  A `.mbt` file is just a chunk of source inside a package.\n  File names do NOT create modules or namespaces.\n  You may freely split/merge/move declarations between files in the same package.\n  Any declaration in a package can reference any other declaration in that package, regardless of file.\n\n\n## Coding/layout rules you MUST follow:\n\n1. Prefer many small, cohesive files over one large file.\n   - Group related types and functions into focused files (e.g. http_client.mbt, router.mbt).\n   - If a file is getting large or unfocused, create a new file and move related declarations into it.\n\n2. You MAY freely move declarations between files inside the same package.\n   - 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.\n   - It is safe to refactor by splitting or merging files inside a package.\n\n3. File names are purely organizational.\n   - Do NOT assume file names define modules, and do NOT use file names in type paths.\n   - Choose file names to describe a feature or responsibility, not to mirror type names rigidly.\n\n4. When adding new code:\n   - Prefer adding it to an existing file that matches the feature.\n   - If no good file exists, create a new file under the same package with a descriptive name.\n   - Avoid creating giant “misc” or “util” files.\n\n5. Tests:\n   - Place tests in dedicated test files (e.g. *_test.mbt) within the appropriate package.\n     For a package, besides `*_test.mbt`files,`*.mbt.md`are also blackbox test files, the code block `mbt check` are treated as test cases, they serve both purposes: documentation and tests.      \n     You may have `README.mbt.md` files with `mbt check` code examples, you can also symlink `README.mbt.md` to `README.md`\n     to make it integrate better with GitHub.\n   - It is fine—and encouraged—to have multiple small test files.\n\n6. Interface files(`pkg.generated.mbti`) \n   `pkg.generated.mbti` is 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.\n   They are generated using `moon info`, 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.\n   \n   You can also use `moon doc @moonbitlang/core/strconv` to explore the public API of a package interactively and `moon ide peek-def 'Array::join'` to read\n   the definition.\n\n# Common Pitfalls to Avoid\n\n- **Don't use uppercase for variables/functions** - compilation error\n- **Don't forget `mut` for mutable record fields** - immutable by default\n- **Don't ignore error handling** - errors must be explicitly handled\n- **Don't use `return` unnecessarily** - last expression is the return value\n- **Don't create methods without Type:: prefix** - methods need explicit type prefix\n- **Don't forget to handle array bounds** - use `get()` for safe access\n- **Don't forget @package prefix when calling functions from other packages**\n- **Don't use ++ or -- (not supported)** - use `i = i + 1` or `i += 1`\n- **Don't add explicit `try` for error-raising functions** - errors propagate automatically (unlike Swift)\n- **Legacy syntax**: Older code may use `function_name!(...)` or `function_name(...)?` - these are deprecated; use normal calls and `try?` for Result conversion\n\n\n# `moon` Essentials\n\n## Essential Commands\n\n- `moon new my_project` - Create new project\n- `moon run cmd/main` - Run main package\n- `moon build` - Build project\n- `moon check` - Type check without building, use it REGULARLY, it is fast\n- `moon info` - Type check and generate `mbti` files\n  run it to see if any public interfaces changed.\n- `moon check --target all` - Type check for all backends\n- `moon add package` - Add dependency\n- `moon remove package` - Remove dependency\n- `moon fmt` - Format code\n\n### Test Commands\n\n- `moon test` - Run all tests\n- `moon test --update` - Update snapshots\n- `moon test -v` - Verbose output with test names\n- `moon test [dirname|filename]` - Test specific directory or file\n- `moon coverage analyze` - Analyze coverage\n- `moon test --filter 'globl'` - Run tests matching filter\n  ```\n  moon test float/float_test.mbt --filter \"Float::*\"\n  ```\n## `README.mbt.md` Generation Guide\n\n- Output `README.mbt.md` in the package directory. \n  `*.mbt.md` file and docstring contents treats `mbt check` specially.\n  `mbt check` block will be included directly as code and also run by `moon check` and `moon test`.  If you don't want the code snippets to be checked, explicit `mbt nocheck` is preferred.\n  If you are only referencing types from the package, you should use `mbt nocheck` which will only be syntax highlighted.\n  Symlink `README.mbt.md` to `README.md` to adapt to systems that expect `README.md`. \n    \n## Testing Guide\n\nUse snapshot tests as it is easy to update when behavior changes.\n\n- **Snapshot Tests**: `inspect(value, content=\"...\")`. If unknown, write `inspect(value)` and run `moon test --update` (or `moon test -u`).\n  - Use regular `inspect()` for simple values (uses `Show` trait)\n  - Use `@json.inspect()` for complex nested structures (uses `ToJson` trait, produces more readable output)\n  - It is encouraged to `inspect` or `@json.inspect` the whole return value of a function if\n    the whole return value is not huge, this makes test simple. You need `impl (Show|ToJson) for YourType` or `derive (Show, ToJson)`.\n- **Update workflow**: After changing code that affects output, run `moon test --update` to regenerate snapshots, then review the diffs in your test files (the `content=` parameter will be updated automatically).\n\n- Black-box by default: Call only public APIs via `@package.fn`. Use white-box tests only when private members matter.\n- Grouping: Combine related checks in one `test \"...\" { ... }` block for speed and clarity.\n- Panics: Name test with prefix `test \"panic ...\" {...}`; if the call returns a value, wrap it with `ignore(...)` to silence warnings.\n- Errors: Use `try? f()` to get `Result[...]` and `inspect` it when a function may raise.\n- Verify: Run `moon test` (or `-u` to update snapshots) and `moon fmt` afterwards.\n\n### Docstring tests \n\nPublic APIs are encouraged to have docstring tests.\n````mbt check\n///|\n/// Get the largest element of a non-empty `Array`.\n///\n/// # Example\n/// ```mbt check\n/// test {\n///   inspect(sum_array([1, 2, 3, 4, 5, 6]), content=\"21\")\n/// }\n/// ```\n///\n/// # Panics\n/// Panics if the `xs` is empty.\npub fn sum_array(xs : Array[Int]) -> Int {\n  xs.fold(init=0, (a, b) => a + b)\n}\n````\n\nThe MoonBit code in docstring will be type checked and tested automatically.\n(using `moon test --update`). In docstrings, `mbt check` should only contain `test` or `async test`.\n\n## Spec-driven Development\n\n- The spec can be written in a readonly `spec.mbt` file (name is conventional, not mandatory) with stub code marked as declarations:\n\n```mbt check\n///|\n#declaration_only\npub type Yaml\n\n///|\n#declaration_only\npub fn Yaml::to_string(y : Yaml) -> String raise {\n  ...\n}\n\n///|\n#declaration_only\npub fn parse_yaml(s : String) -> Yaml raise {\n  ...\n}\n```\n\n- Add `spec_easy_test.mbt`, `spec_difficult_test.mbt` etc to test the spec functions; everything will be type-checked(`moon check`).\n- The AI or students can implement the `declaration_only` functions in different files thanks to our package organization.\n- Run `moon test` to check everything is correct.\n\n- `#declaration_only` is supported for functions, methods, and types.\n- The `pub type Yaml` line is an intentionally opaque placeholder; the implementer chooses its representation.\n- Note the spec file can also contain normal code, not just declarations.\n\n## `moon doc` for API Discovery\n\n**CRITICAL**: `moon doc '<query>'` is your PRIMARY tool for discovering available APIs, functions, types, and methods in MoonBit. Always prefer `moon doc` over other approaches when exploring what APIs are available, it is **more powerful and accurate** than `grep_search` or any regex-based searching tools. \n\n\n`moon doc` uses a specialized query syntax designed for symbol lookup:\n- **Empty query**: `moon doc ''`\n\n  - In a module: shows all available packages in current module, including dependencies and moonbitlang/core\n  - In a package: shows all symbols in current package\n  - Outside package: shows all available packages\n\n- **Function/value lookup**: `moon doc \"[@pkg.]value_or_function_name\"`\n  \n- **Type lookup**: `moon doc \"[@pkg.]Type_name\"` (builtin type does not need package prefix)\n\n- **Method/field lookup**: `moon doc \"[@pkg.]Type_name::method_or_field_name\"`\n\n- **Package exploration**: `moon doc \"@pkg\"`\n  - Show package `pkg` and list all its exported symbols\n  - Example: `moon doc \"@json\"` - explore entire `@json` package\n  - Example: `moon doc \"@encoding/utf8\"` - explore nested package\n\n- **Globbing**: Use `*` wildcard for partial matches, e.g. `moon doc \"String::*rev*\"` to find all String methods with \"rev\" in their name\n\n### `moon doc` Examples\n\n````bash\n# search for String methods in standard library:\n$ moon doc \"String\"\n\ntype String\n\n  pub fn String::add(String, String) -> String\n  # ... more methods omitted ...\n\n$ moon doc \"@buffer\" # list all symbols in  package buffer:\nmoonbitlang/core/buffer\n\nfn from_array(ArrayView[Byte]) -> Buffer\n# ... omitted ...\n\n$ moon doc \"@buffer.new\" # list the specific function in a package:\npackage \"moonbitlang/core/buffer\"\n\npub fn new(size_hint? : Int) -> Buffer\n  Creates ... omitted ...\n\n\n$ moon doc \"String::*rev*\"  # globbing\npackage \"moonbitlang/core/string\"\n\npub fn String::rev(String) -> String\n  Returns ... omitted ...\n  # ... more\n\npub fn String::rev_find(String, StringView) -> Int?\n  Returns ... omitted ...\n````\n**Best practice**: When implementing a feature, start with `moon doc` queries to discover available APIs before writing code. This is faster and more accurate than searching through files.\n\n## `moon ide [peek-def|outline|find-references]` for code navigation and refactoring\n\nFor project-local symbols and navigation, use `moon ide outline .` to scan a package, `moon ide find-references <symbol>` to locate usages, and `moon ide peek-def` for inline definition context and locate toplevel symbols. \n\nThese tools save tokens and more precise than grepping(grep display results in both definition and call site including comments too).\n\n### `moon ide peek-def sym [-loc filename:line:col]` example\n\nWhen the user ask: Can you check if `Parser::read_u32_leb128` is implemented correctly?\n\nIn this case, You can run `moon ide peek-def Parser::read_u32_leb128` to get the definition context: (this is better than `grep` since it searches the whole project by semantics)\n\n``` file src/parse.mbt\nL45:|///|\nL46:|fn Parser::read_u32_leb128(self : Parser) -> UInt raise ParseError {\nL47:|  ...\n...:| }\n```\nNow you want to see the definition of `Parser` struct, you can run:\n\n```bash\n$ moon ide peek-def Parser -loc src/parse.mbt:46:4\nDefinition found at file src/parse.mbt\n  | ///|\n2 | priv struct Parser {\n  |             ^^^^^^\n  |   bytes : Bytes\n  |   mut pos : Int\n  | }  \n  | \n```\nFor the `-loc` argument, the line number must be precise; the column can be approximate since \nthe positonal argument `Parser` helps locate the position.\n\nIf the sym is toplevel symbol, the location can be omitted:\n````bash\n$ moon ide peek-def String::rev\nFound 1 symbols matching 'String::rev':\n\n`pub fn String::rev` in package moonbitlang/core/builtin at /Users/usrname/.moon/lib/core/builtin/string_methods.mbt:1039-1044\n1039 | ///|\n     | /// Returns a new string with the characters in reverse order. It respects\n     | /// Unicode characters and surrogate pairs but not grapheme clusters.\n     | pub fn String::rev(self : String) -> String {\n     |   self[:].rev()\n     | }         \n````\n\n### `moon ide outline [dir|file]` and `moon ide find-references <sym>` for Package Symbols\n\nUse this to scan a package or file for top-level symbols and locate usages without grepping\n\n- `moon ide outline dir` outlines the current package directory (per-file headers)\n- `moon ide outline parser.mbt` outlines a single file\n- Useful when you need a quick inventory of a package, or to find the right file before `goto-definition`\n- `moon ide find-references TranslationUnit` finds all references to a symbol in the current module\n\n```bash\n$ moon ide outline .\nspec.mbt:\n L003 | pub(all) enum CStandard {\n        ...\n L013 | pub(all) struct Position {\n        ...\n```\n\n```bash\n$ moon ide find-references TranslationUnit\n```\n\n## Package Management\n\n### Adding Dependencies\n\n```sh\nmoon add moonbitlang/x        # Add latest version\nmoon add moonbitlang/x@0.4.6  # Add specific version\n```\n\n### Updating Dependencies\n\n```sh\nmoon update                   # Update package index\n```\n\n### Typical Module configurations (`moon.mod.json`)\n\n```json\n{\n  \"name\": \"username/hello\", // Required format for published modules\n  \"version\": \"0.1.0\",\n  \"source\": \".\", // Source directory(optional, default: \".\")\n  \"repository\": \"\", // Git repository URL\n  \"keywords\": [], // Search keywords\n  \"description\": \"...\", // Module description\n  \"deps\": {\n    // Dependencies from mooncakes.io, using`moon add` to add dependencies\n    \"moonbitlang/x\": \"0.4.6\"\n  }\n}\n```\n\n### Typical Package configuration (`moon.pkg.json`)\n\n```json\n{\n  \"is_main\": true,                 // Creates executable when true\n  \"import\": [                      // Package dependencies\n    \"username/hello/liba\",         // Simple import, use @liba.foo() to call functions\n    {\n      \"path\": \"moonbitlang/x/encoding\",\n      \"alias\": \"libb\"              // Custom alias, use @libb.encode() to call functions\n    }\n  ],\n  \"test-import\": [...],            // Imports for black-box tests, similar to import\n  \"wbtest-import\": [...]           // Imports for white-box tests, similar to import (rarely used)\n}\n```\n\nPackages per directory, packages without `moon.pkg.json` are not recognized.\n\n### Package Importing (used in moon.pkg.json)\n\n- **Import format**: `\"module_name/package_path\"`\n- **Usage**: `@alias.function()` to call imported functions\n- **Default alias**: Last part of path (e.g., `liba` for `username/hello/liba`)\n- **Package reference**: Use `@packagename` in test files to reference the\n  tested package\n\n**Package Alias Rules**:\n\n- Import `\"username/hello/liba\"` → use `@liba.function()` (default alias is last path segment)\n- Import with custom alias `{\"path\": \"moonbitlang/x/encoding\", \"alias\": \"enc\"}` → use `@enc.function()`\n- In `_test.mbt` or `_wbtest.mbt` files, the package being tested is auto-imported\n\nExample:\n\n```mbt\n///|\n/// In main.mbt after importing \"username/hello/liba\" in `moon.pkg.json`\nfn main {\n  println(@liba.hello()) // Calls hello() from liba package\n}\n```\n\n### Using Standard Library (moonbitlang/core)\n\n**MoonBit standard library (moonbitlang/core) packages are automatically imported** - DO NOT add them to dependencies:\n\n- ❌ **DO NOT** use `moon add` to add standard library packages like `moonbitlang/core/strconv`\n- ❌ **DO NOT** add standard library packages to `\"deps\"` field of `moon.mod.json`\n- ❌ **DO NOT** add standard library packages to `\"import\"` field of `moon.pkg.json`\n- ✅ **DO** use them directly: `@strconv.parse_int()`, `@list.List`, `@array.fold()`, etc.\n\nIf you get an error like \"cannot import `moonbitlang/core/strconv`\", remove it from imports - it's automatically available.\n\n### Creating Packages\n\nTo add a new package `fib` under `.`:\n\n1. Create directory: `./fib/`\n2. Add `./fib/moon.pkg.json`: `{}` -- Minimal valid moon.pkg.json\n3. Add `.mbt` files with your code\n4. Import in dependent packages:\n\n   ```json\n   {\n     \"import\": [\n        \"username/hello/fib\",\n        ...\n     ]\n   }\n   ```\nFor more advanced topics like `conditional compilation`, `link configuration`, `warning control`, and `pre-build commands`, see `references/advanced-moonbit-build.md`.\n\n# MoonBit Language Tour\n\n## Core facts\n\n- **Expression‑oriented**: `if`, `match`, loops return values; last expression is the return.\n- **References by default**: Arrays/Maps/structs mutate via reference; use `Ref[T]` for primitive mutability.\n- **Blocks**: Separate top‑level items with `///|`. Generate code block‑by‑block.\n- **Visibility**: `fn` private by default; `pub` exposes read/construct as allowed; `pub(all)` allows external construction.\n- **Naming convention**: lower_snake for values/functions; UpperCamel for types/enums; enum variants start UpperCamel.\n- **Packages**: No `import` in code files; call via `@alias.fn`. Configure imports in `moon.pkg.json`.\n- **Placeholders**: `...` is a valid placeholder in MoonBit code for incomplete implementations.\n- **Global values**: immutable by default and generally require type annotations.\n- **Garbage collection**: MoonBit has a GC, there is no lifetime annotation, there's no ownership system.\n  Unlike Rust, like F#, `let mut` is only needed when you want to reassign a variable, not for mutating fields of a struct or elements of an array/map.\n- **Delimit top-level items with `///|` comments** so tools can split the file reliably.\n\n## MoonBit Error Handling (Checked Errors)\n\nMoonBit uses checked error-throwing functions, not unchecked exceptions. All errors are subtype of `Error`, we can declare our own error types by `suberror`.\nUse `raise` in signatures to declare error types and let errors propagate by\ndefault. Use `try?` to convert to `Result[...]` in tests, or `try { } catch { }`\nto handle errors explicitly.\n\n```mbt check\n///|\n/// Declare error types with 'suberror'\nsuberror ValueError String\n\n///|\n/// Tuple struct to hold position info\nstruct Position(Int, Int) derive(ToJson, Show, Eq) \n\n///|\n/// ParseError is subtype of Error\npub(all) suberror ParseError {\n  InvalidChar(pos~:Position, Char) // pos is labeled\n  InvalidEof(pos~:Position)\n  InvalidNumber(pos~:Position, String)\n  InvalidIdentEscape(pos~:Position)\n} derive(Eq, ToJson, Show)\n\n///|\n/// Functions declare what they can throw\nfn parse_int(s : String, position~ : Position) -> Int raise ParseError {\n  // 'raise' throws an error\n  if s is \"\" {\n    raise ParseError::InvalidEof(pos=position)\n  }\n  ... // parsing logic\n}\n\n///|\n/// Just declare `raise` to not track specific error types\nfn div(x : Int, y : Int) -> Int raise {\n  if y is 0 {\n    fail(\"Division by zero\")\n  }\n  x / y\n}\n\n///|\ntest \"inspect raise function\" {\n  let result : Result[Int, Error] = try? div(1, 0) \n  guard result is Err(Failure(msg)) && msg.contains(\"Division by zero\") else {\n    fail(\"Expected error\")\n  }  \n}\n\n// Three ways to handle errors:\n\n///|\n/// Propagate automatically\nfn use_parse(position~: Position) -> Int raise ParseError {\n  let x = parse_int(\"123\", position=position)\n  // Error auto-propagates by default.\n  // Unlike Swift, you do not need to mark `try` for functions that can raise\n  // errors; the compiler infers it automatically. This keeps error handling\n  // explicit but concise.\n  x * 2\n}\n\n///|\n/// Mark `raise` for all possible errors, do not care which error it is.\n/// For quick prototypes, `raise` is acceptable.\nfn use_parse2(position~: Position) -> Int raise {\n  let x = parse_int(\"123\", position=position)\n  x * 2\n}\n\n///|\n/// Convert to Result with try?\nfn safe_parse(s : String, position~: Position) -> Result[Int, ParseError] {\n  let val1 : Result[_] = try? parse_int(s, position=position) // Returns Result[Int, ParseError]\n  // try! is rarely used - it panics on error, similar to unwrap() in Rust\n  // let val2 : Int = try! parse_int(s) // Returns Int otherwise crash\n\n  // Alternative explicit handling:\n  let val3 = try parse_int(s, position=position) catch {\n    err => Err(err)\n  } noraise { // noraise block is optional - handles the success case\n    v => Ok(v)\n  }\n  ...\n}\n\n///|\n/// Handle with try-catch\nfn handle_parse(s : String, position~: Position) -> Int {\n  try parse_int(s, position=position) catch {\n    ParseError::InvalidEof => {\n      println(\"Parse failed: InvalidEof\")\n      -1 // Default value\n    }\n    _ => 2\n  }\n}\n```\n\nImportant: When calling a function that can raise errors, if you only want to\npropagate the error, you do not need any marker; the compiler infers it.\n\n## Integers, Char\n\nMoonBit supports Byte, Int16, Int, UInt16, UInt, Int64, UInt64, etc. When the type is known,\nthe literal can be overloaded:\n\n```mbt check\n///|\ntest \"integer and char literal overloading disambiguation via type in the current context\" {\n  let a0 = 1 // a is Int by default\n  let (int, uint, uint16, int64, byte) : (Int, UInt, UInt16, Int64, Byte) = (\n    1, 1, 1, 1, 1,\n  )\n  assert_eq(int, uint16.to_int())\n  let a1 : Int = 'b' // this also works, a5 will be the unicode value\n  let a2 : Char = 'b'\n}\n```\n## Bytes (Immutable)\n\n```mbt check\n///|\ntest \"bytes literals overloading and indexing\" {\n  let b0 : Bytes = b\"abcd\"\n  let b1 : Bytes = \"abcd\" // b\" prefix is optional, when we know the type\n  let b2 : Bytes = [0xff, 0x00, 0x01] // Array literal overloading\n  guard b0 is [b'a', ..] && b0[1] is b'b' else {\n    // Bytes can be pattern matched as BytesView and indexed\n    fail(\"unexpected bytes content\")\n  }\n  \n}\n```\n## Array (Resizable)\n\n```mbt check\n///|\ntest \"array literals overloading: disambiguation via type in the current context\" {\n  let a0 : Array[Int] = [1, 2, 3] // resizable\n  let a1 : FixedArray[Int] = [1, 2, 3] // Fixed size\n  let a2 : ReadOnlyArray[Int] = [1, 2, 3] \n  let a3 : ArrayView[Int] = [1, 2, 3]\n}\n```\n## String (Immutable UTF-16)\n`s[i]` returns a code unit (UInt16), `s.get_char(i)` returns `Char?`.\nSince MoonBit supports char literal overloading, you can write code snippets like this:\n\n```mbt check\n///|\ntest \"string indexing and utf8 encode/decode\" {\n  let s = \"hello world\"\n  let b0 : UInt16 = s[0]\n  guard(b0 is ('\\n' | 'h' | 'b' | 'a'..='z') && s is [..\"hello\", ..rest]) else {\n    fail(\"unexpected string content\")\n  }\n  guard rest is \" world\" // otherwise will crash (guard without else)\n  \n  // In check mode (expression with explicit type), ('\\n' : UInt16) is valid.\n  \n  // Using get_char for Option handling\n  let b1 : Char? = s.get_char(0)\n  assert_true(b1 is Some('a'..='z'))\n\n  // ⚠️ Important: Variables won't work with direct indexing\n  let eq_char : Char = '='\n  // s[0] == eq_char // ❌ Won't compile - eq_char is not a literal, lhs is UInt while rhs is Char\n  // Use: s[0] == '=' or s.get_char(0) == Some(eq_char)\n  let bytes = @encoding/utf8.encode(\"中文\") // utf8 encode package is in stdlib\n  assert_true(bytes is [0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87])\n  let s2 : String = @encoding/utf8.decode(bytes) // decode utf8 bytes back to String\n  assert_true(s2 is \"中文\")\n  for c in \"中文\" {\n    let _ : Char = c // unicode safe iteration  \n    println(\"char: \\{c}\") // iterate over chars\n  }\n}\n```\n\n### String Interpolation && StringBuilder\n\nMoonBit uses `\\{}` for string interpolation, for custom types, it needs implement trait `Show`\n\n```mbt check\n///|\ntest \"string interpolation basics\" {\n\n  let name : String = \"Moon\"\n  let config = { \"cache\": 123 }\n  let version = 1.0\n  println(\"Hello \\{name} v\\{version}\") // \"Hello Moon v1.0\"\n  // ❌ Wrong - quotes inside interpolation not allowed:\n  // println(\"  - Checking if 'cache' section exists: \\{config[\"cache\"]}\")\n\n  // ✅ Correct - extract to variable first:\n  let has_key = config[\"cache\"] // `\"` not allowed in interpolation\n  println(\"  - Checking if 'cache' section exists: \\{has_key}\")\n  \n  let sb = StringBuilder::new()\n  sb..write_char('[') // dotdot for imperative method chaining\n    ..write_view([1,2,3].map((x) => \"\\{x}\").join(\",\"))\n    ..write_char(']')\n  inspect(sb.to_string(), content=\"[1,2,3]\")\n}\n```\n\nExpressions inside `\\{}` can only be _basic expressions_ (no quotes, newlines, or nested interpolations). String literals are not allowed as it makes lexing too difficult.\n\n\n### Multiple line strings\n\n```mbt check\n///|\ntest \"multi-line string literals\" {  \n  let multi_line_string : String =\n    #|Hello \"world\"\n    #|World\n    #|\n  let multi_line_string_with_interp : String =\n    $|Line 1 \"\"\n    $|Line 2 \\{1+2}\n    $|\n  // no escape in `#|`, \n  // only escape '\\{..}` in `$|`\n  assert_eq(multi_line_string, \"Hello \\\"world\\\"\\nWorld\\n\")  \n  assert_eq(multi_line_string_with_interp, \"Line 1 \\\"\\\"\\nLine 2 3\\n\")\n}\n```\n\n## Map (Mutable, Insertion-Order Preserving)\n\n```mbt check\n///|\ntest \"map literals and common operations\" {\n  // Map literal syntax\n  let map : Map[String, Int] = { \"a\": 1, \"b\": 2, \"c\": 3 }  \n  let empty : Map[String, Int] = {} // Empty map, preferred\n  let also_empty : Map[String, Int] = Map::new()\n  // From array of pairs\n  let from_pairs : Map[String, Int] = Map::from_array([(\"x\", 1), (\"y\", 2)])\n\n  // Set/update value\n  map[\"new-key\"] = 3\n  map[\"a\"] = 10 // Updates existing key\n\n  // Get value - returns Option[T]\n  guard map is { \"new-key\": 3, \"missing\"? : None, .. } else {\n    fail(\"unexpected map contents\")\n  }\n\n  // Direct access (panics if key missing)\n  let value : Int = map[\"a\"] // value = 10\n\n  // Iteration preserves insertion order\n  for k, v in map {\n    println(\"\\{k}: \\{v}\") // Prints: a: 10, b: 2, c: 3, new-key: 3\n  }\n\n  // Other common operations\n  map.remove(\"b\")\n  guard map is { \"a\": 10, \"c\": 3, \"new-key\": 3, .. } && map.length() == 3 else {\n    // \"b\" is gone, only 3 elements left  \n    fail(\"unexpected map contents after removal\")\n  }\n}\n```\n\n## View Types\n\n**Key Concept**: View types (`StringView`, `BytesView`, `ArrayView[T]`) are zero-copy, non-owning read-only slices created with the `[:]` syntax. They don't allocate memory and are ideal for passing sub-sequences without copying data, for function which takes String, Bytes, Array, they also take *View(implicit conversion).\n\n- `String` → `StringView` via `s[:]` or `s[start:end]`\n- `Bytes` → `BytesView` via `b[:]` or `b[start:end]`\n- `Array[T]`, `FixedArray[T]`, `ReadOnlyArray[T] → `ArrayView[T]` via `a[:]` or `a[start:end]`\n\n**Important**: StringView slice is slightly different due to unicode safety:\n`s[a:b]` may raise an error at surrogate boundaries (UTF-16 encoding edge case). You have two options:\n\n- Use `try! s[a:b]` if you're certain the boundaries are valid (crashes on invalid boundaries)\n- Let the error propagate to the caller for proper handling\n\n**When to use views**:\n\n- Pattern matching with rest patterns (`[first, .. rest]`)\n- Passing slices to functions without allocation overhead\n- Avoiding unnecessary copies of large sequences\n\nConvert back with `.to_string()`, `.to_bytes()`, or `.to_array()` when you need ownership. (`moon doc StringView`)\n\n## User defined types(`enum`, `struct`)\n\n```mbt check\n///|\nenum Tree[T] {\n  Leaf(T) // Unlike Rust, no comma here\n  Node(left~ : Tree[T], T, right~ : Tree[T]) // enum can use labels\n} derive(Show, ToJson) // derive traits for Tree\n\n///|\npub fn Tree::sum(tree : Tree[Int]) -> Int {\n  match tree {\n    Leaf(x) => x \n    // we don't need to write Tree::Leaf, when `tree` has a known type\n    Node(left~, x, right~) => left.sum() + x + right.sum() // method invoked in dot notation\n  }\n}\n\n///|\nstruct Point {\n  x : Int\n  y : Int\n} derive(Show, ToJson) // derive traits for Point\n\ntest \"user defined types: enum and struct\" {\n  @json.inspect(Point::{ x: 10, y: 20 }, content=({\"x\":10,\"y\":20}))\n}\n\n```\n\n## Functional `for` loop\n\n\n```mbt check\npub fn binary_search(\n  arr : ArrayView[Int],\n  value : Int,\n) -> Result[Int, Int] {\n  let len = arr.length()\n  // functional for loop:\n  // initial state ; [predicate] ; [post-update] {\n  // loop body with `continue` to update state\n  //} else { // exit block\n  // }\n  // predicate and post-update are optional\n  for i = 0, j = len; i < j; {\n    // post-update is omitted, we use `continue` to update state\n    let h = i + (j - i) / 2\n    if arr[h] < value {\n      continue h + 1, j // functional update of loop state\n    } else {\n      continue i, h // functional update of loop state\n    }\n  } else { // exit of for loop\n    if i < len && arr[i] == value {\n      Ok(i)\n    } else {\n      Err(i)\n    }\n  } where {\n    invariant : 0 <= i && i <= j && j <= len,\n    invariant : i == 0 || arr[i - 1] < value,\n    invariant : j == len || arr[j] >= value,\n    reasoning :\n      #|For a sorted array, the boundary invariants are witnesses:\n      #|  - `arr[i-1] < value` implies all arr[0..i) < value (by sortedness)\n      #|  - `arr[j] >= value` implies all arr[j..len) >= value (by sortedness)\n      #|\n      #|Preservation proof:\n      #|  - When arr[h] < value: new_i = h+1, and arr[new_i - 1] = arr[h] < value ✓\n      #|  - When arr[h] >= value: new_j = h, and arr[new_j] = arr[h] >= value ✓\n      #|\n      #|Termination: j - i decreases each iteration (h is strictly between i and j)\n      #|\n      #|Correctness at exit (i == j):\n      #|  - By invariants: arr[0..i) < value and arr[i..len) >= value\n      #|  - So if value exists, it can only be at index i\n      #|  - If arr[i] != value, then value is absent and i is the insertion point\n      #|\n  }\n}\n\n///|\ntest \"functional for loop control flow\" {\n  let arr : Array[Int] = [1, 3, 5, 7, 9]\n  inspect(binary_search(arr,5), content=\"Ok(2)\") // Array to ArrayView implicit conversion when passing as arguments\n  inspect(binary_search(arr,6), content=\"Err(3)\")\n  // for iteration is supported too\n  for i, v in arr {\n    println(\"\\{i}: \\{v}\") // `i` is index, `v` is value\n  }\n}\n```\nYou are *STRONGLY ENCOURAGED* to use functional `for` loops instead of imperative loops\n*WHENEVER POSSIBLE*, as they are easier to reason about.\n\n### Loop Invariants with `where` Clause\n\nThe `where` clause attaches **machine-checkable invariants** and **human-readable reasoning** to functional `for` loops. This enables formal verification thinking while keeping the code executable. Note for trivial loops, you are encouraged to convert it into `for .. in` so no reasoning is needed.\n\n**Syntax:**\n```mbt nocheck\nfor ... {\n  ...\n} where {\n  invariant : <boolean_expr>,   // checked at runtime in debug builds\n  invariant : <boolean_expr>,   // multiple invariants allowed\n  reasoning : <string>         // documentation for proof sketch\n}\n```\n\n**Writing Good Invariants:**\n\n1. **Make them checkable**: Invariants must be valid MoonBit boolean expressions using loop variables and captured values.\n\n2. **Use boundary witnesses**: For properties over ranges (e.g., \"all elements in arr[0..i) satisfy P\"), check only boundary elements. For sorted arrays, `arr[i-1] < value` implies all `arr[0..i) < value`.\n\n3. **Handle edge cases with `||`**: Use patterns like `i == 0 || arr[i-1] < value` to handle boundary conditions where the check would be out of bounds.\n\n4. **Cover three aspects in reasoning**:\n   - **Preservation**: Why each `continue` maintains the invariants\n   - **Termination**: Why the loop eventually exits (e.g., a decreasing measure)\n   - **Correctness**: Why the invariants at exit imply the desired postcondition\n\n## Label and Optional Parameters\n\nGood example: use labeled and optional parameters\n\n```mbt check\n///|\nfn g(\n  positional : Int,\n  required~ : Int,\n  optional? : Int, // no default => Option\n  optional_with_default? : Int = 42, // default => plain Int\n) -> String {\n  // These are the inferred types inside the function body.\n  let _ : Int = positional\n  let _ : Int = required\n  let _ : Int? = optional\n  let _ : Int = optional_with_default\n  \"\\{positional},\\{required},\\{optional},\\{optional_with_default}\"\n}\n\n///|\ntest {\n  inspect(g(1, required=2), content=\"1,2,None,42\")\n  inspect(g(1, required=2, optional=3), content=\"1,2,Some(3),42\")\n  inspect(g(1, required=4, optional_with_default=100), content=\"1,4,None,100\")\n}\n```\n\nMisuse: `arg : Type?` is not an optional parameter.\nCallers still must pass it (as `None`/`Some(...)`).\n\n```mbt check\n///|\nfn with_config(a : Int?, b : Int?, c : Int) -> String {\n  \"\\{a},\\{b},\\{c}\"\n}\n\n///|\ntest {\n  inspect(with_config(None, None, 1), content=\"None,None,1\")\n  inspect(with_config(Some(5), Some(5), 1), content=\"Some(5),Some(5),1\")\n}\n```\n\nAnti-pattern: `arg? : Type?` (no default => double Option).\nIf you want a defaulted optional parameter, write `b? : Int = 1`, not `b? : Int? = Some(1)`.\n\n```mbt check\n///|\nfn f_misuse(a? : Int?, b? : Int = 1) -> Unit {\n  let _ : Int?? = a // rarely intended\n  let _ : Int = b\n\n}\n// How to fix: declare `(a? : Int, b? : Int = 1)` directly.\n\n///|\nfn f_correct(a? : Int, b? : Int = 1) -> Unit {\n  let _ : Int? = a\n  let _ : Int = b\n\n}\n\n///|\ntest {\n  f_misuse(b=3)\n  f_misuse(a=Some(5), b=2) // works but confusing\n  f_correct(b=2)\n  f_correct(a=5)\n}\n```\n\nBad example: `arg : APIOptions` (use labeled optional parameters instead)\n\n```mbt check\n///|\n/// Do not use struct to group options.\nstruct APIOptions {\n  width : Int?\n  height : Int?\n}\n\n///|\nfn not_idiomatic(opts : APIOptions, arg : Int) -> Unit {\n\n}\n\n///|\ntest {\n  // Hard to use in call site\n  not_idiomatic({ width : Some(5), height : None }, 10)\n  not_idiomatic({ width : None, height : None }, 10)\n}\n```\n\n## More details\n\nFor deeper syntax, types, and examples, read `references/moonbit-language-fundamentals.mbt.md`.\n","skills/moonbit/ide.md":"## Code Navigation with `moon ide`\n\n**ALWAYS use `moon ide` for code navigation in MoonBit projects instead of manual file searching, grep, or semantic search.**\n\nThis tool provides two essential commands for precise code exploration:\n\n### Core Commands\n\n- `moon ide goto-definition` - Find where a symbol is defined\n- `moon ide find-references` - Find all usages of a symbol\n\n### Query System\n\nSymbol lookup uses a two-part query system for precise results:\n\n#### 1. Symbol Name Query (`-query`)\n\nFuzzy search for symbol names with package filtering support:\n\n```bash\n# Find any symbol named 'symbol'\nmoon ide goto-definition -query 'symbol'\n\n# Find methods of a specific type\nmoon ide goto-definition -query 'Type::method'\n\n# Find trait method implementations\nmoon ide goto-definition -query 'Trait for Type with method'\n\n# Find symbol in specific package using @pkg prefix\nmoon ide goto-definition -query '@moonbitlang/x encode'\n\n# Find symbol in multiple packages (searches in pkg1 OR pkg2)\nmoon ide goto-definition -query '@username/mymodule/pkg1 @username/mymodule/pkg2 helper'\n\n# Find symbol in nested package\nmoon ide goto-definition -query '@username/mymodule/mypkg helper'\n```\n\n**Supported symbols**: functions, constants, let bindings, types, structs, enums, traits\n\n**Package filtering**: Prefix your query with `@package_name` to scope the search. Multiple `@pkg` prefixes create an OR condition.\n\n#### 2. Tag-based Filtering (`-tags`)\n\nPre-filter symbols by characteristics before name matching:\n\n**Visibility tags**:\n\n- `pub` - Public symbols\n- `pub all` - Public structs with all public fields\n- `pub open` - Public traits with all methods public\n- `priv` - Private symbols\n\n**Symbol type tags**:\n\n- `type` - Type definitions (struct, enum, typealias, abstract)\n- `error` - Error type definitions\n- `enum` - Enum definitions and variants\n- `struct` - Struct definitions\n- `alias` - Type/function/trait aliases\n- `let` - Top-level let bindings\n- `const` - Constant definitions\n- `fn` - Function definitions\n- `trait` - Trait definitions\n- `impl` - Trait implementations\n- `test` - Named test functions\n\n**Combine tags with logical operators**:\n\n```bash\n# Public functions only\nmoon ide goto-definition -tags 'pub fn' -query 'my_func'\n\n# Functions or constants\nmoon ide goto-definition -tags 'fn | const' -query 'helper'\n\n# Public functions or constants\nmoon ide goto-definition -tags 'pub (fn | const)' -query 'api'\n\n# Public types or traits\nmoon ide goto-definition -tags 'pub (type | trait)' -query 'MyType'\n```\n\n### Practical Examples\n\n```bash\n# Find public function definition\nmoon ide goto-definition -tags 'pub fn' -query 'maximum'\n\n# Find all references to a struct\nmoon ide find-references -tags 'struct' -query 'Rectangle'\n\n# Find trait implementations\nmoon ide goto-definition -tags 'impl' -query 'Show for MyType'\n\n# Find errors in specific package\nmoon ide goto-definition -tags 'error' -query '@mymodule/parser ParseError'\n\n# Find symbol across multiple packages\nmoon ide goto-definition -query '@moonbitlang/x @moonbitlang/core encode'\n\n# Combine package filtering with tags\nmoon ide goto-definition -tags 'pub fn' -query '@username/myapp helper'\n```\n\n### Query Processing\n\nThe tool processes queries in this order:\n\n1. Filter symbols by `-tags` conditions\n2. Extract package scope from `@pkg` prefixes in `-query`\n3. Fuzzy match remaining symbols by name\n4. Return top 3 best matches with location information\n\n**Best Practice**: Start with `-tags` to reduce noise, then use `@pkg` prefixes in `-query` to scope by package for precise navigation.\n","skills/moonbit/references/advanced-moonbit-build.md":"## Conditional Compilation\n\nTarget specific backends/modes in `moon.pkg.json`:\n\n```json\n{\n  \"targets\": {\n    \"wasm_only.mbt\": [\"wasm\"],\n    \"js_only.mbt\": [\"js\"],\n    \"debug_only.mbt\": [\"debug\"],\n    \"wasm_or_js.mbt\": [\"wasm\", \"js\"], // for wasm or js backend\n    \"not_js.mbt\": [\"not\", \"js\"], // for nonjs backend\n    \"complex.mbt\": [\"or\", [\"and\", \"wasm\", \"release\"], [\"and\", \"js\", \"debug\"]] // more complex conditions\n  }\n}\n```\n\n**Available conditions:**\n\n- **Backends**: `\"wasm\"`, `\"wasm-gc\"`, `\"js\"`, `\"native\"`\n- **Build modes**: `\"debug\"`, `\"release\"`\n- **Logical operators**: `\"and\"`, `\"or\"`, `\"not\"`\n\n## Link Configuration\n\n### Basic Linking\n\n```json\n{\n  \"link\": true, // Enable linking for this package\n  // OR for advanced cases:\n  \"link\": {\n    \"wasm\": {\n      \"exports\": [\"hello\", \"foo:bar\"], // Export functions\n      \"heap-start-address\": 1024, // Memory layout\n      \"import-memory\": {\n        // Import external memory\n        \"module\": \"env\",\n        \"name\": \"memory\"\n      },\n      \"export-memory-name\": \"memory\" // Export memory with name\n    },\n    \"wasm-gc\": {\n      \"exports\": [\"hello\"],\n      \"use-js-builtin-string\": true, // JS String Builtin support\n      \"imported-string-constants\": \"_\" // String namespace\n    },\n    \"js\": {\n      \"exports\": [\"hello\"],\n      \"format\": \"esm\" // \"esm\", \"cjs\", or \"iife\"\n    },\n    \"native\": {\n      \"cc\": \"gcc\", // C compiler\n      \"cc-flags\": \"-O2 -DMOONBIT\", // Compile flags\n      \"cc-link-flags\": \"-s\" // Link flags\n    }\n  }\n}\n```\n\n## Warning Control\n\nDisable specific warnings in `moon.mod.json` or `moon.pkg.json`:\n\n```json\n{\n  \"warn-list\": \"-2-29\" // Disable unused variable (2) & unused package (29)\n}\n```\n\n**Common warning numbers:**\n\n- `1` - Unused function\n- `2` - Unused variable\n- `11` - Partial pattern matching\n- `12` - Unreachable code\n- `29` - Unused package\n\nUse `moonc build-package -warn-help` to see all available warnings.\n\n## Pre-build Commands\n\nEmbed external files as MoonBit code:\n\n```json\n{\n  \"pre-build\": [\n    {\n      \"input\": \"data.txt\",\n      \"output\": \"embedded.mbt\",\n      \"command\": \":embed -i $input -o $output --name data --text\"\n    },\n    ... // more embed commands\n  ]\n}\n```\n\nGenerated code example:\n\n```mbt check\n///|\nlet data : String =\n  #|hello,\n  #|world\n  #|\n```\n","skills/moonbit/references/moonbit-language-fundamentals.mbt.md":"# MoonBit Language Fundamentals\n\n\n## Quick reference:\n\n```mbt check\n///|\n/// comments doc string\npub fn sum(x : Int, y : Int) -> Int {\n  x + y\n}\n\n///|\nstruct Rect {\n  width : Int\n  height : Int\n}\n\n///|\nfn Rect::area(self : Rect) -> Int {\n  self.width * self.height\n}\n\n///|\npub impl Show for Rect with output(_self, logger) {\n  logger.write_string(\"Rect\")\n}\n\n///|\nenum MyOption {\n  MyNone\n  MySome(Int)\n} derive(Show, ToJson, Eq, Compare)\n\n///|\n///  match + loops are expressions\ntest \"everything is expression in MoonBit\" {\n  // tuple\n  let (n, opt) = (1, MySome(2))\n  // if expressions return values\n  let msg : String = if n > 0 { \"pos\" } else { \"non-pos\" }\n  let res = match opt {\n    MySome(x) => {\n      inspect(x, content=\"2\")\n      1\n    }\n    MyNone => 0\n  }\n  let status : Result[Int, String] = Ok(10)\n  // match expressions return values\n  let description = match status {\n    Ok(value) => \"Success: \\{value}\"\n    Err(error) => \"Error: \\{error}\"\n  }\n  let array = [1, 2, 3, 4, 5]\n  let mut i = 0 // mutable bindings (local only, globals are immutable)\n  let target = 3\n  // loops return values with 'break'\n  let found : Int? = while i < array.length() {\n    if array[i] == target {\n      break Some(i) // Exit with value\n    }\n    i = i + 1\n  } else { // Value when loop completes normally\n    None\n  }\n  assert_eq(found, Some(2)) // Found at index 2\n}\n\n///|\n/// global bindings\npub let my_name : String = \"MoonBit\"\n\n///|\npub const PI : Double = 3.14159 // constants use UPPER_SNAKE or PascalCase\n\n///|\npub fn maximum(xs : Array[Int]) -> Int raise {\n  // Toplevel functions are *mutually recursive* by default\n  // `raise` annotation means the function would raise any Error\n  //  Only add `raise XXError` when you do need track the specific error type\n  match xs {\n    [] => fail(\"Empty array\") // fail() is built-in for generic errors\n    [x] => x\n    // pattern match over array, the `.. rest` is a rest pattern\n    // it is of type `ArrayView[Int]` which is a slice\n    [x, .. rest] => {\n      let mut max_val = x // `mut` only allowed in local bindings\n      for y in rest {\n        if y > max_val {\n          max_val = y\n        }\n      }\n      max_val // return can be omitted if the last expression is the return value\n    }\n  }\n}\n\n///|\n/// pub(all) means it can be both read and created outside the package\npub(all) struct Point {\n  x : Int\n  mut y : Int\n} derive(Show, ToJson)\n\n///|\npub enum MyResult[T, E] {\n  MyOk(T) // semicolon `;` is optional when we have a newline\n  MyErr(E) // Enum variants must start uppercase\n} derive(Show, Eq, ToJson)\n// pub means it can only be pattern matched outside the package\n// but it can not be created outside the package, use `pub(all)` otherwise\n\n///|\n/// pub (open) means the trait can be implemented for outside packages\npub(open) trait Comparable {\n  compare(Self, Self) -> Int // `Self` refers to the implementing type\n}\n\n///|\ntest \"inspect test\" {\n  let result = sum(1, 2)\n  inspect(result, content=\"3\")\n  // The `content` can be auto-corrected by running `moon test --update`\n  let point = Point::{ x: 10, y: 20 }\n  // For complex structures, use @json.inspect for better readability:\n  @json.inspect(point, content={ \"x\": 10, \"y\": 20 })\n}\n```\n\n\n## Complex Types\n\n```mbt check\n///|\npub type UserId = Int // Int is aliased to UserId - like symlink\n\n///|\n///  Tuple-struct for callback\npub struct Handler((String) -> Unit) // A newtype wrapper\n\n///|\n/// Tuple-struct syntax for single-field newtypes\nstruct Meters(Int) // Tuple-struct syntax\n\n///|\nlet distance : Meters = Meters(100)\n\n///|\nlet raw : Int = distance.0 // Access first field with .0\n\n///|\nstruct Addr {\n  host : String\n  port : Int\n} derive(Show, Eq, ToJson, FromJson)\n\n///|\n/// Structural types with literal syntax\nlet config : Addr = Addr::{\n  // `Type::` can be omitted since the type is already known\n  host: \"localhost\",\n  port: 8080,\n}\n\n\n```\n\n## Common Derivable Traits\n\nMost types can automatically derive standard traits using the `derive(...)` syntax:\n\n- **`Show`** - Enables `to_string()` and string interpolation with `\\{value}`\n- **`Eq`** - Enables `==` and `!=` equality operators\n- **`Compare`** - Enables `<`, `>`, `<=`, `>=` comparison operators\n- **`ToJson`** - Enables `@json.inspect()` for readable test output\n- **`Hash`** - Enables use as Map keys\n\n```mbt check\n///|\nstruct Coordinate {\n  x : Int\n  y : Int\n} derive(Show, Eq, ToJson)\n\n///|\nenum Status {\n  Active\n  Inactive\n} derive(Show, Eq, Compare)\n```\n\n**Best practice**: Always derive `Show` and `Eq` for data types. Add `ToJson` if you plan to test them with `@json.inspect()`.\n\n## Reference Semantics by Default\n\nMoonBit passes most types by reference semantically (the optimizer may copy\nimmutables):\n\n```mbt check\n///|\n///  Structs with 'mut' fields are always passed by reference\nstruct Counter {\n  mut value : Int\n}\n\n///|\nfn increment(c : Counter) -> Unit {\n  c.value += 1 // Modifies the original\n}\n\n///|\n/// Arrays and Maps are mutable references\nfn modify_array(arr : Array[Int]) -> Unit {\n  arr[0] = 999 // Modifies original array\n}\n\n///|\ntest \"reference semantics\" {\n  let counter : Ref[Int] = Ref::{ val: 0 }\n  counter.val += 1\n  assert_true(counter.val is 1)\n  let arr : Array[Int] = [1, 2, 3] // unlike Rust, no `mut` keyword needed\n  modify_array(arr)\n  assert_true(arr[0] is 999)\n  let mut x = 3 // `mut` neeed for re-assignment to the bindings\n  x += 2\n  assert_true(x is 5)\n}\n```\n\n## Pattern Matching\n\n```mbt check\n///|\n#warnings(\"-unused_value\")\ntest \"pattern match over Array, struct and StringView\" {\n  let arr : Array[Int] = [10, 20, 25, 30]\n  match arr {\n    [] => ... // empty array\n    [single] => ... // single element\n    [first, .. middle, rest] => {\n      let _ : ArrayView[Int] = middle // middle is ArrayView[Int]  \n      assert_true(first is 10 && middle is [20, 25] && rest is 30)\n    }\n  }\n  fn process_point(point : Point) -> Unit {\n    match point {\n      { x: 0, y: 0 } => ...\n      { x, y } if x == y => ...\n      { x, .. } if x < 0 => ...\n      ...\n    }\n  }\n  /// StringView pattern matching for parsing\n  fn is_palindrome(s : StringView) -> Bool {\n    loop s {\n      [] | [_] => true\n      [a, .. rest, b] if a == b => continue rest\n      // a is of type Char, rest is of type StringView\n      _ => false\n    }\n  }\n\n\n}\n```\n\n## Functional `loop` control flow\n\nThe `loop` construct is unique to MoonBit:\n\n```mbt check\n///|\n/// Functional loop with pattern matching on loop variables\n/// @list.List is from the standard library\nfn sum_list(list : @list.List[Int]) -> Int {\n  loop (list, 0) {\n    (Empty, acc) => acc // Base case returns accumulator\n    (More(x, tail=rest), acc) => continue (rest, x + acc) // Recurse with new values\n  }\n}\n\n///|\n///  Multiple loop variables with complex control flow\nfn find_pair(arr : Array[Int], target : Int) -> (Int, Int)? {\n  loop (0, arr.length() - 1) {\n    (i, j) if i >= j => None\n    (i, j) => {\n      let sum = arr[i] + arr[j]\n      if sum == target {\n        Some((i, j)) // Found pair\n      } else if sum < target {\n        continue (i + 1, j) // Move left pointer\n      } else {\n        continue (i, j - 1) // Move right pointer\n      }\n    }\n  }\n}\n```\n\n**Note**: You must provide a payload to `loop`. If you want an infinite loop, use `while true { ... }` instead. The syntax `loop { ... }` without arguments is invalid.\n\n\n## Methods and Traits\n\nMethods use `Type::method_name` syntax, traits require explicit implementation:\n\n```mbt check\n///|\nstruct Rectangle {\n  width : Double\n  height : Double\n}\n\n///|\n// Methods are prefixed with Type::\nfn Rectangle::area(self : Rectangle) -> Double {\n  self.width * self.height\n}\n\n///|\n/// Static methods don't need self\nfn Rectangle::new(w : Double, h : Double) -> Rectangle {\n  { width: w, height: h }\n}\n\n///|\n/// Show trait now uses output(self, logger) for custom formatting\n/// to_string() is automatically derived from this\npub impl Show for Rectangle with output(self, logger) {\n  logger.write_string(\"Rectangle(\\{self.width}x\\{self.height})\")\n}\n\n///|\n/// Traits can have non-object-safe methods\ntrait Named {\n  name() -> String // No 'self' parameter - not object-safe\n}\n\n///|\n/// Trait bounds in generics\nfn[T : Show + Named] describe(value : T) -> String {\n  \"\\{T::name()}: \\{value.to_string()}\"\n}\n\n///|\n///  Trait implementation\nimpl Hash for Rectangle with hash_combine(self, hasher) {\n  hasher..combine(self.width)..combine(self.height)\n}\n```\n\n## Operator Overloading\n\nMoonBit supports operator overloading through traits:\n\n```mbt check\n///|\nstruct Vector(Int, Int)\n\n///|\n/// Implement arithmetic operators\npub impl Add for Vector with add(self, other) {\n  Vector(self.0 + other.0, self.1 + other.1)\n}\n\n///|\nstruct Person {\n  age : Int\n} derive(Eq)\n\n///|\n/// Comparison operators\npub impl Compare for Person with compare(self, other) {\n  self.age.compare(other.age)\n}\n\n///|\ntest \"overloading\" {\n  let v1 : Vector = Vector(1, 2)\n  let v2 : Vector = Vector(3, 4)\n  let _v3 : Vector = v1 + v2\n\n}\n```\n\n## Access Control Modifiers\n\nMoonBit has fine-grained visibility control:\n\n```mbt check\n///|\n/// `fn` defaults to Private - only visible in current package\nfn internal_helper() -> Unit {\n  ...\n}\n\n///|\npub fn get_value() -> Int {\n  ...\n}\n\n///|\n// Struct (default) - type visible, implementation hidden\nstruct DataStructure {}\n\n///|\n/// `pub struct` defaults to readonly - can read, pattern match, but not create\npub struct Config {}\n\n///|\n///  Public all - full access\npub(all) struct Config2 {}\n\n///|\n/// Abstract trait (default) - cannot be implemented by\n/// types outside this package\npub trait MyTrait {}\n\n///|\n///  Open for extension\npub(open) trait Extendable {}\n```\n","skills/moonbit/references/moonbit-language-fundamentals.md":"moonbit-language-fundamentals.mbt.md"},"files":{"AGENTS.md":"# Repository Guidelines\n\n## Project Snapshot\n\nLoro is a Rust CRDT workspace with JS/WASM packaging and a MoonBit codec.\n\n- `crates/loro`: public Rust API; avoid breaking downstream users.\n- `crates/loro-internal`: core CRDT logic. Read its\n  [AGENTS.md](crates/loro-internal/AGENTS.md) before changing import/export,\n  encoding, state, diff, checkout, or replay behavior.\n- `crates/loro-wasm`: `loro-crdt` WASM/TypeScript package. Read its\n  [AGENTS.md](crates/loro-wasm/AGENTS.md) before changing bindings, exports,\n  wrappers, or build scripts.\n- `crates/delta`, `crates/rle`, `crates/kv-store`, `crates/fractional_index`,\n  `crates/loro-common`, and `packages/fractional-index`: shared primitives and\n  packages.\n- `moon/`: MoonBit Loro binary codec; use [skills/moonbit/SKILL.md](skills/moonbit/SKILL.md).\n\n## Context Index\n\n- Undo/redo item boundaries when remote edits make an inverse a no-op:\n  [context/undo-history-boundaries.md](context/undo-history-boundaries.md).\n- Rust undo failure rollback and transaction writer serialization:\n  [context/undo-atomicity.md](context/undo-atomicity.md).\n- Encoding/import/export modes, current vs outdated formats, shallow snapshots:\n  [context/internal-encoding.md](context/internal-encoding.md).\n- Mergeable container model, marker/cid rules, tests, and common pitfalls:\n  [context/mergeable-containers.md](context/mergeable-containers.md).\n- `import_batch` force-detach, batch-wide rollback scope, and the never-exit-detached\n  invariant: [context/import-batch-atomicity.md](context/import-batch-atomicity.md).\n- Which root containers are visible (history-touched vs handle-acquired), and\n  why replays materialize empty roots:\n  [context/root-container-visibility.md](context/root-container-visibility.md).\n- Imports that reuse local op ids (a shared peer id): the known-history check,\n  what counts as equal, and what it cannot catch:\n  [context/import-peer-id-reuse.md](context/import-peer-id-reuse.md).\n- `apply_diff`/`revert_to` rollback of a failed batch, reused op ids, other\n  threads: [context/apply-diff-atomicity.md](context/apply-diff-atomicity.md).\n- Movable-list `Move`/`Set` import validation, and why a move of a deleted element\n  is applied rather than rejected:\n  [context/movable-list-op-validation.md](context/movable-list-op-validation.md).\n- Shallow-snapshot dead-style redaction (null-only, both-expand exclusion,\n  root-whitelisted latest state):\n  [context/shallow-snapshot-style-redaction.md](context/shallow-snapshot-style-redaction.md).\n- Rich-text insert positions next to style anchors, the insert cursor cache,\n  and delete `start_id`s: [context/richtext-insert-positions.md](context/richtext-insert-positions.md).\n- Tree diff cache transitions and why their lamport window comes from the two\n  versions, not the replay base: [context/tree-checkout-window.md](context/tree-checkout-window.md).\n- Tree event invariants (revived subtrees get `Create`s) and the two event\n  paths, diff-calculator vs raw ops: [context/tree-events.md](context/tree-events.md).\n- Deep tree traversal, snapshot order, and iterative result disposal:\n  [context/tree-depth.md](context/tree-depth.md).\n- loro.js tree diff item order, index counting, apply resolution, and batch dry-run:\n  [context/loro-js-tree-diff.md](context/loro-js-tree-diff.md).\n- loro.js concurrent tree moves, skipped cycles, replay, checkout, and undo:\n  [context/loro-js-tree-moves.md](context/loro-js-tree-moves.md).\n- User-facing Loro usage, sync, editor integration, and performance guidance:\n  [skills/loro/SKILL.md](skills/loro/SKILL.md).\n- Pure TypeScript runtime indexes, complexity contracts, benchmarks, and remaining gaps:\n  [context/loro-js-performance.md](context/loro-js-performance.md).\n- loro.js vs Rust randomized Text differential tests and the Rust behaviors they\n  work around: [context/loro-js-rust-differential.md](context/loro-js-rust-differential.md).\n- loro.js rich-text style anchors, entity positions, and Rust's insert/delete/mark\n  position rules: [context/loro-js-richtext-anchors.md](context/loro-js-richtext-anchors.md).\n- loro.js multi-peer differential fuzzing against replay, checkout, event, and\n  Rust/WASM oracles: [context/loro-js-differential-fuzz.md](context/loro-js-differential-fuzz.md).\n- loro.js MovableList model, the MovableList Rust differential suite\n  (`loro-js/tests/differential/`), and known loro.js/Rust divergences:\n  [context/loro-js-movable-list.md](context/loro-js-movable-list.md).\n- WASM panic/OOM reporting channels, `__wbindgen_start` glue invariant, and\n  trap-testing recipes:\n  [context/wasm-error-reporting.md](context/wasm-error-reporting.md).\n- WASM container id wrapper identity, lazy caching, and benchmark:\n  [context/wasm-container-id-cache.md](context/wasm-container-id-cache.md).\n- Bounded decoded-value cache in `InnerStore` (second-chance FIFO, eviction\n  safety contract, loro-dev/loro#1092):\n  [context/container-value-cache.md](context/container-value-cache.md).\n- Deep plain value decoding, Drop, and WASM conversion stack safety:\n  [context/deep-value-stack-safety.md](context/deep-value-stack-safety.md).\n- How the arena learns a container's parent (parsed changes, state KV, the op\n  log's creator resolver), its locking (including `ChangeStore`'s lock order),\n  and import rollback: [context/arena-parent-links.md](context/arena-parent-links.md).\n- Why a failed import's rollback keeps arena indices (DocState, caches and handlers\n  are keyed by them) and what it drops instead:\n  [context/failed-import-arena-indices.md](context/failed-import-arena-indices.md).\n- Which deletions `DocState::is_deleted` caches, and how tree/movable-list\n  children are revived: [context/dead-container-cache.md](context/dead-container-cache.md).\n- Movable-list `apply_diff`/undo: delete + re-insert of a child becomes a move,\n  cursor invariant, pitfalls: [context/movable-list-apply-diff.md](context/movable-list-apply-diff.md).\n- Unknown container types (newer-version containers): never created locally,\n  `apply_diff`/undo pre-check, events, test forging:\n  [context/unknown-containers.md](context/unknown-containers.md).\n- Why parsed change blocks keep text and list values out of doc-wide arenas\n  (`ValueSlice`, tracker tables): [context/text-arena-growth.md](context/text-arena-growth.md).\n- User callbacks that panic (subscribers, pre-commit, local updates): no poisoned\n  locks, lost events or hangs: [context/callback-panics.md](context/callback-panics.md).\n- Context backlog: [context/CONTEXT-GAPS.md](context/CONTEXT-GAPS.md).\n\n## Commands\n\n- JS deps: `pnpm install --frozen-lockfile`.\n- Rust build/check/format/lint: `cargo build`, `cargo check -p loro-internal`,\n  `cargo fmt --all`, `pnpm check`.\n- Rust tests: `pnpm test`; internal doctests: `cargo test -p loro-internal --doc`.\n- Loom: `pnpm test-loom`.\n- WASM: `pnpm release-wasm`, or `pnpm -C crates/loro-wasm build-dev`.\n- Bundlers after WASM packaging changes: `pnpm test-bundlers`; browser runtime:\n  `pnpm --dir examples/bundler-smoke-tests run test:browser`.\n- Fractional-index TS: `pnpm test-fractional-index`.\n- Fuzz smoke: `pnpm run-fuzz-corpus`.\n- MoonBit codec, when `moon` is available: from `moon/`, run `moon check`,\n  `moon test`, `moon fmt`.\n\nUse narrow checks first. Ask before broad fuzzing or long browser matrices.\n\n## Working Rules\n\n- Start with `git status --short --branch`; treat uncommitted changes as user\n  work unless you made them.\n- Before editing, read every `AGENTS.md` from root to target directory. Keep\n  `CLAUDE.md` as a symlink to the nearest `AGENTS.md`.\n- Use `rg` / `rg --files` for search.\n- Public API changes in `loro` or `loro-crdt` should be backward-compatible when\n  possible. Prefer new `try_*` APIs over breaking signatures.\n- Internal corruption should fail fast; invalid external input should return\n  `Err`. Returning wrong state is worse than panicking on an impossible internal\n  invariant.\n- Add regression tests near behavior: `crates/loro/tests`,\n  `crates/loro-internal/tests`, module tests, `crates/loro-wasm/tests`, or\n  `moon/loro_codec/*_test.mbt`.\n- Add a changeset for publishing behavior or package output changes.\n- Do not hand-edit generated WASM package output; regenerate it with package\n  scripts.\n\n## Self-Maintained Agent Context\n\n- Treat \"why was that hard to find?\" as a context bug. Add a nearby\n  `AGENTS.md` pointer or a `context/` article, or append a line to\n  [context/CONTEXT-GAPS.md](context/CONTEXT-GAPS.md).\n- Keep root context short. If an `AGENTS.md` grows past about 4000 characters, move\n  detail into a linked `context/` article.\n- Header context articles with `Verified against code YYYY-MM-DD`, anchor claims\n  to files/symbols, and link them from root plus the nearest per-directory\n  `AGENTS.md`.\n- If code changes make an `AGENTS.md` or context article stale, update the docs\n  in the same change.\n- When a commit needs non-obvious rationale, land that rationale in the nearest\n  context file and keep the commit message as a pointer.\n\n## Commit And PR Notes\n\nHistory uses short imperative commits, often prefixed by `fix:`, `test:`,\n`chore:`, or `refactor:`. PRs should include summary, rationale, validation, and\nlinked issues or traces when relevant.\n- Structured WASM reads, node identity, ranges and performance responsibilities:\n  [context/wasm-container-tree.md](context/wasm-container-tree.md).\n","CLAUDE.md":"AGENTS.md","loro-js/AGENTS.md":"# loro.js\n\nPure TypeScript implementation of Loro (`loro-js/src`). It must read and write\nthe same binary and JSON data as Rust (`loro-crdt`) and give the same results.\n\n## Context\n\n- Concurrent tree moves, skipped cycles, replay, checkout, and undo:\n  [context/loro-js-tree-moves.md](../context/loro-js-tree-moves.md).\n- Undo/redo no-op return values and item boundaries:\n  [context/undo-history-boundaries.md](../context/undo-history-boundaries.md).\n- Index structures, complexity contracts, and benchmarks:\n  [context/loro-js-performance.md](../context/loro-js-performance.md).\n- Randomized Text comparison with Rust (build the nodejs WASM package first):\n  [context/loro-js-rust-differential.md](../context/loro-js-rust-differential.md).\n- Multi-peer fuzzing of all containers against replay, checkout, event, and\n  shallow-snapshot oracles, optionally in lockstep with Rust:\n  [context/loro-js-differential-fuzz.md](../context/loro-js-differential-fuzz.md).\n- MovableList model (Rust's positions + LWW elements) and its multi-peer Rust\n  differential suite (`tests/differential/`):\n  [context/loro-js-movable-list.md](../context/loro-js-movable-list.md).\n- Rich text: style anchors live in the Text sequence and op positions count\n  them. Read [context/loro-js-richtext-anchors.md](../context/loro-js-richtext-anchors.md)\n  before changing Text positions, marks, or Text snapshot state.\n- Encoding formats: [context/internal-encoding.md](../context/internal-encoding.md)\n  and `docs/encoding*.md`.\n\n## Interop fixtures\n\n- Rust output read by loro.js: `tests/fixtures/rust/*.blob` and `*.json`.\n- loro.js output read by Rust: `pnpm fixtures:rewrite` runs\n  `scripts/rewrite-rust-fixture.mjs`, which writes `tests/fixtures/rust/*.ts.blob`;\n  `crates/loro/tests/loro_js_interop.rs` imports them. Container state encoders\n  live in `src/runtime/document.ts` (`#containerState`) and must follow\n  `docs/encoding-container-states.md`.\n- loro.js 0.2 output read by later versions: `scripts/write-legacy-fixtures.mjs`\n  writes `tests/fixtures/loro-js-0.2/` with a 0.2 build; `tests/legacy-data.test.ts`\n  pins that loro.js and Rust read it the same way. Later versions read 0.2 data\n  with Rust's semantics, with no version marker (README \"Upgrading from 0.2\"; the\n  decision is in [context/loro-js-rust-differential.md](../context/loro-js-rust-differential.md)).\n\n## Commands\n\nFrom `loro-js/`: `pnpm test`, `pnpm typecheck`, `pnpm lint`, `pnpm format:check`,\n`pnpm build`, or `pnpm check` for all of them. From the root, `pnpm test-loro-js`\nruns the tests and fails if the Rust WASM reference is missing (CI runs it after\n`release-wasm`). Benchmarks: `pnpm bench:b4`,\n`pnpm bench:complexity -- 1000,2000,4000,8000`.\n","loro-js/CLAUDE.md":"AGENTS.md","packages/fractional-index/README.md":"# @loro-dev/fractional-index\n\nTypeScript implementation of Loro's Rust `loro_fractional_index` crate.\n\nThis package creates compact string positions that sort lexicographically. The\npublic API always accepts and returns canonical uppercase hex strings, so indexes\nare easy to store, compare, serialize, and use as object or map keys.\n\n- No runtime dependencies.\n- ESM output with TypeScript declarations.\n- Public indexes are plain strings.\n- Generated strings are byte-for-byte compatible with the Rust crate's\n  `Display` output.\n- Golden tests are generated from the Rust implementation in this repository.\n\n## Install\n\n```sh\npnpm add @loro-dev/fractional-index\n```\n\n```sh\nnpm install @loro-dev/fractional-index\n```\n\n```sh\nyarn add @loro-dev/fractional-index\n```\n\n## Quick Start\n\n```ts\nimport { FractionalIndex, compare } from \"@loro-dev/fractional-index\";\n\nconst first = FractionalIndex.default();\nconst before = FractionalIndex.newBefore(first);\nconst after = FractionalIndex.newAfter(first);\nconst middle = FractionalIndex.newBetween(first, after);\n\nconsole.log(first); // \"80\"\nconsole.log(before); // \"7F80\"\nconsole.log(after); // \"8180\"\nconsole.log(middle); // \"817F80\"\n\nconst ordered = [after, first, before].sort(compare);\nconsole.log(ordered); // [\"7F80\", \"80\", \"8180\"]\n\nJSON.stringify({ position: first }); // \"{\\\"position\\\":\\\"80\\\"}\"\n```\n\nGenerated indexes are canonical uppercase hex strings. For generated values,\nordinary string comparison also follows byte order:\n\n```ts\nbefore < first; // true\nfirst < after; // true\n```\n\nUse `compare(a, b)` when sorting values that may have been parsed from external\ninput, because it compares by bytes after parsing.\n\n## Data Model\n\nAn index string is the uppercase hex encoding of the same bytes used by Rust.\nGenerated indexes include the `0x80` terminator byte.\n\n```ts\nconst index = FractionalIndex.default(); // \"80\"\n```\n\nThe public API does not expose byte arrays. Internally, the implementation still\nuses bytes to stay aligned with the Rust algorithm.\n\n## Creating Indexes\n\n### Default\n\n```ts\nconst index = FractionalIndex.default(); // \"80\"\n```\n\nThis matches `FractionalIndex::default()` in Rust.\n\n### Before And After\n\n```ts\nconst base = FractionalIndex.default();\n\nconst before = FractionalIndex.newBefore(base); // \"7F80\"\nconst after = FractionalIndex.newAfter(base); // \"8180\"\n```\n\n### Between Two Indexes\n\n```ts\nconst left = FractionalIndex.default();\nconst right = FractionalIndex.newAfter(left);\nconst between = FractionalIndex.newBetween(left, right);\n\nif (between) {\n  console.log(left < between); // true for canonical generated strings\n  console.log(between < right); // true\n}\n```\n\n`newBetween()` returns `undefined` when the Rust crate would return `None`.\nFor byte sequences that trigger a Rust panic, this package throws an `Error`\ninstead of returning a misleading value.\n\n### General Constructor\n\n`FractionalIndex.new(lower, upper)` mirrors Rust's `FractionalIndex::new`:\n\n```ts\nFractionalIndex.new(undefined, undefined); // default \"80\"\nFractionalIndex.new(existing, undefined); // after existing\nFractionalIndex.new(undefined, existing); // before existing\nFractionalIndex.new(left, right); // between left and right\n```\n\n`null` and `undefined` are both treated as an absent bound.\n\n## Generating Many Indexes\n\nUse `generateNEvenly()` when you know how many positions you need. It produces\nstrictly sorted indexes inside the open interval `(lower, upper)`.\n\n```ts\nconst values = FractionalIndex.generateNEvenly(undefined, undefined, 5);\n\nconsole.log(values);\n// [\"7E80\", \"7F80\", \"80\", \"817F80\", \"8180\"]\n```\n\nBounded generation:\n\n```ts\nconst lower = FractionalIndex.newBefore(FractionalIndex.default());\nconst upper = FractionalIndex.newAfter(FractionalIndex.default());\n\nconst values = FractionalIndex.generateNEvenly(lower, upper, 100);\n```\n\nThe method returns `undefined` if both bounds are provided and `lower >= upper`.\n\n## Jitter\n\nThe Rust crate can append random bytes after the terminator. This package exposes\nthe same behavior through `JitterOptions`.\n\n```ts\nconst index = FractionalIndex.jitterDefault({ jitter: 3 });\nconsole.log(index.length); // 8 hex chars: 0x80 plus 3 random bytes\n```\n\nFor deterministic tests or replicated fixtures, provide `randomByte`:\n\n```ts\nconst bytes = [1, 2, 3];\nlet offset = 0;\n\nconst index = FractionalIndex.jitterDefault({\n  jitter: 3,\n  randomByte: () => bytes[offset++],\n});\n\nconsole.log(index); // \"80010203\"\n```\n\nJitter variants:\n\n```ts\nFractionalIndex.jitterDefault({ jitter: 2 });\nFractionalIndex.newJitter(lower, upper, { jitter: 2 });\nFractionalIndex.newBeforeJitter(index, { jitter: 2 });\nFractionalIndex.newAfterJitter(index, { jitter: 2 });\nFractionalIndex.newBetweenJitter(left, right, { jitter: 2 });\nFractionalIndex.generateNEvenlyJitter(lower, upper, 10, { jitter: 2 });\n```\n\n`jitter` and `randomByte` must both be integers in `[0, 255]`, matching Rust's\n`u8` boundary.\n\n## Parsing And Serialization\n\n```ts\nconst fromHex = FractionalIndex.fromHexString(\"80ff\");\nconsole.log(fromHex); // \"80FF\"\n```\n\nCompatibility notes:\n\n- `fromHexString()` accepts uppercase or lowercase hex and returns canonical\n  uppercase hex.\n- Like Rust, `fromHexString()` ignores a trailing odd nibble. `\"80A\"` parses as\n  `\"80\"`.\n- Invalid hex pairs throw `SyntaxError`.\n\n## API Reference\n\n```ts\ntype FractionalIndex = string;\n\ninterface JitterOptions {\n  jitter?: number;\n  randomByte?: () => number;\n}\n```\n\n### Namespace API\n\n```ts\nFractionalIndex.TERMINATOR; // 128\n\nFractionalIndex.default(): FractionalIndex;\nFractionalIndex.fromHexString(hex): FractionalIndex;\n\nFractionalIndex.new(lower?, upper?): FractionalIndex | undefined;\nFractionalIndex.newBefore(index): FractionalIndex;\nFractionalIndex.newAfter(index): FractionalIndex;\nFractionalIndex.newBetween(left, right): FractionalIndex | undefined;\nFractionalIndex.generateNEvenly(lower, upper, n): FractionalIndex[] | undefined;\n\nFractionalIndex.jitterDefault(options?): FractionalIndex;\nFractionalIndex.newJitter(lower, upper, options?): FractionalIndex | undefined;\nFractionalIndex.newBeforeJitter(index, options?): FractionalIndex;\nFractionalIndex.newAfterJitter(index, options?): FractionalIndex;\nFractionalIndex.newBetweenJitter(left, right, options?): FractionalIndex | undefined;\nFractionalIndex.generateNEvenlyJitter(\n  lower,\n  upper,\n  n,\n  options?,\n): FractionalIndex[] | undefined;\n\nFractionalIndex.compare(left, right): number;\nFractionalIndex.equals(left, right): boolean;\nFractionalIndex.isFractionalIndex(value): value is FractionalIndex;\n```\n\n### Top-Level Helpers\n\nNamespace methods are also available as named exports. Since `new` is a\nJavaScript keyword, `FractionalIndex.new()` is exported as `newIndex()`:\n\n```ts\ndefaultIndex();\nfromHexString(hex);\ncompare(left, right);\nequals(left, right);\nnewIndex(lower, upper);\nnewBefore(index);\nnewAfter(index);\nnewBetween(left, right);\ngenerateNEvenly(lower, upper, n);\njitterDefault(options);\nnewJitter(lower, upper, options);\nnewBeforeJitter(index, options);\nnewAfterJitter(index, options);\nnewBetweenJitter(left, right, options);\ngenerateNEvenlyJitter(lower, upper, n, options);\nisFractionalIndex(value);\n```\n\n## Testing Against Rust\n\nThe golden fixture used by the TypeScript tests is generated from the Rust crate:\n\n```sh\npnpm --filter @loro-dev/fractional-index fixtures:generate\npnpm --filter @loro-dev/fractional-index check\n```\n\nThe fixture covers:\n\n- Default, before, after, and between generation.\n- Long before/after chains.\n- `generate_n_evenly` for bounded and unbounded ranges.\n- `None` cases.\n- Rust panic edge cases.\n- Jitter byte placement.\n- Hex serialization.\n\n## Development Commands\n\nThis package uses Vite+ (`vp`) for build, test, lint, and format orchestration.\n\n```sh\npnpm --filter @loro-dev/fractional-index format\npnpm --filter @loro-dev/fractional-index lint\npnpm --filter @loro-dev/fractional-index typecheck\npnpm --filter @loro-dev/fractional-index test\npnpm --filter @loro-dev/fractional-index build\npnpm --filter @loro-dev/fractional-index check\n```\n\n`lint` runs oxlint in type-aware mode with warnings denied. `format` and\n`format:check` use oxfmt. `typecheck` uses `tsgo`. `build` runs `vp pack` and\nemits the ESM bundle, declarations, and sourcemap to `dist/`.\n\n## Performance Notes\n\nString indexes are optimized for JavaScript ergonomics: comparison, JSON,\nstorage, and use as keys are all straightforward. The implementation parses\nstrings to byte arrays internally for generation so it can stay aligned with the\nRust byte algorithm. For the expected workload of normal list/tree positioning,\nthis keeps the API simple without a meaningful practical performance cost.\n","skills/loro/SKILL.md":"---\nname: loro\ndescription: \"Practical guide for helping app developers evaluate, adopt, and use Loro for local-first collaboration. Use when Codex needs to answer questions or write examples for `loro-crdt`, `loro`, `loro-prosemirror`, `loro-codemirror`, `loro-mirror`, language bindings such as Swift/Python/C#/Go/React Native, or Loro-powered apps about: (1) Deciding whether Loro fits a product, (2) Getting started in JavaScript/TypeScript, Rust, or another supported binding, (3) Choosing CRDT containers and document structure, (4) Designing sync, persistence, snapshots, versioning, undo, presence, or time travel, (5) Integrating rich-text editors and stable selections, (6) Mirroring app state with React, or (7) Understanding performance and tradeoffs.\"\n---\n\n# Loro\n\nUse this skill to help users build applications with Loro. Start from the user's product goal, then choose the narrowest chapter that answers it. Load a second chapter only when the task crosses domains.\n\n## Select A Chapter\n\n- Read [references/topic-map.md](references/topic-map.md) if the task is broad and you need to route it.\n- Read [references/fit-and-architecture.md](references/fit-and-architecture.md) for product fit, installation, language/package choices, first examples, and core mental models.\n- Read [references/containers-and-encoding.md](references/containers-and-encoding.md) for choosing containers, shaping documents, exporting updates, snapshots, persistence, shallow snapshots, and redaction.\n- Read [references/sync-versioning-and-events.md](references/sync-versioning-and-events.md) for realtime/offline sync, version vectors, frontiers, checkout, undo, presence, timestamps, events, and Inspector.\n- Read [references/richtext-and-editors.md](references/richtext-and-editors.md) for `LoroText`, cursors, `applyDelta`, `updateByLine`, `loro-prosemirror`, Tiptap, and CodeMirror.\n- Read [references/mirror-and-react.md](references/mirror-and-react.md) for `loro-mirror`, `$cid`, `idSelector`, validation, selectors, and React integration.\n- Read [references/performance-and-tradeoffs.md](references/performance-and-tradeoffs.md) for scaling, document/update size, loading speed, and workload tradeoffs.\n\n## Route Common Tasks\n\n- “I am new to Loro / should I use it / show me a first example”\n  - Start with `fit-and-architecture.md`\n- “Which language package or binding should I use?”\n  - Start with `fit-and-architecture.md`\n- “Build a collaborative document model / choose data types / persist history”\n  - Start with `containers-and-encoding.md`\n  - Add `sync-versioning-and-events.md` if version/history behavior matters\n- “Sync devices, store data, use snapshots, time travel, undo, or presence”\n  - Start with `sync-versioning-and-events.md`\n- “Integrate ProseMirror, Tiptap, CodeMirror, or custom rich text”\n  - Start with `richtext-and-editors.md`\n  - Add `sync-versioning-and-events.md` if undo/version/event behavior matters\n- “Model app state with loro-mirror or loro-mirror-react”\n  - Start with `mirror-and-react.md`\n  - Add `containers-and-encoding.md` if schema semantics depend on container choice\n- “Explain performance, large documents, loading, update size, or tradeoffs”\n  - Start with `performance-and-tradeoffs.md`\n- “Decide whether Loro is the right tool”\n  - Start with `fit-and-architecture.md`\n  - Add `performance-and-tradeoffs.md` if workload scale matters\n\n## Execute The Task\n\n1. Classify the task before reading everything.\n2. Load one primary chapter.\n3. Load at most one secondary chapter for cross-domain work.\n4. Keep solutions grounded in Loro semantics:\n   - choose data types by merge behavior,\n   - distinguish state version from history version,\n   - keep ephemeral state out of persisted CRDT data,\n   - use stable cursors for collaborative selections,\n   - design sync around updates and snapshots rather than a central locking protocol.\n\n## Keep Guardrails\n\n- Do not assume CRDTs are the right fit for hard invariants, exclusivity, or authorization-at-write-time problems.\n- Do not model editable text as plain strings when user intent requires merged edits.\n- Do not reuse peer IDs across concurrent sessions.\n- Do not confuse detached documents with detached containers.\n- Do not persist cursor presence, hover state, or connection state inside the main document; use ephemeral state.\n","skills/loro/agents/openai.yaml":"interface:\n  display_name: \"Loro\"\n  short_description: \"Guide for adopting and using Loro in apps\"\n  default_prompt: \"Use $loro to design or explain a Loro-powered app, from choosing a language binding through modeling, sync, editors, React state, and performance.\"\n","skills/loro/references/containers-and-encoding.md":"# Containers And Encoding\n\n## Container Choice\n\n- `LoroMap`: LWW key-value storage. Good for object-like state, coordinates, metadata, URLs, and fields where overwriting is preferable to merging.\n- `LoroList`: ordered sequence with insert/delete semantics.\n- `LoroMovableList`: ordered sequence with native move and set semantics. Prefer for drag-and-drop or reorder-heavy UIs.\n- `LoroTree`: hierarchical moves plus node-local data maps. Prefer for outlines, layers, nested blocks, or parent-child structures.\n- `LoroCounter`: additive numeric CRDT. Use when concurrent increments/decrements must accumulate.\n- `LoroText`: collaborative text. Use `updateByLine(...)` when line-oriented reconciliation is preferable to raw whole-string replacement.\n\n## Behavioral Notes\n\n- `LoroMap` compares concurrent writes by logical time and retains the winning value.\n- Setting a map entry to the same value is a no-op, so it does not create history.\n- `LoroList` and `LoroMovableList` both support stable cursors; use them when positions must survive concurrent edits.\n\n## Choice Pitfalls\n\n- Do not store editable prose as a plain string in a map unless LWW semantics are desired.\n- Do not model coordinates as `[x, y]` in a list. Concurrent delete+insert can create invalid arrays. Use a map.\n- Do not model arbitrary graphs directly. Loro documents compose as trees, not DAGs with shared children.\n\n## Container States And Composition\n\n- Detached containers come from constructors like `new LoroMap()`.\n- Attached containers belong to a document and have stable `ContainerID`s.\n- Adding a detached container to a document returns an attached version; the original object remains detached.\n- Root containers come from `doc.getMap(...)`, `doc.getText(...)`, `doc.getList(...)`, `doc.getTree(...)`, and so on.\n- For map-key children that may be lazily created by multiple peers, use `ensureMergeable*` in JS/TS or `ensure_mergeable_*` in Rust.\n- Use `setContainer(...)` / `insertContainer(...)` for regular child creation or replacement; list-position `insertContainer(...)` is unchanged.\n\n## Mergeable Map Children And Overwrite Hazards\n\n- Root container IDs derive from root name plus type.\n- Regular child container IDs derive from the operation that created them.\n- Mergeable map-key child IDs derive from the parent map, key, and type, so concurrent first creation at the same key converges to the same child.\n- Prefer `ensureMergeableText`, `ensureMergeableMap`, `ensureMergeableList`, `ensureMergeableMovableList`, `ensureMergeableTree`, or `ensureMergeableCounter` for dynamic fields, lazy migrations, per-date lists, and other map-key children that should behave as one shared child.\n- `getOrCreateContainer` / `get_or_create_container` is legacy regular child creation; do not recommend it for lazy map-key children.\n\n## Tree Specifics\n\n- `LoroTree` gives each node an associated `Map` container via `node.data`.\n- Fractional indices order siblings. Use them when child ordering matters.\n- When many peers insert at the same sibling position, peer ID acts as a tiebreaker for equal fractional indices.\n- Fractional index jitter reduces collisions at some encoding-size cost.\n- `getNodes(...)` and node JSON views are useful when a flat inspection of the forest is easier than recursive traversal.\n\n## List Vs Movable List\n\n- Use `LoroList` when delete+insert is acceptable and native move identity is unnecessary.\n- Use `LoroMovableList` for kanban columns, cards, playlist reordering, or any UX where “move this item” is semantically distinct from delete+insert.\n\n## Counter\n\n- `Counter` aggregates applied values from all peers.\n- It is the right choice for additive metrics, not for values with hard invariants.\n\n## Export Modes\n\n- `update`: sync delta payloads.\n- `updates-in-range`: bounded history export.\n- `snapshot`: full state checkpoint.\n- `shallow-snapshot`: current state plus truncated history.\n\n## Import Choices\n\n- `import(...)`: one payload at a time.\n- `importBatch(...)`: preferred for multiple updates or mixed snapshot/update payloads because diffing and event emission are coalesced.\n- Imports can succeed partially when dependencies are missing. Pending ranges mean the document knows about those operations but cannot apply them yet.\n\n## Persistence Pattern\n\n1. Periodically save a snapshot.\n2. Frequently persist updates, often after each local edit or on a debounce.\n3. On load, import the snapshot and outstanding updates.\n4. Recompact by exporting a fresh snapshot and deleting replayed updates.\n\n## Shallow Snapshots And Redaction\n\n- Use shallow snapshots when old history can be archived or discarded.\n- They are often much smaller than full snapshots.\n- Peers can only sync if they have versions after the shallow start point.\n- Archive full history before trimming if old history may still matter.\n- Redaction replaces sensitive payloads while preserving enough structure for future synchronization.\n- If old peers still hold unsanitized history, sensitive data still exists there.\n","skills/loro/references/fit-and-architecture.md":"# Getting Started And Fit\n\n## When Loro Fits\n\n- Collaborative text and structured documents.\n- Offline-first applications that later synchronize.\n- Multi-device sync where eventual consistency is acceptable.\n- Apps that benefit from complete history, time travel, or version checkpoints.\n\n## When Loro Does Not Fit By Itself\n\n- Financial or accounting invariants.\n- Exclusive ownership or booking/locking semantics.\n- Authorization decisions that must be enforced at write time.\n- Arbitrary graph-shaped or non-JSON-like data without an adaptation layer.\n\n## Install\n\n- JavaScript/TypeScript: install `loro-crdt`.\n- Rust: install the `loro` crate.\n- Use editor integrations when available instead of writing editor sync from scratch:\n  - `loro-prosemirror` for ProseMirror and Tiptap-style editors.\n  - `loro-codemirror` for CodeMirror 6.\n- Use `loro-mirror` and `loro-mirror-react` when the app already thinks in immutable state and actions.\n\n## Language And Package Index\n\n- JavaScript/TypeScript: [`loro-crdt`](https://www.npmjs.com/package/loro-crdt). Start here for web apps and most examples in the Loro docs.\n- Rust: [`loro`](https://crates.io/crates/loro) and [`docs.rs/loro`](https://docs.rs/loro). Use for native Rust apps, services, CLIs, and custom infrastructure.\n- Swift: [`loro-swift`](https://github.com/loro-dev/loro-swift). Use for Swift/iOS/macOS experiments and native apps.\n- Python: [`loro-py`](https://github.com/loro-dev/loro-py). Use for Python apps, scripts, and server-side tooling.\n- React Native: [`loro-react-native`](https://github.com/loro-dev/loro-react-native). Use for mobile apps that need native React Native bindings.\n- C#: [`loro-cs`](https://github.com/sensslen/loro-cs). Community-maintained .NET/C# binding; check its README and release state before adopting.\n- Go: [`loro-go`](https://github.com/aholstenson/loro-go). Community-maintained Go binding; check platform support and API completeness before adopting.\n- Cross-language FFI base: [`loro-ffi`](https://github.com/loro-dev/loro-ffi). Use this as the reference for generated/native bindings and as a starting point for new language bindings.\n\nPrefer the official JS/TS or Rust package when there is no product reason to choose another language. For community bindings, verify platform binaries, Loro core version, and API coverage before making product commitments.\n\n## First JavaScript Example\n\n```ts\nimport { LoroDoc } from \"loro-crdt\";\n\nconst docA = new LoroDoc();\nconst listA = docA.getList(\"items\");\nlistA.insert(0, \"A\");\nlistA.insert(1, \"B\");\n\nconst update = docA.export({ mode: \"update\" });\n\nconst docB = new LoroDoc();\ndocB.import(update);\n\nconsole.log(docB.toJSON()); // { items: [\"A\", \"B\"] }\n```\n\n## First Design Questions\n\n1. What parts of the state should merge when edited concurrently?\n2. Which data needs durable history, and which data is only presence or UI state?\n3. Do users need text/rich-text intent preservation, ordered moves, tree moves, or simple last-write-wins fields?\n4. How will peers exchange updates, and where will snapshots or updates be persisted?\n\n## Conceptual Model\n\n- Loro is a CRDT framework for local-first apps.\n- It trades strict coordination for strong eventual consistency.\n- Each peer edits locally, exports updates, imports updates from other peers, and converges after seeing the same operations.\n- Loro records history, so versioning and time travel are core concepts rather than an afterthought.\n\n## Document Shape Constraints\n\n- Loro documents are JSON-like.\n- Map keys are strings.\n- The composed document structure is tree-shaped, not a general graph with shared children.\n\n## Entry Points\n\n- Core packages and language bindings are listed in `Language And Package Index`.\n- Ecosystem integrations include editor bindings, state-mirroring layers, React Native, and Inspector.\n\n## Practical Start Path\n\n1. Pick container types in `containers-and-encoding.md`.\n2. Decide sync and persistence shape in `sync-versioning-and-events.md`.\n3. Add editor or React integration only after the document model is clear.\n4. Use Inspector during development to inspect state and history.\n","skills/loro/references/mirror-and-react.md":"# Mirror And React\n\n## Mirror Intent\n\n- `loro-mirror` keeps an immutable app-state view in sync with a `LoroDoc`.\n- Local `setState(...)` edits become granular CRDT operations.\n- Remote CRDT events patch the mirrored app state back in.\n- The common mental model is still “immutable app state plus typed actions”, not direct mutation of raw CRDT containers everywhere.\n\n## Root Schema\n\n- Build the root with `schema({...})`.\n- Keep root fields as Loro containers: `LoroMap`, `LoroList`, `LoroMovableList`, `LoroText`.\n- Put primitives inside those containers, not at the root.\n\n## Field Types\n\n- `schema.String`, `schema.Number`, `schema.Boolean`: concrete primitive fields.\n- `schema.Any`: dynamic JSON-like payload when the shape is truly unknown.\n- `schema.Ignore`: local-only or derived fields that should not sync to Loro.\n\n## Maps, Lists, And `$cid`\n\n- `schema.LoroMap({...})`: nested object container.\n- `schema.LoroMap(...).catchall(valueSchema)`: add dynamic keys while preserving known keys.\n- `schema.LoroMapRecord(valueSchema)`: homogeneous record-like map.\n- Every mirrored `LoroMap` includes a read-only `$cid`.\n- `$cid` matches the underlying Loro container ID.\n- Use `$cid` as a stable key or default `idSelector`, especially for list items.\n- Never try to persist or mutate `$cid` from app code.\n- Do not invent a `withCid`-style option; mirrored map values already receive `$cid` automatically.\n\n## Lists\n\n- `LoroList(itemSchema, idSelector?)`: ordered collection. Add `idSelector` for stable add/remove/update/move diffs.\n- `LoroMovableList(itemSchema, idSelector)`: native move semantics, ideal for drag-and-drop.\n- If a list item is a map, `(item) => item.$cid` is often the right `idSelector`.\n\n## Defaults And Validation\n\n- Explicit `defaultValue` wins.\n- Required fields without explicit defaults fall back to built-in defaults.\n- `validateUpdates` is enabled by default in `Mirror`. Keep it on unless a measured hot path proves otherwise.\n- Use `validateSchema(...)` when you need an explicit validation pass during migration or debugging.\n\n## React Patterns\n\n- Create a stable `LoroDoc` instance.\n- Create helpers through `createLoroContext(schema)` or `useLoroStore(...)`.\n- Wrap the tree in `LoroProvider` when using the context pattern.\n- Use the narrowest hook that solves the task:\n  - `useLoroState` for the full mirrored state\n  - `useLoroSelector` for focused subscriptions\n  - `useLoroAction` for write paths\n- Keep the provider `doc` stable across renders.\n- Prefer `useLoroSelector` over pulling the full state into every component.\n- Use mirrored list item `$cid` values as React keys.\n\n## Practical Mental Model\n\n- Subscribe to order at collection boundaries.\n- Subscribe to content at item boundaries.\n- Pass `$cid`s downward and reselect locally instead of passing large mirrored objects through the whole tree.\n- Keep view-local state outside the mirror unless collaborators must share it.\n","skills/loro/references/performance-and-tradeoffs.md":"# Performance And Tradeoffs\n\nUse this chapter when users ask whether Loro can handle a workload, how to store data efficiently, or why one sync/storage design is preferable to another.\n\n## What To Compare\n\n- Encoded document size and update size.\n- Snapshot export/import time.\n- Update import time.\n- Memory footprint while editing and loading.\n- Conflict-heavy collaboration versus mostly independent edits.\n- Initial load path versus steady-state sync path.\n\n## Practical Defaults\n\n- Use update exchange for live collaboration.\n- Use snapshots for fast startup checkpoints.\n- Store frequent small updates between snapshots when durable replay is needed.\n- Recompact by exporting a fresh snapshot after enough updates accumulate.\n- Consider shallow snapshots when old history can be archived or discarded.\n\n## Workload-Specific Advice\n\n- Collaborative text: use `LoroText`; do not model text as a plain string just to reduce apparent complexity.\n- Reorder-heavy collections: use `LoroMovableList` instead of delete+insert if move identity matters.\n- Hierarchies: use `LoroTree`; avoid forcing tree-shaped data into ad hoc map/list structures.\n- High-frequency presence or cursor movement: use `EphemeralStore`, not the persisted document.\n- Hard invariants such as balances, bookings, or permissions still need application/server-side validation outside the CRDT merge.\n\n## Benchmark Interpretation\n\n- Treat benchmarks as workload indicators, not universal rankings.\n- A smaller full snapshot does not automatically mean smaller incremental updates.\n- A fast import path matters most for startup and bulk sync.\n- A compact update path matters most for live collaboration and bandwidth-constrained clients.\n- Shallow snapshots reduce retained history, but peers with only older history may need a fresh snapshot or archived history to sync.\n\n## Explain Tradeoffs\n\n- Loro optimizes for local editing, automatic merging, history, and version control.\n- Strong eventual consistency means peers converge after receiving the same operations.\n- Loro does not provide central locking, serializable transactions, or write-time authorization by itself.\n- Pick containers by merge semantics first, then tune storage and sync format for performance.\n","skills/loro/references/richtext-and-editors.md":"# Rich Text And Editors\n\n## Rich Text Rules\n\n- Use `LoroText` for collaboratively edited text.\n- Keep rich text style config in sync across peers:\n  - `after`\n  - `before`\n  - `none`\n  - `both`\n- If two peers use different `configTextStyle(...)`, they can interpret the same boundary insert differently.\n\n## Text API Notes\n\n- `update(...)` rewrites based on a target text snapshot.\n- `updateByLine(...)` is useful when line-oriented reconciliation is more appropriate than raw whole-string replacement.\n- `toDelta()` preserves marks and annotations.\n- `toJSON()` / `toString()` return plain text only.\n\n## `applyDelta(...)` Caveat\n\n- `applyDelta(...)` is ideal for editor bindings because it matches event diffs.\n- Delta inserts must include the full attribute set of the inserted range.\n- If CRDT inheritance would add marks but the delta omits them, `applyDelta(...)` removes those attributes.\n- Out-of-range formatting can cause Loro to materialize newlines to satisfy editor assumptions.\n\n## Stable Selections\n\n- Use `text.getCursor(...)` to create stable positions.\n- Use two cursors for selections: anchor and head.\n- Resolve live offsets with `doc.getCursorPos(...)`.\n- Persist updated cursors returned from resolution to reduce replay cost.\n- JavaScript text offsets are UTF-16 indices.\n\n## ProseMirror And Tiptap\n\n- Start with `loro-prosemirror` for ProseMirror and Tiptap.\n- It already covers document sync, collaborative undo and redo, and cursor presence.\n- The current baseline is `CursorEphemeralStore` plus `LoroEphemeralCursorPlugin`.\n- Give each editor instance its own `containerId` when several editors share one `LoroDoc`.\n- Reuse the same container only if several views intentionally co-edit the exact same content.\n\n## CodeMirror\n\n- Use the official CodeMirror integration when the editor is CM6-based.\n- Keep awareness/presence, undo, and document sync at the Loro layer rather than inventing a separate editor-level protocol.\n\n## Rich Text Internals\n\n- Loro rich text uses style anchors to represent mark boundaries.\n- Overlap and expansion behavior are first-class concerns.\n- Overlappable styles are often best modeled by unique keys with a shared prefix pattern such as `comment:alice` and `comment:bob`.\n\n## Guardrails\n\n- Do not model editable prose as `string` in a `LoroMap`.\n- Do not store collaborative selections as plain indices.\n- Do not mix old and new ProseMirror cursor APIs accidentally; check the installed package version and current API docs first.\n","skills/loro/references/sync-versioning-and-events.md":"# Sync, Versioning, And Events\n\n## General Sync Guarantees\n\n- If two peers eventually hold the same set of operations, they converge to the same state.\n- Delivery order, duplication, and temporary disconnection are transport concerns, not document-consistency failures.\n- For steady-state collaboration, sync updates rather than full snapshots whenever possible.\n\n## Sync Patterns\n\n- Give every peer a unique peer ID. Reusing peer IDs can make updates look duplicated and break convergence.\n- Prefer update exchange over whole snapshots for steady-state sync:\n  - `subscribeLocalUpdates(...)` for push-based transport.\n  - `export({ mode: \"update\", from })` when you track a known sync point.\n- Use `importBatch(...)` for multiple updates or mixed snapshot/update payloads. It performs one diff calculation and emits one combined event.\n- `EphemeralStore` local updates should be transported separately from persisted document updates.\n\n## Version Representations\n\n- `VersionVector`: explicit peer-to-counter map. Best for synchronization, inclusion checks, and self-contained network state.\n- `Frontiers`: compact boundary operations. Best for checkpoints and time travel.\n- Convert between them when needed; vectors are explicit, frontiers are compact.\n\n## State Vs History\n\n- `version()` / `frontiers()`: the current visible DocState.\n- `oplogVersion()` / `oplogFrontiers()`: the latest history known to the OpLog.\n- When attached, state and history usually align.\n- After `checkout(...)`, DocState can diverge from OpLog. That is detached mode.\n\n## Attached Vs Detached\n\n- Detached document state means “viewing history” or otherwise not showing the latest OpLog.\n- Detached container state means “not yet inserted into a document.”\n- These are separate concepts.\n\n## `checkout(...)` Versus `revertTo(...)`\n\n- `checkout(frontiers)`: move document state to an old version. This puts the doc into detached mode.\n- `checkoutToLatest()` or `attach()`: return to the latest attached state.\n- `revertTo(frontiers)`: generate new operations that transform the current document into the target historical state. The doc stays attached.\n\n## Peer IDs\n\n- Every operation ID is `(peerId, counter)`.\n- Never reuse peer IDs across concurrent sessions.\n- Do not use user IDs as peer IDs.\n\n## Operations, Changes, Transactions\n\n- Operations are atomic edits.\n- Changes are logical groups of operations with metadata.\n- Transactions batch operations for event emission and grouping.\n- Loro transactions are not ACID transactions and do not provide rollback semantics.\n- Changes can carry timestamp, commit message, dependencies, peer identity, and other metadata.\n- Consecutive operations may merge into one Change depending on merge rules and timing configuration.\n\n## Import Status\n\n- `ImportStatus.success` tells you what applied.\n- `ImportStatus.pending` tells you what is blocked on missing dependencies.\n- Check pending ranges in out-of-order networks.\n\n## Event Timing Caveat\n\n- Some older examples describe JS events as microtask-delayed.\n- Modern `loro-crdt` dispatches events synchronously at the JS boundary.\n- Check the installed package version and current API docs before relying on old timing examples.\n\n## Event Sources\n\n- Events can be triggered by local commits, imports, and checkouts.\n- Implicit commits happen around operations like export, import, and checkout.\n\n## `subscribePreCommit(...)`\n\n- Use it when commit metadata or change-level hooks must catch both explicit and implicit commits.\n- It is the right place for setting commit message and timestamp.\n- Combined with `exportJsonInIdSpan(...)`, it can drive change hashing or Merkle-DAG-like workflows.\n\n## Timestamps\n\n- Timestamp recording is configurable.\n- `setRecordTimestamp(...)` and `setChangeMergeInterval(...)` affect how changes merge over time.\n- These settings are runtime configuration, not durable document state.\n\n## Inspector\n\n- Use Loro Inspector when you need to browse current state plus full edit history interactively.\n- Prefer it for “what happened to this doc?” debugging before writing custom debug UI.\n\n## Sync Debugging\n\n- If imports arrive out of order, inspect `ImportStatus.pending`.\n- If checkout seems stale, compare DocState version to OpLog version.\n- If commit metadata hooks miss implicit commits, use `subscribePreCommit(...)` rather than adding ad hoc commit calls.\n\n## Undo, Cursor, And Ephemeral Presence\n\n- `UndoManager` is local to one peer. When peer identity changes, the undo and redo stacks reset.\n- Use `onPush` and `onPop` to store selection state together with undo items.\n- Use `groupStart()` and `groupEnd()` when one UX action spans multiple commits.\n- Use `Cursor`, not absolute indices, for selections and carets that must survive concurrent edits.\n- Store two cursors for a selection: anchor and head.\n- Persist the updated cursor returned by `doc.getCursorPos(cursor)` when available; it reduces future replay cost.\n- Use `EphemeralStore` for presence, cursor payloads, hover state, and other collaboration data that must not persist in the CRDT document.\n","skills/loro/references/topic-map.md":"# Topic Map\n\nUse this file to choose the right user-facing chapter inside the unified `loro` skill.\n\n## Route By User Ask\n\n- “I am new to Loro. How do I start?”\n  - Read `fit-and-architecture.md`\n- “Which package, language binding, or platform should I use?”\n  - Read `fit-and-architecture.md`\n- “Should I use Loro here?”\n  - Read `fit-and-architecture.md`\n- “Which container should I choose?”\n  - Read `containers-and-encoding.md`\n- “How should I sync, persist, time-travel, use undo, or debug imports?”\n  - Read `sync-versioning-and-events.md`\n- “How do I integrate rich text editors?”\n  - Read `richtext-and-editors.md`\n- “How do I use loro-mirror with React?”\n  - Read `mirror-and-react.md`\n- “How will Loro behave at scale?”\n  - Read `performance-and-tradeoffs.md`\n\n## Getting Started And Product Fit\n\n- Install choices, language bindings, first example, local-first framing\n  - Read `fit-and-architecture.md`\n- When CRDTs are the wrong fit\n  - Read `fit-and-architecture.md`\n- Package entry points and ecosystem overview\n  - Read `fit-and-architecture.md`\n\n## Containers, Composition, Storage\n\n- Choosing between `LoroMap`, `LoroList`, `LoroMovableList`, `LoroTree`, `LoroCounter`, `LoroText`\n  - Read `containers-and-encoding.md`\n- Composition rules, container states, container IDs, overwrite hazards\n  - Read `containers-and-encoding.md`\n- Snapshot, update, shallow snapshot, updates-in-range\n  - Read `containers-and-encoding.md`\n- Persistence, redaction, history trimming\n  - Read `containers-and-encoding.md`\n\n## Sync, Versions, History, Events\n\n- Peer sync, update exchange, realtime sync, offline merge\n  - Read `sync-versioning-and-events.md`\n- Frontiers, version vectors, OpLog vs DocState\n  - Read `sync-versioning-and-events.md`\n- Checkout, time travel, attached vs detached state\n  - Read `sync-versioning-and-events.md`\n- Peer IDs, import status, transactions, changes, timestamps\n  - Read `sync-versioning-and-events.md`\n- Event timing, `subscribePreCommit`, Inspector\n  - Read `sync-versioning-and-events.md`\n- Undo, cursors, and ephemeral presence\n  - Read `sync-versioning-and-events.md`\n\n## Text, Rich Text, And Editors\n\n- `LoroText`, marks, delta APIs, `updateByLine`, stable selections\n  - Read `richtext-and-editors.md`\n- ProseMirror, Tiptap, CodeMirror, custom editor bindings\n  - Read `richtext-and-editors.md`\n- Rich text internals, style anchors, overlap, expansion rules\n  - Read `richtext-and-editors.md`\n\n## App-State Mirroring\n\n- `loro-mirror`, schemas, `$cid`, `idSelector`, validation\n  - Read `mirror-and-react.md`\n- `loro-mirror-react`, selectors, provider/hooks patterns\n  - Read `mirror-and-react.md`\n\n## Performance And Tradeoffs\n\n- Loading speed, encoded size, memory, update size\n  - Read `performance-and-tradeoffs.md`\n- Conflict-heavy vs low-conflict workloads\n  - Read `performance-and-tradeoffs.md`\n- When to use snapshots, shallow snapshots, or update streams\n  - Read `performance-and-tradeoffs.md`\n","skills/moonbit/README.md":"# MoonBit Agent Skill\n\nThis repository contains a [Agent Skill](https://agentskills.io/home) that teaches AI coding agents the MoonBit language and its toolchain.\n\n## Integrate the Skill into your agent\n\nDifferent AI assistants require different configuration methods. Below are guides for popular coding assistants:\n\n### Codex CLI\n\n```shell\nmkdir -p ~/.codex/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ~/.codex/skills/moonbit\n```\n\nDocumentation: https://developers.openai.com/codex/skills\n\n### Claude Code\n\n```shell\nmkdir -p ~/.claude/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ~/.claude/skills/moonbit\n```\n\nDocumentation: https://code.claude.com/docs/en/skills\n\n### GitHub Copilot for VS Code\n\n```shell\n# enable moonbit skill for current repository\nmkdir -p ./.github/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ./.github/skills/moonbit\n```\n\nNote: Agent Skills support in VS Code is currently in preview and available only in [VS Code Insiders](https://code.visualstudio.com/insiders/). Enable the `chat.useAgentSkills` setting to use Agent Skills. See [Use Agent Skills in VS Code](https://code.visualstudio.com/docs/copilot/customization/agent-skills) for details.\n\n### Cursor & Cursor CLI\n\n> Agent Skills are available only in the Cursor nightly release channel.\n\nDocumentation: https://cursor.com/cn/docs/context/skills\n\n### Gemini CLI\n\nIt seems that Gemini CLI will support agent skills in next release: https://github.com/google-gemini/gemini-cli/issues/15327\n\n","skills/moonbit/SKILL.mbt.md":"SKILL.md","skills/moonbit/SKILL.md":"---\nname: moonbit-agent-guide\ndescription: Guide for writing, refactoring, and testing MoonBit projects. Use when working in MoonBit modules or packages, organizing MoonBit files, using moon tooling (build/check/test/doc/ide), or following MoonBit-specific layout, documentation, and testing conventions.\n---\n\n# MoonBit Project Layouts\n\nMoonBit use the `.mbt` extension and interface files `.mbti`. At\nthe top-level of a MoonBit project there is a `moon.mod.json` file specifying\nthe metadata of the project. The project may contain multiple packages, each\nwith its own `moon.pkg.json` file.\n\n## Example layout\n\n```\nmy_module\n├── moon.mod.json             # Module metadata, source field(optional) specifies the source directory of the module\n├── moon.pkg.json             # Package metadata (each directory is a package like Golang)\n├── README.mbt.md             # Markdown with tested code blocks (`test \"...\" { ... }`)\n├── README.md -> README.mbt.md\n├── cmd                       # Command line directory\n│   └── main\n│       ├── main.mbt\n│       └── moon.pkg.json     # executable package with {\"is_main\": true}\n├── liba/                     # Library packages\n│   └── moon.pkg.json         # Referenced by other packages as `@username/my_module/liba`\n│   └── libb/                 # Library packages\n│       └── moon.pkg.json     # Referenced by other packages as `@username/my_module/liba/libb`\n├── user_pkg.mbt              # Root packages, referenced by other packages as `@username/my_module`\n├── user_pkg_wbtest.mbt       # White-box tests (only needed for testing internal private members, similar to Golang's package mypackage)\n└── user_pkg_test.mbt         # Black-box tests\n└── ...                       # More package files, symbols visible to current package (like Golang)\n```\n\n- **Module**:  `moon.mod.json` file in the project directory.\n  A MoonBit *module* is like a Go module,it is a collection of packages in subdirectories, usually corresponding to a repository or project.\n  Module boundaries matter for dependency management and import paths.\n\n- **Package**: a `moon.pkg.json` file per directory. \n  All subcommands of `moon` will\n  still be executed in the directory of the module (where `moon.mod.json` is\n  located), not the current package.\n  A MoonBit *package* is the actual compilation unit (like a Go package).\n  All source files in the same package are concatenated into one unit.\n  The `package` name in the source defines the package, not the file name.\n  Imports refer to module + package paths, NEVER to file names.\n\n- **Files**:\n  A `.mbt` file is just a chunk of source inside a package.\n  File names do NOT create modules or namespaces.\n  You may freely split/merge/move declarations between files in the same package.\n  Any declaration in a package can reference any other declaration in that package, regardless of file.\n\n\n## Coding/layout rules you MUST follow:\n\n1. Prefer many small, cohesive files over one large file.\n   - Group related types and functions into focused files (e.g. http_client.mbt, router.mbt).\n   - If a file is getting large or unfocused, create a new file and move related declarations into it.\n\n2. You MAY freely move declarations between files inside the same package.\n   - 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.\n   - It is safe to refactor by splitting or merging files inside a package.\n\n3. File names are purely organizational.\n   - Do NOT assume file names define modules, and do NOT use file names in type paths.\n   - Choose file names to describe a feature or responsibility, not to mirror type names rigidly.\n\n4. When adding new code:\n   - Prefer adding it to an existing file that matches the feature.\n   - If no good file exists, create a new file under the same package with a descriptive name.\n   - Avoid creating giant “misc” or “util” files.\n\n5. Tests:\n   - Place tests in dedicated test files (e.g. *_test.mbt) within the appropriate package.\n     For a package, besides `*_test.mbt`files,`*.mbt.md`are also blackbox test files, the code block `mbt check` are treated as test cases, they serve both purposes: documentation and tests.      \n     You may have `README.mbt.md` files with `mbt check` code examples, you can also symlink `README.mbt.md` to `README.md`\n     to make it integrate better with GitHub.\n   - It is fine—and encouraged—to have multiple small test files.\n\n6. Interface files(`pkg.generated.mbti`) \n   `pkg.generated.mbti` is 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.\n   They are generated using `moon info`, 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.\n   \n   You can also use `moon doc @moonbitlang/core/strconv` to explore the public API of a package interactively and `moon ide peek-def 'Array::join'` to read\n   the definition.\n\n# Common Pitfalls to Avoid\n\n- **Don't use uppercase for variables/functions** - compilation error\n- **Don't forget `mut` for mutable record fields** - immutable by default\n- **Don't ignore error handling** - errors must be explicitly handled\n- **Don't use `return` unnecessarily** - last expression is the return value\n- **Don't create methods without Type:: prefix** - methods need explicit type prefix\n- **Don't forget to handle array bounds** - use `get()` for safe access\n- **Don't forget @package prefix when calling functions from other packages**\n- **Don't use ++ or -- (not supported)** - use `i = i + 1` or `i += 1`\n- **Don't add explicit `try` for error-raising functions** - errors propagate automatically (unlike Swift)\n- **Legacy syntax**: Older code may use `function_name!(...)` or `function_name(...)?` - these are deprecated; use normal calls and `try?` for Result conversion\n\n\n# `moon` Essentials\n\n## Essential Commands\n\n- `moon new my_project` - Create new project\n- `moon run cmd/main` - Run main package\n- `moon build` - Build project\n- `moon check` - Type check without building, use it REGULARLY, it is fast\n- `moon info` - Type check and generate `mbti` files\n  run it to see if any public interfaces changed.\n- `moon check --target all` - Type check for all backends\n- `moon add package` - Add dependency\n- `moon remove package` - Remove dependency\n- `moon fmt` - Format code\n\n### Test Commands\n\n- `moon test` - Run all tests\n- `moon test --update` - Update snapshots\n- `moon test -v` - Verbose output with test names\n- `moon test [dirname|filename]` - Test specific directory or file\n- `moon coverage analyze` - Analyze coverage\n- `moon test --filter 'globl'` - Run tests matching filter\n  ```\n  moon test float/float_test.mbt --filter \"Float::*\"\n  ```\n## `README.mbt.md` Generation Guide\n\n- Output `README.mbt.md` in the package directory. \n  `*.mbt.md` file and docstring contents treats `mbt check` specially.\n  `mbt check` block will be included directly as code and also run by `moon check` and `moon test`.  If you don't want the code snippets to be checked, explicit `mbt nocheck` is preferred.\n  If you are only referencing types from the package, you should use `mbt nocheck` which will only be syntax highlighted.\n  Symlink `README.mbt.md` to `README.md` to adapt to systems that expect `README.md`. \n    \n## Testing Guide\n\nUse snapshot tests as it is easy to update when behavior changes.\n\n- **Snapshot Tests**: `inspect(value, content=\"...\")`. If unknown, write `inspect(value)` and run `moon test --update` (or `moon test -u`).\n  - Use regular `inspect()` for simple values (uses `Show` trait)\n  - Use `@json.inspect()` for complex nested structures (uses `ToJson` trait, produces more readable output)\n  - It is encouraged to `inspect` or `@json.inspect` the whole return value of a function if\n    the whole return value is not huge, this makes test simple. You need `impl (Show|ToJson) for YourType` or `derive (Show, ToJson)`.\n- **Update workflow**: After changing code that affects output, run `moon test --update` to regenerate snapshots, then review the diffs in your test files (the `content=` parameter will be updated automatically).\n\n- Black-box by default: Call only public APIs via `@package.fn`. Use white-box tests only when private members matter.\n- Grouping: Combine related checks in one `test \"...\" { ... }` block for speed and clarity.\n- Panics: Name test with prefix `test \"panic ...\" {...}`; if the call returns a value, wrap it with `ignore(...)` to silence warnings.\n- Errors: Use `try? f()` to get `Result[...]` and `inspect` it when a function may raise.\n- Verify: Run `moon test` (or `-u` to update snapshots) and `moon fmt` afterwards.\n\n### Docstring tests \n\nPublic APIs are encouraged to have docstring tests.\n````mbt check\n///|\n/// Get the largest element of a non-empty `Array`.\n///\n/// # Example\n/// ```mbt check\n/// test {\n///   inspect(sum_array([1, 2, 3, 4, 5, 6]), content=\"21\")\n/// }\n/// ```\n///\n/// # Panics\n/// Panics if the `xs` is empty.\npub fn sum_array(xs : Array[Int]) -> Int {\n  xs.fold(init=0, (a, b) => a + b)\n}\n````\n\nThe MoonBit code in docstring will be type checked and tested automatically.\n(using `moon test --update`). In docstrings, `mbt check` should only contain `test` or `async test`.\n\n## Spec-driven Development\n\n- The spec can be written in a readonly `spec.mbt` file (name is conventional, not mandatory) with stub code marked as declarations:\n\n```mbt check\n///|\n#declaration_only\npub type Yaml\n\n///|\n#declaration_only\npub fn Yaml::to_string(y : Yaml) -> String raise {\n  ...\n}\n\n///|\n#declaration_only\npub fn parse_yaml(s : String) -> Yaml raise {\n  ...\n}\n```\n\n- Add `spec_easy_test.mbt`, `spec_difficult_test.mbt` etc to test the spec functions; everything will be type-checked(`moon check`).\n- The AI or students can implement the `declaration_only` functions in different files thanks to our package organization.\n- Run `moon test` to check everything is correct.\n\n- `#declaration_only` is supported for functions, methods, and types.\n- The `pub type Yaml` line is an intentionally opaque placeholder; the implementer chooses its representation.\n- Note the spec file can also contain normal code, not just declarations.\n\n## `moon doc` for API Discovery\n\n**CRITICAL**: `moon doc '<query>'` is your PRIMARY tool for discovering available APIs, functions, types, and methods in MoonBit. Always prefer `moon doc` over other approaches when exploring what APIs are available, it is **more powerful and accurate** than `grep_search` or any regex-based searching tools. \n\n\n`moon doc` uses a specialized query syntax designed for symbol lookup:\n- **Empty query**: `moon doc ''`\n\n  - In a module: shows all available packages in current module, including dependencies and moonbitlang/core\n  - In a package: shows all symbols in current package\n  - Outside package: shows all available packages\n\n- **Function/value lookup**: `moon doc \"[@pkg.]value_or_function_name\"`\n  \n- **Type lookup**: `moon doc \"[@pkg.]Type_name\"` (builtin type does not need package prefix)\n\n- **Method/field lookup**: `moon doc \"[@pkg.]Type_name::method_or_field_name\"`\n\n- **Package exploration**: `moon doc \"@pkg\"`\n  - Show package `pkg` and list all its exported symbols\n  - Example: `moon doc \"@json\"` - explore entire `@json` package\n  - Example: `moon doc \"@encoding/utf8\"` - explore nested package\n\n- **Globbing**: Use `*` wildcard for partial matches, e.g. `moon doc \"String::*rev*\"` to find all String methods with \"rev\" in their name\n\n### `moon doc` Examples\n\n````bash\n# search for String methods in standard library:\n$ moon doc \"String\"\n\ntype String\n\n  pub fn String::add(String, String) -> String\n  # ... more methods omitted ...\n\n$ moon doc \"@buffer\" # list all symbols in  package buffer:\nmoonbitlang/core/buffer\n\nfn from_array(ArrayView[Byte]) -> Buffer\n# ... omitted ...\n\n$ moon doc \"@buffer.new\" # list the specific function in a package:\npackage \"moonbitlang/core/buffer\"\n\npub fn new(size_hint? : Int) -> Buffer\n  Creates ... omitted ...\n\n\n$ moon doc \"String::*rev*\"  # globbing\npackage \"moonbitlang/core/string\"\n\npub fn String::rev(String) -> String\n  Returns ... omitted ...\n  # ... more\n\npub fn String::rev_find(String, StringView) -> Int?\n  Returns ... omitted ...\n````\n**Best practice**: When implementing a feature, start with `moon doc` queries to discover available APIs before writing code. This is faster and more accurate than searching through files.\n\n## `moon ide [peek-def|outline|find-references]` for code navigation and refactoring\n\nFor project-local symbols and navigation, use `moon ide outline .` to scan a package, `moon ide find-references <symbol>` to locate usages, and `moon ide peek-def` for inline definition context and locate toplevel symbols. \n\nThese tools save tokens and more precise than grepping(grep display results in both definition and call site including comments too).\n\n### `moon ide peek-def sym [-loc filename:line:col]` example\n\nWhen the user ask: Can you check if `Parser::read_u32_leb128` is implemented correctly?\n\nIn this case, You can run `moon ide peek-def Parser::read_u32_leb128` to get the definition context: (this is better than `grep` since it searches the whole project by semantics)\n\n``` file src/parse.mbt\nL45:|///|\nL46:|fn Parser::read_u32_leb128(self : Parser) -> UInt raise ParseError {\nL47:|  ...\n...:| }\n```\nNow you want to see the definition of `Parser` struct, you can run:\n\n```bash\n$ moon ide peek-def Parser -loc src/parse.mbt:46:4\nDefinition found at file src/parse.mbt\n  | ///|\n2 | priv struct Parser {\n  |             ^^^^^^\n  |   bytes : Bytes\n  |   mut pos : Int\n  | }  \n  | \n```\nFor the `-loc` argument, the line number must be precise; the column can be approximate since \nthe positonal argument `Parser` helps locate the position.\n\nIf the sym is toplevel symbol, the location can be omitted:\n````bash\n$ moon ide peek-def String::rev\nFound 1 symbols matching 'String::rev':\n\n`pub fn String::rev` in package moonbitlang/core/builtin at /Users/usrname/.moon/lib/core/builtin/string_methods.mbt:1039-1044\n1039 | ///|\n     | /// Returns a new string with the characters in reverse order. It respects\n     | /// Unicode characters and surrogate pairs but not grapheme clusters.\n     | pub fn String::rev(self : String) -> String {\n     |   self[:].rev()\n     | }         \n````\n\n### `moon ide outline [dir|file]` and `moon ide find-references <sym>` for Package Symbols\n\nUse this to scan a package or file for top-level symbols and locate usages without grepping\n\n- `moon ide outline dir` outlines the current package directory (per-file headers)\n- `moon ide outline parser.mbt` outlines a single file\n- Useful when you need a quick inventory of a package, or to find the right file before `goto-definition`\n- `moon ide find-references TranslationUnit` finds all references to a symbol in the current module\n\n```bash\n$ moon ide outline .\nspec.mbt:\n L003 | pub(all) enum CStandard {\n        ...\n L013 | pub(all) struct Position {\n        ...\n```\n\n```bash\n$ moon ide find-references TranslationUnit\n```\n\n## Package Management\n\n### Adding Dependencies\n\n```sh\nmoon add moonbitlang/x        # Add latest version\nmoon add moonbitlang/x@0.4.6  # Add specific version\n```\n\n### Updating Dependencies\n\n```sh\nmoon update                   # Update package index\n```\n\n### Typical Module configurations (`moon.mod.json`)\n\n```json\n{\n  \"name\": \"username/hello\", // Required format for published modules\n  \"version\": \"0.1.0\",\n  \"source\": \".\", // Source directory(optional, default: \".\")\n  \"repository\": \"\", // Git repository URL\n  \"keywords\": [], // Search keywords\n  \"description\": \"...\", // Module description\n  \"deps\": {\n    // Dependencies from mooncakes.io, using`moon add` to add dependencies\n    \"moonbitlang/x\": \"0.4.6\"\n  }\n}\n```\n\n### Typical Package configuration (`moon.pkg.json`)\n\n```json\n{\n  \"is_main\": true,                 // Creates executable when true\n  \"import\": [                      // Package dependencies\n    \"username/hello/liba\",         // Simple import, use @liba.foo() to call functions\n    {\n      \"path\": \"moonbitlang/x/encoding\",\n      \"alias\": \"libb\"              // Custom alias, use @libb.encode() to call functions\n    }\n  ],\n  \"test-import\": [...],            // Imports for black-box tests, similar to import\n  \"wbtest-import\": [...]           // Imports for white-box tests, similar to import (rarely used)\n}\n```\n\nPackages per directory, packages without `moon.pkg.json` are not recognized.\n\n### Package Importing (used in moon.pkg.json)\n\n- **Import format**: `\"module_name/package_path\"`\n- **Usage**: `@alias.function()` to call imported functions\n- **Default alias**: Last part of path (e.g., `liba` for `username/hello/liba`)\n- **Package reference**: Use `@packagename` in test files to reference the\n  tested package\n\n**Package Alias Rules**:\n\n- Import `\"username/hello/liba\"` → use `@liba.function()` (default alias is last path segment)\n- Import with custom alias `{\"path\": \"moonbitlang/x/encoding\", \"alias\": \"enc\"}` → use `@enc.function()`\n- In `_test.mbt` or `_wbtest.mbt` files, the package being tested is auto-imported\n\nExample:\n\n```mbt\n///|\n/// In main.mbt after importing \"username/hello/liba\" in `moon.pkg.json`\nfn main {\n  println(@liba.hello()) // Calls hello() from liba package\n}\n```\n\n### Using Standard Library (moonbitlang/core)\n\n**MoonBit standard library (moonbitlang/core) packages are automatically imported** - DO NOT add them to dependencies:\n\n- ❌ **DO NOT** use `moon add` to add standard library packages like `moonbitlang/core/strconv`\n- ❌ **DO NOT** add standard library packages to `\"deps\"` field of `moon.mod.json`\n- ❌ **DO NOT** add standard library packages to `\"import\"` field of `moon.pkg.json`\n- ✅ **DO** use them directly: `@strconv.parse_int()`, `@list.List`, `@array.fold()`, etc.\n\nIf you get an error like \"cannot import `moonbitlang/core/strconv`\", remove it from imports - it's automatically available.\n\n### Creating Packages\n\nTo add a new package `fib` under `.`:\n\n1. Create directory: `./fib/`\n2. Add `./fib/moon.pkg.json`: `{}` -- Minimal valid moon.pkg.json\n3. Add `.mbt` files with your code\n4. Import in dependent packages:\n\n   ```json\n   {\n     \"import\": [\n        \"username/hello/fib\",\n        ...\n     ]\n   }\n   ```\nFor more advanced topics like `conditional compilation`, `link configuration`, `warning control`, and `pre-build commands`, see `references/advanced-moonbit-build.md`.\n\n# MoonBit Language Tour\n\n## Core facts\n\n- **Expression‑oriented**: `if`, `match`, loops return values; last expression is the return.\n- **References by default**: Arrays/Maps/structs mutate via reference; use `Ref[T]` for primitive mutability.\n- **Blocks**: Separate top‑level items with `///|`. Generate code block‑by‑block.\n- **Visibility**: `fn` private by default; `pub` exposes read/construct as allowed; `pub(all)` allows external construction.\n- **Naming convention**: lower_snake for values/functions; UpperCamel for types/enums; enum variants start UpperCamel.\n- **Packages**: No `import` in code files; call via `@alias.fn`. Configure imports in `moon.pkg.json`.\n- **Placeholders**: `...` is a valid placeholder in MoonBit code for incomplete implementations.\n- **Global values**: immutable by default and generally require type annotations.\n- **Garbage collection**: MoonBit has a GC, there is no lifetime annotation, there's no ownership system.\n  Unlike Rust, like F#, `let mut` is only needed when you want to reassign a variable, not for mutating fields of a struct or elements of an array/map.\n- **Delimit top-level items with `///|` comments** so tools can split the file reliably.\n\n## MoonBit Error Handling (Checked Errors)\n\nMoonBit uses checked error-throwing functions, not unchecked exceptions. All errors are subtype of `Error`, we can declare our own error types by `suberror`.\nUse `raise` in signatures to declare error types and let errors propagate by\ndefault. Use `try?` to convert to `Result[...]` in tests, or `try { } catch { }`\nto handle errors explicitly.\n\n```mbt check\n///|\n/// Declare error types with 'suberror'\nsuberror ValueError String\n\n///|\n/// Tuple struct to hold position info\nstruct Position(Int, Int) derive(ToJson, Show, Eq) \n\n///|\n/// ParseError is subtype of Error\npub(all) suberror ParseError {\n  InvalidChar(pos~:Position, Char) // pos is labeled\n  InvalidEof(pos~:Position)\n  InvalidNumber(pos~:Position, String)\n  InvalidIdentEscape(pos~:Position)\n} derive(Eq, ToJson, Show)\n\n///|\n/// Functions declare what they can throw\nfn parse_int(s : String, position~ : Position) -> Int raise ParseError {\n  // 'raise' throws an error\n  if s is \"\" {\n    raise ParseError::InvalidEof(pos=position)\n  }\n  ... // parsing logic\n}\n\n///|\n/// Just declare `raise` to not track specific error types\nfn div(x : Int, y : Int) -> Int raise {\n  if y is 0 {\n    fail(\"Division by zero\")\n  }\n  x / y\n}\n\n///|\ntest \"inspect raise function\" {\n  let result : Result[Int, Error] = try? div(1, 0) \n  guard result is Err(Failure(msg)) && msg.contains(\"Division by zero\") else {\n    fail(\"Expected error\")\n  }  \n}\n\n// Three ways to handle errors:\n\n///|\n/// Propagate automatically\nfn use_parse(position~: Position) -> Int raise ParseError {\n  let x = parse_int(\"123\", position=position)\n  // Error auto-propagates by default.\n  // Unlike Swift, you do not need to mark `try` for functions that can raise\n  // errors; the compiler infers it automatically. This keeps error handling\n  // explicit but concise.\n  x * 2\n}\n\n///|\n/// Mark `raise` for all possible errors, do not care which error it is.\n/// For quick prototypes, `raise` is acceptable.\nfn use_parse2(position~: Position) -> Int raise {\n  let x = parse_int(\"123\", position=position)\n  x * 2\n}\n\n///|\n/// Convert to Result with try?\nfn safe_parse(s : String, position~: Position) -> Result[Int, ParseError] {\n  let val1 : Result[_] = try? parse_int(s, position=position) // Returns Result[Int, ParseError]\n  // try! is rarely used - it panics on error, similar to unwrap() in Rust\n  // let val2 : Int = try! parse_int(s) // Returns Int otherwise crash\n\n  // Alternative explicit handling:\n  let val3 = try parse_int(s, position=position) catch {\n    err => Err(err)\n  } noraise { // noraise block is optional - handles the success case\n    v => Ok(v)\n  }\n  ...\n}\n\n///|\n/// Handle with try-catch\nfn handle_parse(s : String, position~: Position) -> Int {\n  try parse_int(s, position=position) catch {\n    ParseError::InvalidEof => {\n      println(\"Parse failed: InvalidEof\")\n      -1 // Default value\n    }\n    _ => 2\n  }\n}\n```\n\nImportant: When calling a function that can raise errors, if you only want to\npropagate the error, you do not need any marker; the compiler infers it.\n\n## Integers, Char\n\nMoonBit supports Byte, Int16, Int, UInt16, UInt, Int64, UInt64, etc. When the type is known,\nthe literal can be overloaded:\n\n```mbt check\n///|\ntest \"integer and char literal overloading disambiguation via type in the current context\" {\n  let a0 = 1 // a is Int by default\n  let (int, uint, uint16, int64, byte) : (Int, UInt, UInt16, Int64, Byte) = (\n    1, 1, 1, 1, 1,\n  )\n  assert_eq(int, uint16.to_int())\n  let a1 : Int = 'b' // this also works, a5 will be the unicode value\n  let a2 : Char = 'b'\n}\n```\n## Bytes (Immutable)\n\n```mbt check\n///|\ntest \"bytes literals overloading and indexing\" {\n  let b0 : Bytes = b\"abcd\"\n  let b1 : Bytes = \"abcd\" // b\" prefix is optional, when we know the type\n  let b2 : Bytes = [0xff, 0x00, 0x01] // Array literal overloading\n  guard b0 is [b'a', ..] && b0[1] is b'b' else {\n    // Bytes can be pattern matched as BytesView and indexed\n    fail(\"unexpected bytes content\")\n  }\n  \n}\n```\n## Array (Resizable)\n\n```mbt check\n///|\ntest \"array literals overloading: disambiguation via type in the current context\" {\n  let a0 : Array[Int] = [1, 2, 3] // resizable\n  let a1 : FixedArray[Int] = [1, 2, 3] // Fixed size\n  let a2 : ReadOnlyArray[Int] = [1, 2, 3] \n  let a3 : ArrayView[Int] = [1, 2, 3]\n}\n```\n## String (Immutable UTF-16)\n`s[i]` returns a code unit (UInt16), `s.get_char(i)` returns `Char?`.\nSince MoonBit supports char literal overloading, you can write code snippets like this:\n\n```mbt check\n///|\ntest \"string indexing and utf8 encode/decode\" {\n  let s = \"hello world\"\n  let b0 : UInt16 = s[0]\n  guard(b0 is ('\\n' | 'h' | 'b' | 'a'..='z') && s is [..\"hello\", ..rest]) else {\n    fail(\"unexpected string content\")\n  }\n  guard rest is \" world\" // otherwise will crash (guard without else)\n  \n  // In check mode (expression with explicit type), ('\\n' : UInt16) is valid.\n  \n  // Using get_char for Option handling\n  let b1 : Char? = s.get_char(0)\n  assert_true(b1 is Some('a'..='z'))\n\n  // ⚠️ Important: Variables won't work with direct indexing\n  let eq_char : Char = '='\n  // s[0] == eq_char // ❌ Won't compile - eq_char is not a literal, lhs is UInt while rhs is Char\n  // Use: s[0] == '=' or s.get_char(0) == Some(eq_char)\n  let bytes = @encoding/utf8.encode(\"中文\") // utf8 encode package is in stdlib\n  assert_true(bytes is [0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87])\n  let s2 : String = @encoding/utf8.decode(bytes) // decode utf8 bytes back to String\n  assert_true(s2 is \"中文\")\n  for c in \"中文\" {\n    let _ : Char = c // unicode safe iteration  \n    println(\"char: \\{c}\") // iterate over chars\n  }\n}\n```\n\n### String Interpolation && StringBuilder\n\nMoonBit uses `\\{}` for string interpolation, for custom types, it needs implement trait `Show`\n\n```mbt check\n///|\ntest \"string interpolation basics\" {\n\n  let name : String = \"Moon\"\n  let config = { \"cache\": 123 }\n  let version = 1.0\n  println(\"Hello \\{name} v\\{version}\") // \"Hello Moon v1.0\"\n  // ❌ Wrong - quotes inside interpolation not allowed:\n  // println(\"  - Checking if 'cache' section exists: \\{config[\"cache\"]}\")\n\n  // ✅ Correct - extract to variable first:\n  let has_key = config[\"cache\"] // `\"` not allowed in interpolation\n  println(\"  - Checking if 'cache' section exists: \\{has_key}\")\n  \n  let sb = StringBuilder::new()\n  sb..write_char('[') // dotdot for imperative method chaining\n    ..write_view([1,2,3].map((x) => \"\\{x}\").join(\",\"))\n    ..write_char(']')\n  inspect(sb.to_string(), content=\"[1,2,3]\")\n}\n```\n\nExpressions inside `\\{}` can only be _basic expressions_ (no quotes, newlines, or nested interpolations). String literals are not allowed as it makes lexing too difficult.\n\n\n### Multiple line strings\n\n```mbt check\n///|\ntest \"multi-line string literals\" {  \n  let multi_line_string : String =\n    #|Hello \"world\"\n    #|World\n    #|\n  let multi_line_string_with_interp : String =\n    $|Line 1 \"\"\n    $|Line 2 \\{1+2}\n    $|\n  // no escape in `#|`, \n  // only escape '\\{..}` in `$|`\n  assert_eq(multi_line_string, \"Hello \\\"world\\\"\\nWorld\\n\")  \n  assert_eq(multi_line_string_with_interp, \"Line 1 \\\"\\\"\\nLine 2 3\\n\")\n}\n```\n\n## Map (Mutable, Insertion-Order Preserving)\n\n```mbt check\n///|\ntest \"map literals and common operations\" {\n  // Map literal syntax\n  let map : Map[String, Int] = { \"a\": 1, \"b\": 2, \"c\": 3 }  \n  let empty : Map[String, Int] = {} // Empty map, preferred\n  let also_empty : Map[String, Int] = Map::new()\n  // From array of pairs\n  let from_pairs : Map[String, Int] = Map::from_array([(\"x\", 1), (\"y\", 2)])\n\n  // Set/update value\n  map[\"new-key\"] = 3\n  map[\"a\"] = 10 // Updates existing key\n\n  // Get value - returns Option[T]\n  guard map is { \"new-key\": 3, \"missing\"? : None, .. } else {\n    fail(\"unexpected map contents\")\n  }\n\n  // Direct access (panics if key missing)\n  let value : Int = map[\"a\"] // value = 10\n\n  // Iteration preserves insertion order\n  for k, v in map {\n    println(\"\\{k}: \\{v}\") // Prints: a: 10, b: 2, c: 3, new-key: 3\n  }\n\n  // Other common operations\n  map.remove(\"b\")\n  guard map is { \"a\": 10, \"c\": 3, \"new-key\": 3, .. } && map.length() == 3 else {\n    // \"b\" is gone, only 3 elements left  \n    fail(\"unexpected map contents after removal\")\n  }\n}\n```\n\n## View Types\n\n**Key Concept**: View types (`StringView`, `BytesView`, `ArrayView[T]`) are zero-copy, non-owning read-only slices created with the `[:]` syntax. They don't allocate memory and are ideal for passing sub-sequences without copying data, for function which takes String, Bytes, Array, they also take *View(implicit conversion).\n\n- `String` → `StringView` via `s[:]` or `s[start:end]`\n- `Bytes` → `BytesView` via `b[:]` or `b[start:end]`\n- `Array[T]`, `FixedArray[T]`, `ReadOnlyArray[T] → `ArrayView[T]` via `a[:]` or `a[start:end]`\n\n**Important**: StringView slice is slightly different due to unicode safety:\n`s[a:b]` may raise an error at surrogate boundaries (UTF-16 encoding edge case). You have two options:\n\n- Use `try! s[a:b]` if you're certain the boundaries are valid (crashes on invalid boundaries)\n- Let the error propagate to the caller for proper handling\n\n**When to use views**:\n\n- Pattern matching with rest patterns (`[first, .. rest]`)\n- Passing slices to functions without allocation overhead\n- Avoiding unnecessary copies of large sequences\n\nConvert back with `.to_string()`, `.to_bytes()`, or `.to_array()` when you need ownership. (`moon doc StringView`)\n\n## User defined types(`enum`, `struct`)\n\n```mbt check\n///|\nenum Tree[T] {\n  Leaf(T) // Unlike Rust, no comma here\n  Node(left~ : Tree[T], T, right~ : Tree[T]) // enum can use labels\n} derive(Show, ToJson) // derive traits for Tree\n\n///|\npub fn Tree::sum(tree : Tree[Int]) -> Int {\n  match tree {\n    Leaf(x) => x \n    // we don't need to write Tree::Leaf, when `tree` has a known type\n    Node(left~, x, right~) => left.sum() + x + right.sum() // method invoked in dot notation\n  }\n}\n\n///|\nstruct Point {\n  x : Int\n  y : Int\n} derive(Show, ToJson) // derive traits for Point\n\ntest \"user defined types: enum and struct\" {\n  @json.inspect(Point::{ x: 10, y: 20 }, content=({\"x\":10,\"y\":20}))\n}\n\n```\n\n## Functional `for` loop\n\n\n```mbt check\npub fn binary_search(\n  arr : ArrayView[Int],\n  value : Int,\n) -> Result[Int, Int] {\n  let len = arr.length()\n  // functional for loop:\n  // initial state ; [predicate] ; [post-update] {\n  // loop body with `continue` to update state\n  //} else { // exit block\n  // }\n  // predicate and post-update are optional\n  for i = 0, j = len; i < j; {\n    // post-update is omitted, we use `continue` to update state\n    let h = i + (j - i) / 2\n    if arr[h] < value {\n      continue h + 1, j // functional update of loop state\n    } else {\n      continue i, h // functional update of loop state\n    }\n  } else { // exit of for loop\n    if i < len && arr[i] == value {\n      Ok(i)\n    } else {\n      Err(i)\n    }\n  } where {\n    invariant : 0 <= i && i <= j && j <= len,\n    invariant : i == 0 || arr[i - 1] < value,\n    invariant : j == len || arr[j] >= value,\n    reasoning :\n      #|For a sorted array, the boundary invariants are witnesses:\n      #|  - `arr[i-1] < value` implies all arr[0..i) < value (by sortedness)\n      #|  - `arr[j] >= value` implies all arr[j..len) >= value (by sortedness)\n      #|\n      #|Preservation proof:\n      #|  - When arr[h] < value: new_i = h+1, and arr[new_i - 1] = arr[h] < value ✓\n      #|  - When arr[h] >= value: new_j = h, and arr[new_j] = arr[h] >= value ✓\n      #|\n      #|Termination: j - i decreases each iteration (h is strictly between i and j)\n      #|\n      #|Correctness at exit (i == j):\n      #|  - By invariants: arr[0..i) < value and arr[i..len) >= value\n      #|  - So if value exists, it can only be at index i\n      #|  - If arr[i] != value, then value is absent and i is the insertion point\n      #|\n  }\n}\n\n///|\ntest \"functional for loop control flow\" {\n  let arr : Array[Int] = [1, 3, 5, 7, 9]\n  inspect(binary_search(arr,5), content=\"Ok(2)\") // Array to ArrayView implicit conversion when passing as arguments\n  inspect(binary_search(arr,6), content=\"Err(3)\")\n  // for iteration is supported too\n  for i, v in arr {\n    println(\"\\{i}: \\{v}\") // `i` is index, `v` is value\n  }\n}\n```\nYou are *STRONGLY ENCOURAGED* to use functional `for` loops instead of imperative loops\n*WHENEVER POSSIBLE*, as they are easier to reason about.\n\n### Loop Invariants with `where` Clause\n\nThe `where` clause attaches **machine-checkable invariants** and **human-readable reasoning** to functional `for` loops. This enables formal verification thinking while keeping the code executable. Note for trivial loops, you are encouraged to convert it into `for .. in` so no reasoning is needed.\n\n**Syntax:**\n```mbt nocheck\nfor ... {\n  ...\n} where {\n  invariant : <boolean_expr>,   // checked at runtime in debug builds\n  invariant : <boolean_expr>,   // multiple invariants allowed\n  reasoning : <string>         // documentation for proof sketch\n}\n```\n\n**Writing Good Invariants:**\n\n1. **Make them checkable**: Invariants must be valid MoonBit boolean expressions using loop variables and captured values.\n\n2. **Use boundary witnesses**: For properties over ranges (e.g., \"all elements in arr[0..i) satisfy P\"), check only boundary elements. For sorted arrays, `arr[i-1] < value` implies all `arr[0..i) < value`.\n\n3. **Handle edge cases with `||`**: Use patterns like `i == 0 || arr[i-1] < value` to handle boundary conditions where the check would be out of bounds.\n\n4. **Cover three aspects in reasoning**:\n   - **Preservation**: Why each `continue` maintains the invariants\n   - **Termination**: Why the loop eventually exits (e.g., a decreasing measure)\n   - **Correctness**: Why the invariants at exit imply the desired postcondition\n\n## Label and Optional Parameters\n\nGood example: use labeled and optional parameters\n\n```mbt check\n///|\nfn g(\n  positional : Int,\n  required~ : Int,\n  optional? : Int, // no default => Option\n  optional_with_default? : Int = 42, // default => plain Int\n) -> String {\n  // These are the inferred types inside the function body.\n  let _ : Int = positional\n  let _ : Int = required\n  let _ : Int? = optional\n  let _ : Int = optional_with_default\n  \"\\{positional},\\{required},\\{optional},\\{optional_with_default}\"\n}\n\n///|\ntest {\n  inspect(g(1, required=2), content=\"1,2,None,42\")\n  inspect(g(1, required=2, optional=3), content=\"1,2,Some(3),42\")\n  inspect(g(1, required=4, optional_with_default=100), content=\"1,4,None,100\")\n}\n```\n\nMisuse: `arg : Type?` is not an optional parameter.\nCallers still must pass it (as `None`/`Some(...)`).\n\n```mbt check\n///|\nfn with_config(a : Int?, b : Int?, c : Int) -> String {\n  \"\\{a},\\{b},\\{c}\"\n}\n\n///|\ntest {\n  inspect(with_config(None, None, 1), content=\"None,None,1\")\n  inspect(with_config(Some(5), Some(5), 1), content=\"Some(5),Some(5),1\")\n}\n```\n\nAnti-pattern: `arg? : Type?` (no default => double Option).\nIf you want a defaulted optional parameter, write `b? : Int = 1`, not `b? : Int? = Some(1)`.\n\n```mbt check\n///|\nfn f_misuse(a? : Int?, b? : Int = 1) -> Unit {\n  let _ : Int?? = a // rarely intended\n  let _ : Int = b\n\n}\n// How to fix: declare `(a? : Int, b? : Int = 1)` directly.\n\n///|\nfn f_correct(a? : Int, b? : Int = 1) -> Unit {\n  let _ : Int? = a\n  let _ : Int = b\n\n}\n\n///|\ntest {\n  f_misuse(b=3)\n  f_misuse(a=Some(5), b=2) // works but confusing\n  f_correct(b=2)\n  f_correct(a=5)\n}\n```\n\nBad example: `arg : APIOptions` (use labeled optional parameters instead)\n\n```mbt check\n///|\n/// Do not use struct to group options.\nstruct APIOptions {\n  width : Int?\n  height : Int?\n}\n\n///|\nfn not_idiomatic(opts : APIOptions, arg : Int) -> Unit {\n\n}\n\n///|\ntest {\n  // Hard to use in call site\n  not_idiomatic({ width : Some(5), height : None }, 10)\n  not_idiomatic({ width : None, height : None }, 10)\n}\n```\n\n## More details\n\nFor deeper syntax, types, and examples, read `references/moonbit-language-fundamentals.mbt.md`.\n","skills/moonbit/ide.md":"## Code Navigation with `moon ide`\n\n**ALWAYS use `moon ide` for code navigation in MoonBit projects instead of manual file searching, grep, or semantic search.**\n\nThis tool provides two essential commands for precise code exploration:\n\n### Core Commands\n\n- `moon ide goto-definition` - Find where a symbol is defined\n- `moon ide find-references` - Find all usages of a symbol\n\n### Query System\n\nSymbol lookup uses a two-part query system for precise results:\n\n#### 1. Symbol Name Query (`-query`)\n\nFuzzy search for symbol names with package filtering support:\n\n```bash\n# Find any symbol named 'symbol'\nmoon ide goto-definition -query 'symbol'\n\n# Find methods of a specific type\nmoon ide goto-definition -query 'Type::method'\n\n# Find trait method implementations\nmoon ide goto-definition -query 'Trait for Type with method'\n\n# Find symbol in specific package using @pkg prefix\nmoon ide goto-definition -query '@moonbitlang/x encode'\n\n# Find symbol in multiple packages (searches in pkg1 OR pkg2)\nmoon ide goto-definition -query '@username/mymodule/pkg1 @username/mymodule/pkg2 helper'\n\n# Find symbol in nested package\nmoon ide goto-definition -query '@username/mymodule/mypkg helper'\n```\n\n**Supported symbols**: functions, constants, let bindings, types, structs, enums, traits\n\n**Package filtering**: Prefix your query with `@package_name` to scope the search. Multiple `@pkg` prefixes create an OR condition.\n\n#### 2. Tag-based Filtering (`-tags`)\n\nPre-filter symbols by characteristics before name matching:\n\n**Visibility tags**:\n\n- `pub` - Public symbols\n- `pub all` - Public structs with all public fields\n- `pub open` - Public traits with all methods public\n- `priv` - Private symbols\n\n**Symbol type tags**:\n\n- `type` - Type definitions (struct, enum, typealias, abstract)\n- `error` - Error type definitions\n- `enum` - Enum definitions and variants\n- `struct` - Struct definitions\n- `alias` - Type/function/trait aliases\n- `let` - Top-level let bindings\n- `const` - Constant definitions\n- `fn` - Function definitions\n- `trait` - Trait definitions\n- `impl` - Trait implementations\n- `test` - Named test functions\n\n**Combine tags with logical operators**:\n\n```bash\n# Public functions only\nmoon ide goto-definition -tags 'pub fn' -query 'my_func'\n\n# Functions or constants\nmoon ide goto-definition -tags 'fn | const' -query 'helper'\n\n# Public functions or constants\nmoon ide goto-definition -tags 'pub (fn | const)' -query 'api'\n\n# Public types or traits\nmoon ide goto-definition -tags 'pub (type | trait)' -query 'MyType'\n```\n\n### Practical Examples\n\n```bash\n# Find public function definition\nmoon ide goto-definition -tags 'pub fn' -query 'maximum'\n\n# Find all references to a struct\nmoon ide find-references -tags 'struct' -query 'Rectangle'\n\n# Find trait implementations\nmoon ide goto-definition -tags 'impl' -query 'Show for MyType'\n\n# Find errors in specific package\nmoon ide goto-definition -tags 'error' -query '@mymodule/parser ParseError'\n\n# Find symbol across multiple packages\nmoon ide goto-definition -query '@moonbitlang/x @moonbitlang/core encode'\n\n# Combine package filtering with tags\nmoon ide goto-definition -tags 'pub fn' -query '@username/myapp helper'\n```\n\n### Query Processing\n\nThe tool processes queries in this order:\n\n1. Filter symbols by `-tags` conditions\n2. Extract package scope from `@pkg` prefixes in `-query`\n3. Fuzzy match remaining symbols by name\n4. Return top 3 best matches with location information\n\n**Best Practice**: Start with `-tags` to reduce noise, then use `@pkg` prefixes in `-query` to scope by package for precise navigation.\n","skills/moonbit/references/advanced-moonbit-build.md":"## Conditional Compilation\n\nTarget specific backends/modes in `moon.pkg.json`:\n\n```json\n{\n  \"targets\": {\n    \"wasm_only.mbt\": [\"wasm\"],\n    \"js_only.mbt\": [\"js\"],\n    \"debug_only.mbt\": [\"debug\"],\n    \"wasm_or_js.mbt\": [\"wasm\", \"js\"], // for wasm or js backend\n    \"not_js.mbt\": [\"not\", \"js\"], // for nonjs backend\n    \"complex.mbt\": [\"or\", [\"and\", \"wasm\", \"release\"], [\"and\", \"js\", \"debug\"]] // more complex conditions\n  }\n}\n```\n\n**Available conditions:**\n\n- **Backends**: `\"wasm\"`, `\"wasm-gc\"`, `\"js\"`, `\"native\"`\n- **Build modes**: `\"debug\"`, `\"release\"`\n- **Logical operators**: `\"and\"`, `\"or\"`, `\"not\"`\n\n## Link Configuration\n\n### Basic Linking\n\n```json\n{\n  \"link\": true, // Enable linking for this package\n  // OR for advanced cases:\n  \"link\": {\n    \"wasm\": {\n      \"exports\": [\"hello\", \"foo:bar\"], // Export functions\n      \"heap-start-address\": 1024, // Memory layout\n      \"import-memory\": {\n        // Import external memory\n        \"module\": \"env\",\n        \"name\": \"memory\"\n      },\n      \"export-memory-name\": \"memory\" // Export memory with name\n    },\n    \"wasm-gc\": {\n      \"exports\": [\"hello\"],\n      \"use-js-builtin-string\": true, // JS String Builtin support\n      \"imported-string-constants\": \"_\" // String namespace\n    },\n    \"js\": {\n      \"exports\": [\"hello\"],\n      \"format\": \"esm\" // \"esm\", \"cjs\", or \"iife\"\n    },\n    \"native\": {\n      \"cc\": \"gcc\", // C compiler\n      \"cc-flags\": \"-O2 -DMOONBIT\", // Compile flags\n      \"cc-link-flags\": \"-s\" // Link flags\n    }\n  }\n}\n```\n\n## Warning Control\n\nDisable specific warnings in `moon.mod.json` or `moon.pkg.json`:\n\n```json\n{\n  \"warn-list\": \"-2-29\" // Disable unused variable (2) & unused package (29)\n}\n```\n\n**Common warning numbers:**\n\n- `1` - Unused function\n- `2` - Unused variable\n- `11` - Partial pattern matching\n- `12` - Unreachable code\n- `29` - Unused package\n\nUse `moonc build-package -warn-help` to see all available warnings.\n\n## Pre-build Commands\n\nEmbed external files as MoonBit code:\n\n```json\n{\n  \"pre-build\": [\n    {\n      \"input\": \"data.txt\",\n      \"output\": \"embedded.mbt\",\n      \"command\": \":embed -i $input -o $output --name data --text\"\n    },\n    ... // more embed commands\n  ]\n}\n```\n\nGenerated code example:\n\n```mbt check\n///|\nlet data : String =\n  #|hello,\n  #|world\n  #|\n```\n","skills/moonbit/references/moonbit-language-fundamentals.mbt.md":"# MoonBit Language Fundamentals\n\n\n## Quick reference:\n\n```mbt check\n///|\n/// comments doc string\npub fn sum(x : Int, y : Int) -> Int {\n  x + y\n}\n\n///|\nstruct Rect {\n  width : Int\n  height : Int\n}\n\n///|\nfn Rect::area(self : Rect) -> Int {\n  self.width * self.height\n}\n\n///|\npub impl Show for Rect with output(_self, logger) {\n  logger.write_string(\"Rect\")\n}\n\n///|\nenum MyOption {\n  MyNone\n  MySome(Int)\n} derive(Show, ToJson, Eq, Compare)\n\n///|\n///  match + loops are expressions\ntest \"everything is expression in MoonBit\" {\n  // tuple\n  let (n, opt) = (1, MySome(2))\n  // if expressions return values\n  let msg : String = if n > 0 { \"pos\" } else { \"non-pos\" }\n  let res = match opt {\n    MySome(x) => {\n      inspect(x, content=\"2\")\n      1\n    }\n    MyNone => 0\n  }\n  let status : Result[Int, String] = Ok(10)\n  // match expressions return values\n  let description = match status {\n    Ok(value) => \"Success: \\{value}\"\n    Err(error) => \"Error: \\{error}\"\n  }\n  let array = [1, 2, 3, 4, 5]\n  let mut i = 0 // mutable bindings (local only, globals are immutable)\n  let target = 3\n  // loops return values with 'break'\n  let found : Int? = while i < array.length() {\n    if array[i] == target {\n      break Some(i) // Exit with value\n    }\n    i = i + 1\n  } else { // Value when loop completes normally\n    None\n  }\n  assert_eq(found, Some(2)) // Found at index 2\n}\n\n///|\n/// global bindings\npub let my_name : String = \"MoonBit\"\n\n///|\npub const PI : Double = 3.14159 // constants use UPPER_SNAKE or PascalCase\n\n///|\npub fn maximum(xs : Array[Int]) -> Int raise {\n  // Toplevel functions are *mutually recursive* by default\n  // `raise` annotation means the function would raise any Error\n  //  Only add `raise XXError` when you do need track the specific error type\n  match xs {\n    [] => fail(\"Empty array\") // fail() is built-in for generic errors\n    [x] => x\n    // pattern match over array, the `.. rest` is a rest pattern\n    // it is of type `ArrayView[Int]` which is a slice\n    [x, .. rest] => {\n      let mut max_val = x // `mut` only allowed in local bindings\n      for y in rest {\n        if y > max_val {\n          max_val = y\n        }\n      }\n      max_val // return can be omitted if the last expression is the return value\n    }\n  }\n}\n\n///|\n/// pub(all) means it can be both read and created outside the package\npub(all) struct Point {\n  x : Int\n  mut y : Int\n} derive(Show, ToJson)\n\n///|\npub enum MyResult[T, E] {\n  MyOk(T) // semicolon `;` is optional when we have a newline\n  MyErr(E) // Enum variants must start uppercase\n} derive(Show, Eq, ToJson)\n// pub means it can only be pattern matched outside the package\n// but it can not be created outside the package, use `pub(all)` otherwise\n\n///|\n/// pub (open) means the trait can be implemented for outside packages\npub(open) trait Comparable {\n  compare(Self, Self) -> Int // `Self` refers to the implementing type\n}\n\n///|\ntest \"inspect test\" {\n  let result = sum(1, 2)\n  inspect(result, content=\"3\")\n  // The `content` can be auto-corrected by running `moon test --update`\n  let point = Point::{ x: 10, y: 20 }\n  // For complex structures, use @json.inspect for better readability:\n  @json.inspect(point, content={ \"x\": 10, \"y\": 20 })\n}\n```\n\n\n## Complex Types\n\n```mbt check\n///|\npub type UserId = Int // Int is aliased to UserId - like symlink\n\n///|\n///  Tuple-struct for callback\npub struct Handler((String) -> Unit) // A newtype wrapper\n\n///|\n/// Tuple-struct syntax for single-field newtypes\nstruct Meters(Int) // Tuple-struct syntax\n\n///|\nlet distance : Meters = Meters(100)\n\n///|\nlet raw : Int = distance.0 // Access first field with .0\n\n///|\nstruct Addr {\n  host : String\n  port : Int\n} derive(Show, Eq, ToJson, FromJson)\n\n///|\n/// Structural types with literal syntax\nlet config : Addr = Addr::{\n  // `Type::` can be omitted since the type is already known\n  host: \"localhost\",\n  port: 8080,\n}\n\n\n```\n\n## Common Derivable Traits\n\nMost types can automatically derive standard traits using the `derive(...)` syntax:\n\n- **`Show`** - Enables `to_string()` and string interpolation with `\\{value}`\n- **`Eq`** - Enables `==` and `!=` equality operators\n- **`Compare`** - Enables `<`, `>`, `<=`, `>=` comparison operators\n- **`ToJson`** - Enables `@json.inspect()` for readable test output\n- **`Hash`** - Enables use as Map keys\n\n```mbt check\n///|\nstruct Coordinate {\n  x : Int\n  y : Int\n} derive(Show, Eq, ToJson)\n\n///|\nenum Status {\n  Active\n  Inactive\n} derive(Show, Eq, Compare)\n```\n\n**Best practice**: Always derive `Show` and `Eq` for data types. Add `ToJson` if you plan to test them with `@json.inspect()`.\n\n## Reference Semantics by Default\n\nMoonBit passes most types by reference semantically (the optimizer may copy\nimmutables):\n\n```mbt check\n///|\n///  Structs with 'mut' fields are always passed by reference\nstruct Counter {\n  mut value : Int\n}\n\n///|\nfn increment(c : Counter) -> Unit {\n  c.value += 1 // Modifies the original\n}\n\n///|\n/// Arrays and Maps are mutable references\nfn modify_array(arr : Array[Int]) -> Unit {\n  arr[0] = 999 // Modifies original array\n}\n\n///|\ntest \"reference semantics\" {\n  let counter : Ref[Int] = Ref::{ val: 0 }\n  counter.val += 1\n  assert_true(counter.val is 1)\n  let arr : Array[Int] = [1, 2, 3] // unlike Rust, no `mut` keyword needed\n  modify_array(arr)\n  assert_true(arr[0] is 999)\n  let mut x = 3 // `mut` neeed for re-assignment to the bindings\n  x += 2\n  assert_true(x is 5)\n}\n```\n\n## Pattern Matching\n\n```mbt check\n///|\n#warnings(\"-unused_value\")\ntest \"pattern match over Array, struct and StringView\" {\n  let arr : Array[Int] = [10, 20, 25, 30]\n  match arr {\n    [] => ... // empty array\n    [single] => ... // single element\n    [first, .. middle, rest] => {\n      let _ : ArrayView[Int] = middle // middle is ArrayView[Int]  \n      assert_true(first is 10 && middle is [20, 25] && rest is 30)\n    }\n  }\n  fn process_point(point : Point) -> Unit {\n    match point {\n      { x: 0, y: 0 } => ...\n      { x, y } if x == y => ...\n      { x, .. } if x < 0 => ...\n      ...\n    }\n  }\n  /// StringView pattern matching for parsing\n  fn is_palindrome(s : StringView) -> Bool {\n    loop s {\n      [] | [_] => true\n      [a, .. rest, b] if a == b => continue rest\n      // a is of type Char, rest is of type StringView\n      _ => false\n    }\n  }\n\n\n}\n```\n\n## Functional `loop` control flow\n\nThe `loop` construct is unique to MoonBit:\n\n```mbt check\n///|\n/// Functional loop with pattern matching on loop variables\n/// @list.List is from the standard library\nfn sum_list(list : @list.List[Int]) -> Int {\n  loop (list, 0) {\n    (Empty, acc) => acc // Base case returns accumulator\n    (More(x, tail=rest), acc) => continue (rest, x + acc) // Recurse with new values\n  }\n}\n\n///|\n///  Multiple loop variables with complex control flow\nfn find_pair(arr : Array[Int], target : Int) -> (Int, Int)? {\n  loop (0, arr.length() - 1) {\n    (i, j) if i >= j => None\n    (i, j) => {\n      let sum = arr[i] + arr[j]\n      if sum == target {\n        Some((i, j)) // Found pair\n      } else if sum < target {\n        continue (i + 1, j) // Move left pointer\n      } else {\n        continue (i, j - 1) // Move right pointer\n      }\n    }\n  }\n}\n```\n\n**Note**: You must provide a payload to `loop`. If you want an infinite loop, use `while true { ... }` instead. The syntax `loop { ... }` without arguments is invalid.\n\n\n## Methods and Traits\n\nMethods use `Type::method_name` syntax, traits require explicit implementation:\n\n```mbt check\n///|\nstruct Rectangle {\n  width : Double\n  height : Double\n}\n\n///|\n// Methods are prefixed with Type::\nfn Rectangle::area(self : Rectangle) -> Double {\n  self.width * self.height\n}\n\n///|\n/// Static methods don't need self\nfn Rectangle::new(w : Double, h : Double) -> Rectangle {\n  { width: w, height: h }\n}\n\n///|\n/// Show trait now uses output(self, logger) for custom formatting\n/// to_string() is automatically derived from this\npub impl Show for Rectangle with output(self, logger) {\n  logger.write_string(\"Rectangle(\\{self.width}x\\{self.height})\")\n}\n\n///|\n/// Traits can have non-object-safe methods\ntrait Named {\n  name() -> String // No 'self' parameter - not object-safe\n}\n\n///|\n/// Trait bounds in generics\nfn[T : Show + Named] describe(value : T) -> String {\n  \"\\{T::name()}: \\{value.to_string()}\"\n}\n\n///|\n///  Trait implementation\nimpl Hash for Rectangle with hash_combine(self, hasher) {\n  hasher..combine(self.width)..combine(self.height)\n}\n```\n\n## Operator Overloading\n\nMoonBit supports operator overloading through traits:\n\n```mbt check\n///|\nstruct Vector(Int, Int)\n\n///|\n/// Implement arithmetic operators\npub impl Add for Vector with add(self, other) {\n  Vector(self.0 + other.0, self.1 + other.1)\n}\n\n///|\nstruct Person {\n  age : Int\n} derive(Eq)\n\n///|\n/// Comparison operators\npub impl Compare for Person with compare(self, other) {\n  self.age.compare(other.age)\n}\n\n///|\ntest \"overloading\" {\n  let v1 : Vector = Vector(1, 2)\n  let v2 : Vector = Vector(3, 4)\n  let _v3 : Vector = v1 + v2\n\n}\n```\n\n## Access Control Modifiers\n\nMoonBit has fine-grained visibility control:\n\n```mbt check\n///|\n/// `fn` defaults to Private - only visible in current package\nfn internal_helper() -> Unit {\n  ...\n}\n\n///|\npub fn get_value() -> Int {\n  ...\n}\n\n///|\n// Struct (default) - type visible, implementation hidden\nstruct DataStructure {}\n\n///|\n/// `pub struct` defaults to readonly - can read, pattern match, but not create\npub struct Config {}\n\n///|\n///  Public all - full access\npub(all) struct Config2 {}\n\n///|\n/// Abstract trait (default) - cannot be implemented by\n/// types outside this package\npub trait MyTrait {}\n\n///|\n///  Open for extension\npub(open) trait Extendable {}\n```\n","skills/moonbit/references/moonbit-language-fundamentals.md":"moonbit-language-fundamentals.mbt.md"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Repository Guidelines\n\n## Project Snapshot\n\nLoro is a Rust CRDT workspace with JS/WASM packaging and a MoonBit codec.\n\n- `crates/loro`: public Rust API; avoid breaking downstream users.\n- `crates/loro-internal`: core CRDT logic. Read its\n  [AGENTS.md](crates/loro-internal/AGENTS.md) before changing import/export,\n  encoding, state, diff, checkout, or replay behavior.\n- `crates/loro-wasm`: `loro-crdt` WASM/TypeScript package. Read its\n  [AGENTS.md](crates/loro-wasm/AGENTS.md) before changing bindings, exports,\n  wrappers, or build scripts.\n- `crates/delta`, `crates/rle`, `crates/kv-store`, `crates/fractional_index`,\n  `crates/loro-common`, and `packages/fractional-index`: shared primitives and\n  packages.\n- `moon/`: MoonBit Loro binary codec; use [skills/moonbit/SKILL.md](skills/moonbit/SKILL.md).\n\n## Context Index\n\n- Undo/redo item boundaries when remote edits make an inverse a no-op:\n  [context/undo-history-boundaries.md](context/undo-history-boundaries.md).\n- Rust undo failure rollback and transaction writer serialization:\n  [context/undo-atomicity.md](context/undo-atomicity.md).\n- Encoding/import/export modes, current vs outdated formats, shallow snapshots:\n  [context/internal-encoding.md](context/internal-encoding.md).\n- Mergeable container model, marker/cid rules, tests, and common pitfalls:\n  [context/mergeable-containers.md](context/mergeable-containers.md).\n- `import_batch` force-detach, batch-wide rollback scope, and the never-exit-detached\n  invariant: [context/import-batch-atomicity.md](context/import-batch-atomicity.md).\n- Which root containers are visible (history-touched vs handle-acquired), and\n  why replays materialize empty roots:\n  [context/root-container-visibility.md](context/root-container-visibility.md).\n- Imports that reuse local op ids (a shared peer id): the known-history check,\n  what counts as equal, and what it cannot catch:\n  [context/import-peer-id-reuse.md](context/import-peer-id-reuse.md).\n- `apply_diff`/`revert_to` rollback of a failed batch, reused op ids, other\n  threads: [context/apply-diff-atomicity.md](context/apply-diff-atomicity.md).\n- Movable-list `Move`/`Set` import validation, and why a move of a deleted element\n  is applied rather than rejected:\n  [context/movable-list-op-validation.md](context/movable-list-op-validation.md).\n- Shallow-snapshot dead-style redaction (null-only, both-expand exclusion,\n  root-whitelisted latest state):\n  [context/shallow-snapshot-style-redaction.md](context/shallow-snapshot-style-redaction.md).\n- Rich-text insert positions next to style anchors, the insert cursor cache,\n  and delete `start_id`s: [context/richtext-insert-positions.md](context/richtext-insert-positions.md).\n- Tree diff cache transitions and why their lamport window comes from the two\n  versions, not the replay base: [context/tree-checkout-window.md](context/tree-checkout-window.md).\n- Tree event invariants (revived subtrees get `Create`s) and the two event\n  paths, diff-calculator vs raw ops: [context/tree-events.md](context/tree-events.md).\n- Deep tree traversal, snapshot order, and iterative result disposal:\n  [context/tree-depth.md](context/tree-depth.md).\n- loro.js tree diff item order, index counting, apply resolution, and batch dry-run:\n  [context/loro-js-tree-diff.md](context/loro-js-tree-diff.md).\n- loro.js concurrent tree moves, skipped cycles, replay, checkout, and undo:\n  [context/loro-js-tree-moves.md](context/loro-js-tree-moves.md).\n- User-facing Loro usage, sync, editor integration, and performance guidance:\n  [skills/loro/SKILL.md](skills/loro/SKILL.md).\n- Pure TypeScript runtime indexes, complexity contracts, benchmarks, and remaining gaps:\n  [context/loro-js-performance.md](context/loro-js-performance.md).\n- loro.js vs Rust randomized Text differential tests and the Rust behaviors they\n  work around: [context/loro-js-rust-differential.md](context/loro-js-rust-differential.md).\n- loro.js rich-text style anchors, entity positions, and Rust's insert/delete/mark\n  position rules: [context/loro-js-richtext-anchors.md](context/loro-js-richtext-anchors.md).\n- loro.js multi-peer differential fuzzing against replay, checkout, event, and\n  Rust/WASM oracles: [context/loro-js-differential-fuzz.md](context/loro-js-differential-fuzz.md).\n- loro.js MovableList model, the MovableList Rust differential suite\n  (`loro-js/tests/differential/`), and known loro.js/Rust divergences:\n  [context/loro-js-movable-list.md](context/loro-js-movable-list.md).\n- WASM panic/OOM reporting channels, `__wbindgen_start` glue invariant, and\n  trap-testing recipes:\n  [context/wasm-error-reporting.md](context/wasm-error-reporting.md).\n- WASM container id wrapper identity, lazy caching, and benchmark:\n  [context/wasm-container-id-cache.md](context/wasm-container-id-cache.md).\n- Bounded decoded-value cache in `InnerStore` (second-chance FIFO, eviction\n  safety contract, loro-dev/loro#1092):\n  [context/container-value-cache.md](context/container-value-cache.md).\n- Deep plain value decoding, Drop, and WASM conversion stack safety:\n  [context/deep-value-stack-safety.md](context/deep-value-stack-safety.md).\n- How the arena learns a container's parent (parsed changes, state KV, the op\n  log's creator resolver), its locking (including `ChangeStore`'s lock order),\n  and import rollback: [context/arena-parent-links.md](context/arena-parent-links.md).\n- Why a failed import's rollback keeps arena indices (DocState, caches and handlers\n  are keyed by them) and what it drops instead:\n  [context/failed-import-arena-indices.md](context/failed-import-arena-indices.md).\n- Which deletions `DocState::is_deleted` caches, and how tree/movable-list\n  children are revived: [context/dead-container-cache.md](context/dead-container-cache.md).\n- Movable-list `apply_diff`/undo: delete + re-insert of a child becomes a move,\n  cursor invariant, pitfalls: [context/movable-list-apply-diff.md](context/movable-list-apply-diff.md).\n- Unknown container types (newer-version containers): never created locally,\n  `apply_diff`/undo pre-check, events, test forging:\n  [context/unknown-containers.md](context/unknown-containers.md).\n- Why parsed change blocks keep text and list values out of doc-wide arenas\n  (`ValueSlice`, tracker tables): [context/text-arena-growth.md](context/text-arena-growth.md).\n- User callbacks that panic (subscribers, pre-commit, local updates): no poisoned\n  locks, lost events or hangs: [context/callback-panics.md](context/callback-panics.md).\n- Context backlog: [context/CONTEXT-GAPS.md](context/CONTEXT-GAPS.md).\n\n## Commands\n\n- JS deps: `pnpm install --frozen-lockfile`.\n- Rust build/check/format/lint: `cargo build`, `cargo check -p loro-internal`,\n  `cargo fmt --all`, `pnpm check`.\n- Rust tests: `pnpm test`; internal doctests: `cargo test -p loro-internal --doc`.\n- Loom: `pnpm test-loom`.\n- WASM: `pnpm release-wasm`, or `pnpm -C crates/loro-wasm build-dev`.\n- Bundlers after WASM packaging changes: `pnpm test-bundlers`; browser runtime:\n  `pnpm --dir examples/bundler-smoke-tests run test:browser`.\n- Fractional-index TS: `pnpm test-fractional-index`.\n- Fuzz smoke: `pnpm run-fuzz-corpus`.\n- MoonBit codec, when `moon` is available: from `moon/`, run `moon check`,\n  `moon test`, `moon fmt`.\n\nUse narrow checks first. Ask before broad fuzzing or long browser matrices.\n\n## Working Rules\n\n- Start with `git status --short --branch`; treat uncommitted changes as user\n  work unless you made them.\n- Before editing, read every `AGENTS.md` from root to target directory. Keep\n  `CLAUDE.md` as a symlink to the nearest `AGENTS.md`.\n- Use `rg` / `rg --files` for search.\n- Public API changes in `loro` or `loro-crdt` should be backward-compatible when\n  possible. Prefer new `try_*` APIs over breaking signatures.\n- Internal corruption should fail fast; invalid external input should return\n  `Err`. Returning wrong state is worse than panicking on an impossible internal\n  invariant.\n- Add regression tests near behavior: `crates/loro/tests`,\n  `crates/loro-internal/tests`, module tests, `crates/loro-wasm/tests`, or\n  `moon/loro_codec/*_test.mbt`.\n- Add a changeset for publishing behavior or package output changes.\n- Do not hand-edit generated WASM package output; regenerate it with package\n  scripts.\n\n## Self-Maintained Agent Context\n\n- Treat \"why was that hard to find?\" as a context bug. Add a nearby\n  `AGENTS.md` pointer or a `context/` article, or append a line to\n  [context/CONTEXT-GAPS.md](context/CONTEXT-GAPS.md).\n- Keep root context short. If an `AGENTS.md` grows past about 4000 characters, move\n  detail into a linked `context/` article.\n- Header context articles with `Verified against code YYYY-MM-DD`, anchor claims\n  to files/symbols, and link them from root plus the nearest per-directory\n  `AGENTS.md`.\n- If code changes make an `AGENTS.md` or context article stale, update the docs\n  in the same change.\n- When a commit needs non-obvious rationale, land that rationale in the nearest\n  context file and keep the commit message as a pointer.\n\n## Commit And PR Notes\n\nHistory uses short imperative commits, often prefixed by `fix:`, `test:`,\n`chore:`, or `refactor:`. PRs should include summary, rationale, validation, and\nlinked issues or traces when relevant.\n- Structured WASM reads, node identity, ranges and performance responsibilities:\n  [context/wasm-container-tree.md](context/wasm-container-tree.md).\n","isInternal":false,"tokens":2374,"sizeBytes":9364},{"name":"AGENTS.md","path":"loro-js/AGENTS.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/loro-js/AGENTS.md","title":"loro-js - AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# loro.js\n\nPure TypeScript implementation of Loro (`loro-js/src`). It must read and write\nthe same binary and JSON data as Rust (`loro-crdt`) and give the same results.\n\n## Context\n\n- Concurrent tree moves, skipped cycles, replay, checkout, and undo:\n  [context/loro-js-tree-moves.md](../context/loro-js-tree-moves.md).\n- Undo/redo no-op return values and item boundaries:\n  [context/undo-history-boundaries.md](../context/undo-history-boundaries.md).\n- Index structures, complexity contracts, and benchmarks:\n  [context/loro-js-performance.md](../context/loro-js-performance.md).\n- Randomized Text comparison with Rust (build the nodejs WASM package first):\n  [context/loro-js-rust-differential.md](../context/loro-js-rust-differential.md).\n- Multi-peer fuzzing of all containers against replay, checkout, event, and\n  shallow-snapshot oracles, optionally in lockstep with Rust:\n  [context/loro-js-differential-fuzz.md](../context/loro-js-differential-fuzz.md).\n- MovableList model (Rust's positions + LWW elements) and its multi-peer Rust\n  differential suite (`tests/differential/`):\n  [context/loro-js-movable-list.md](../context/loro-js-movable-list.md).\n- Rich text: style anchors live in the Text sequence and op positions count\n  them. Read [context/loro-js-richtext-anchors.md](../context/loro-js-richtext-anchors.md)\n  before changing Text positions, marks, or Text snapshot state.\n- Encoding formats: [context/internal-encoding.md](../context/internal-encoding.md)\n  and `docs/encoding*.md`.\n\n## Interop fixtures\n\n- Rust output read by loro.js: `tests/fixtures/rust/*.blob` and `*.json`.\n- loro.js output read by Rust: `pnpm fixtures:rewrite` runs\n  `scripts/rewrite-rust-fixture.mjs`, which writes `tests/fixtures/rust/*.ts.blob`;\n  `crates/loro/tests/loro_js_interop.rs` imports them. Container state encoders\n  live in `src/runtime/document.ts` (`#containerState`) and must follow\n  `docs/encoding-container-states.md`.\n- loro.js 0.2 output read by later versions: `scripts/write-legacy-fixtures.mjs`\n  writes `tests/fixtures/loro-js-0.2/` with a 0.2 build; `tests/legacy-data.test.ts`\n  pins that loro.js and Rust read it the same way. Later versions read 0.2 data\n  with Rust's semantics, with no version marker (README \"Upgrading from 0.2\"; the\n  decision is in [context/loro-js-rust-differential.md](../context/loro-js-rust-differential.md)).\n\n## Commands\n\nFrom `loro-js/`: `pnpm test`, `pnpm typecheck`, `pnpm lint`, `pnpm format:check`,\n`pnpm build`, or `pnpm check` for all of them. From the root, `pnpm test-loro-js`\nruns the tests and fails if the Rust WASM reference is missing (CI runs it after\n`release-wasm`). Benchmarks: `pnpm bench:b4`,\n`pnpm bench:complexity -- 1000,2000,4000,8000`.\n","isInternal":false,"tokens":743,"sizeBytes":2714},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"AGENTS.md","isInternal":false,"tokens":3,"sizeBytes":9},{"name":"CLAUDE.md","path":"loro-js/CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/loro-js/CLAUDE.md","title":"loro-js - Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"AGENTS.md","isInternal":false,"tokens":3,"sizeBytes":9},{"name":"openai.yaml","path":"skills/loro/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/loro/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Loro\"\n  short_description: \"Guide for adopting and using Loro in apps\"\n  default_prompt: \"Use $loro to design or explain a Loro-powered app, from choosing a language binding through modeling, sync, editors, React state, and performance.\"\n","isInternal":false,"tokens":62,"sizeBytes":266},{"name":"containers-and-encoding.md","path":"skills/loro/references/containers-and-encoding.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/loro/references/containers-and-encoding.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Containers And Encoding\n\n## Container Choice\n\n- `LoroMap`: LWW key-value storage. Good for object-like state, coordinates, metadata, URLs, and fields where overwriting is preferable to merging.\n- `LoroList`: ordered sequence with insert/delete semantics.\n- `LoroMovableList`: ordered sequence with native move and set semantics. Prefer for drag-and-drop or reorder-heavy UIs.\n- `LoroTree`: hierarchical moves plus node-local data maps. Prefer for outlines, layers, nested blocks, or parent-child structures.\n- `LoroCounter`: additive numeric CRDT. Use when concurrent increments/decrements must accumulate.\n- `LoroText`: collaborative text. Use `updateByLine(...)` when line-oriented reconciliation is preferable to raw whole-string replacement.\n\n## Behavioral Notes\n\n- `LoroMap` compares concurrent writes by logical time and retains the winning value.\n- Setting a map entry to the same value is a no-op, so it does not create history.\n- `LoroList` and `LoroMovableList` both support stable cursors; use them when positions must survive concurrent edits.\n\n## Choice Pitfalls\n\n- Do not store editable prose as a plain string in a map unless LWW semantics are desired.\n- Do not model coordinates as `[x, y]` in a list. Concurrent delete+insert can create invalid arrays. Use a map.\n- Do not model arbitrary graphs directly. Loro documents compose as trees, not DAGs with shared children.\n\n## Container States And Composition\n\n- Detached containers come from constructors like `new LoroMap()`.\n- Attached containers belong to a document and have stable `ContainerID`s.\n- Adding a detached container to a document returns an attached version; the original object remains detached.\n- Root containers come from `doc.getMap(...)`, `doc.getText(...)`, `doc.getList(...)`, `doc.getTree(...)`, and so on.\n- For map-key children that may be lazily created by multiple peers, use `ensureMergeable*` in JS/TS or `ensure_mergeable_*` in Rust.\n- Use `setContainer(...)` / `insertContainer(...)` for regular child creation or replacement; list-position `insertContainer(...)` is unchanged.\n\n## Mergeable Map Children And Overwrite Hazards\n\n- Root container IDs derive from root name plus type.\n- Regular child container IDs derive from the operation that created them.\n- Mergeable map-key child IDs derive from the parent map, key, and type, so concurrent first creation at the same key converges to the same child.\n- Prefer `ensureMergeableText`, `ensureMergeableMap`, `ensureMergeableList`, `ensureMergeableMovableList`, `ensureMergeableTree`, or `ensureMergeableCounter` for dynamic fields, lazy migrations, per-date lists, and other map-key children that should behave as one shared child.\n- `getOrCreateContainer` / `get_or_create_container` is legacy regular child creation; do not recommend it for lazy map-key children.\n\n## Tree Specifics\n\n- `LoroTree` gives each node an associated `Map` container via `node.data`.\n- Fractional indices order siblings. Use them when child ordering matters.\n- When many peers insert at the same sibling position, peer ID acts as a tiebreaker for equal fractional indices.\n- Fractional index jitter reduces collisions at some encoding-size cost.\n- `getNodes(...)` and node JSON views are useful when a flat inspection of the forest is easier than recursive traversal.\n\n## List Vs Movable List\n\n- Use `LoroList` when delete+insert is acceptable and native move identity is unnecessary.\n- Use `LoroMovableList` for kanban columns, cards, playlist reordering, or any UX where “move this item” is semantically distinct from delete+insert.\n\n## Counter\n\n- `Counter` aggregates applied values from all peers.\n- It is the right choice for additive metrics, not for values with hard invariants.\n\n## Export Modes\n\n- `update`: sync delta payloads.\n- `updates-in-range`: bounded history export.\n- `snapshot`: full state checkpoint.\n- `shallow-snapshot`: current state plus truncated history.\n\n## Import Choices\n\n- `import(...)`: one payload at a time.\n- `importBatch(...)`: preferred for multiple updates or mixed snapshot/update payloads because diffing and event emission are coalesced.\n- Imports can succeed partially when dependencies are missing. Pending ranges mean the document knows about those operations but cannot apply them yet.\n\n## Persistence Pattern\n\n1. Periodically save a snapshot.\n2. Frequently persist updates, often after each local edit or on a debounce.\n3. On load, import the snapshot and outstanding updates.\n4. Recompact by exporting a fresh snapshot and deleting replayed updates.\n\n## Shallow Snapshots And Redaction\n\n- Use shallow snapshots when old history can be archived or discarded.\n- They are often much smaller than full snapshots.\n- Peers can only sync if they have versions after the shallow start point.\n- Archive full history before trimming if old history may still matter.\n- Redaction replaces sensitive payloads while preserving enough structure for future synchronization.\n- If old peers still hold unsanitized history, sensitive data still exists there.\n","isInternal":false,"tokens":1076,"sizeBytes":5016},{"name":"fit-and-architecture.md","path":"skills/loro/references/fit-and-architecture.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/loro/references/fit-and-architecture.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Getting Started And Fit\n\n## When Loro Fits\n\n- Collaborative text and structured documents.\n- Offline-first applications that later synchronize.\n- Multi-device sync where eventual consistency is acceptable.\n- Apps that benefit from complete history, time travel, or version checkpoints.\n\n## When Loro Does Not Fit By Itself\n\n- Financial or accounting invariants.\n- Exclusive ownership or booking/locking semantics.\n- Authorization decisions that must be enforced at write time.\n- Arbitrary graph-shaped or non-JSON-like data without an adaptation layer.\n\n## Install\n\n- JavaScript/TypeScript: install `loro-crdt`.\n- Rust: install the `loro` crate.\n- Use editor integrations when available instead of writing editor sync from scratch:\n  - `loro-prosemirror` for ProseMirror and Tiptap-style editors.\n  - `loro-codemirror` for CodeMirror 6.\n- Use `loro-mirror` and `loro-mirror-react` when the app already thinks in immutable state and actions.\n\n## Language And Package Index\n\n- JavaScript/TypeScript: [`loro-crdt`](https://www.npmjs.com/package/loro-crdt). Start here for web apps and most examples in the Loro docs.\n- Rust: [`loro`](https://crates.io/crates/loro) and [`docs.rs/loro`](https://docs.rs/loro). Use for native Rust apps, services, CLIs, and custom infrastructure.\n- Swift: [`loro-swift`](https://github.com/loro-dev/loro-swift). Use for Swift/iOS/macOS experiments and native apps.\n- Python: [`loro-py`](https://github.com/loro-dev/loro-py). Use for Python apps, scripts, and server-side tooling.\n- React Native: [`loro-react-native`](https://github.com/loro-dev/loro-react-native). Use for mobile apps that need native React Native bindings.\n- C#: [`loro-cs`](https://github.com/sensslen/loro-cs). Community-maintained .NET/C# binding; check its README and release state before adopting.\n- Go: [`loro-go`](https://github.com/aholstenson/loro-go). Community-maintained Go binding; check platform support and API completeness before adopting.\n- Cross-language FFI base: [`loro-ffi`](https://github.com/loro-dev/loro-ffi). Use this as the reference for generated/native bindings and as a starting point for new language bindings.\n\nPrefer the official JS/TS or Rust package when there is no product reason to choose another language. For community bindings, verify platform binaries, Loro core version, and API coverage before making product commitments.\n\n## First JavaScript Example\n\n```ts\nimport { LoroDoc } from \"loro-crdt\";\n\nconst docA = new LoroDoc();\nconst listA = docA.getList(\"items\");\nlistA.insert(0, \"A\");\nlistA.insert(1, \"B\");\n\nconst update = docA.export({ mode: \"update\" });\n\nconst docB = new LoroDoc();\ndocB.import(update);\n\nconsole.log(docB.toJSON()); // { items: [\"A\", \"B\"] }\n```\n\n## First Design Questions\n\n1. What parts of the state should merge when edited concurrently?\n2. Which data needs durable history, and which data is only presence or UI state?\n3. Do users need text/rich-text intent preservation, ordered moves, tree moves, or simple last-write-wins fields?\n4. How will peers exchange updates, and where will snapshots or updates be persisted?\n\n## Conceptual Model\n\n- Loro is a CRDT framework for local-first apps.\n- It trades strict coordination for strong eventual consistency.\n- Each peer edits locally, exports updates, imports updates from other peers, and converges after seeing the same operations.\n- Loro records history, so versioning and time travel are core concepts rather than an afterthought.\n\n## Document Shape Constraints\n\n- Loro documents are JSON-like.\n- Map keys are strings.\n- The composed document structure is tree-shaped, not a general graph with shared children.\n\n## Entry Points\n\n- Core packages and language bindings are listed in `Language And Package Index`.\n- Ecosystem integrations include editor bindings, state-mirroring layers, React Native, and Inspector.\n\n## Practical Start Path\n\n1. Pick container types in `containers-and-encoding.md`.\n2. Decide sync and persistence shape in `sync-versioning-and-events.md`.\n3. Add editor or React integration only after the document model is clear.\n4. Use Inspector during development to inspect state and history.\n","isInternal":false,"tokens":976,"sizeBytes":4124},{"name":"mirror-and-react.md","path":"skills/loro/references/mirror-and-react.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/loro/references/mirror-and-react.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Mirror And React\n\n## Mirror Intent\n\n- `loro-mirror` keeps an immutable app-state view in sync with a `LoroDoc`.\n- Local `setState(...)` edits become granular CRDT operations.\n- Remote CRDT events patch the mirrored app state back in.\n- The common mental model is still “immutable app state plus typed actions”, not direct mutation of raw CRDT containers everywhere.\n\n## Root Schema\n\n- Build the root with `schema({...})`.\n- Keep root fields as Loro containers: `LoroMap`, `LoroList`, `LoroMovableList`, `LoroText`.\n- Put primitives inside those containers, not at the root.\n\n## Field Types\n\n- `schema.String`, `schema.Number`, `schema.Boolean`: concrete primitive fields.\n- `schema.Any`: dynamic JSON-like payload when the shape is truly unknown.\n- `schema.Ignore`: local-only or derived fields that should not sync to Loro.\n\n## Maps, Lists, And `$cid`\n\n- `schema.LoroMap({...})`: nested object container.\n- `schema.LoroMap(...).catchall(valueSchema)`: add dynamic keys while preserving known keys.\n- `schema.LoroMapRecord(valueSchema)`: homogeneous record-like map.\n- Every mirrored `LoroMap` includes a read-only `$cid`.\n- `$cid` matches the underlying Loro container ID.\n- Use `$cid` as a stable key or default `idSelector`, especially for list items.\n- Never try to persist or mutate `$cid` from app code.\n- Do not invent a `withCid`-style option; mirrored map values already receive `$cid` automatically.\n\n## Lists\n\n- `LoroList(itemSchema, idSelector?)`: ordered collection. Add `idSelector` for stable add/remove/update/move diffs.\n- `LoroMovableList(itemSchema, idSelector)`: native move semantics, ideal for drag-and-drop.\n- If a list item is a map, `(item) => item.$cid` is often the right `idSelector`.\n\n## Defaults And Validation\n\n- Explicit `defaultValue` wins.\n- Required fields without explicit defaults fall back to built-in defaults.\n- `validateUpdates` is enabled by default in `Mirror`. Keep it on unless a measured hot path proves otherwise.\n- Use `validateSchema(...)` when you need an explicit validation pass during migration or debugging.\n\n## React Patterns\n\n- Create a stable `LoroDoc` instance.\n- Create helpers through `createLoroContext(schema)` or `useLoroStore(...)`.\n- Wrap the tree in `LoroProvider` when using the context pattern.\n- Use the narrowest hook that solves the task:\n  - `useLoroState` for the full mirrored state\n  - `useLoroSelector` for focused subscriptions\n  - `useLoroAction` for write paths\n- Keep the provider `doc` stable across renders.\n- Prefer `useLoroSelector` over pulling the full state into every component.\n- Use mirrored list item `$cid` values as React keys.\n\n## Practical Mental Model\n\n- Subscribe to order at collection boundaries.\n- Subscribe to content at item boundaries.\n- Pass `$cid`s downward and reselect locally instead of passing large mirrored objects through the whole tree.\n- Keep view-local state outside the mirror unless collaborators must share it.\n","isInternal":false,"tokens":685,"sizeBytes":2935},{"name":"performance-and-tradeoffs.md","path":"skills/loro/references/performance-and-tradeoffs.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/loro/references/performance-and-tradeoffs.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Performance And Tradeoffs\n\nUse this chapter when users ask whether Loro can handle a workload, how to store data efficiently, or why one sync/storage design is preferable to another.\n\n## What To Compare\n\n- Encoded document size and update size.\n- Snapshot export/import time.\n- Update import time.\n- Memory footprint while editing and loading.\n- Conflict-heavy collaboration versus mostly independent edits.\n- Initial load path versus steady-state sync path.\n\n## Practical Defaults\n\n- Use update exchange for live collaboration.\n- Use snapshots for fast startup checkpoints.\n- Store frequent small updates between snapshots when durable replay is needed.\n- Recompact by exporting a fresh snapshot after enough updates accumulate.\n- Consider shallow snapshots when old history can be archived or discarded.\n\n## Workload-Specific Advice\n\n- Collaborative text: use `LoroText`; do not model text as a plain string just to reduce apparent complexity.\n- Reorder-heavy collections: use `LoroMovableList` instead of delete+insert if move identity matters.\n- Hierarchies: use `LoroTree`; avoid forcing tree-shaped data into ad hoc map/list structures.\n- High-frequency presence or cursor movement: use `EphemeralStore`, not the persisted document.\n- Hard invariants such as balances, bookings, or permissions still need application/server-side validation outside the CRDT merge.\n\n## Benchmark Interpretation\n\n- Treat benchmarks as workload indicators, not universal rankings.\n- A smaller full snapshot does not automatically mean smaller incremental updates.\n- A fast import path matters most for startup and bulk sync.\n- A compact update path matters most for live collaboration and bandwidth-constrained clients.\n- Shallow snapshots reduce retained history, but peers with only older history may need a fresh snapshot or archived history to sync.\n\n## Explain Tradeoffs\n\n- Loro optimizes for local editing, automatic merging, history, and version control.\n- Strong eventual consistency means peers converge after receiving the same operations.\n- Loro does not provide central locking, serializable transactions, or write-time authorization by itself.\n- Pick containers by merge semantics first, then tune storage and sync format for performance.\n","isInternal":false,"tokens":428,"sizeBytes":2240},{"name":"richtext-and-editors.md","path":"skills/loro/references/richtext-and-editors.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/loro/references/richtext-and-editors.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Rich Text And Editors\n\n## Rich Text Rules\n\n- Use `LoroText` for collaboratively edited text.\n- Keep rich text style config in sync across peers:\n  - `after`\n  - `before`\n  - `none`\n  - `both`\n- If two peers use different `configTextStyle(...)`, they can interpret the same boundary insert differently.\n\n## Text API Notes\n\n- `update(...)` rewrites based on a target text snapshot.\n- `updateByLine(...)` is useful when line-oriented reconciliation is more appropriate than raw whole-string replacement.\n- `toDelta()` preserves marks and annotations.\n- `toJSON()` / `toString()` return plain text only.\n\n## `applyDelta(...)` Caveat\n\n- `applyDelta(...)` is ideal for editor bindings because it matches event diffs.\n- Delta inserts must include the full attribute set of the inserted range.\n- If CRDT inheritance would add marks but the delta omits them, `applyDelta(...)` removes those attributes.\n- Out-of-range formatting can cause Loro to materialize newlines to satisfy editor assumptions.\n\n## Stable Selections\n\n- Use `text.getCursor(...)` to create stable positions.\n- Use two cursors for selections: anchor and head.\n- Resolve live offsets with `doc.getCursorPos(...)`.\n- Persist updated cursors returned from resolution to reduce replay cost.\n- JavaScript text offsets are UTF-16 indices.\n\n## ProseMirror And Tiptap\n\n- Start with `loro-prosemirror` for ProseMirror and Tiptap.\n- It already covers document sync, collaborative undo and redo, and cursor presence.\n- The current baseline is `CursorEphemeralStore` plus `LoroEphemeralCursorPlugin`.\n- Give each editor instance its own `containerId` when several editors share one `LoroDoc`.\n- Reuse the same container only if several views intentionally co-edit the exact same content.\n\n## CodeMirror\n\n- Use the official CodeMirror integration when the editor is CM6-based.\n- Keep awareness/presence, undo, and document sync at the Loro layer rather than inventing a separate editor-level protocol.\n\n## Rich Text Internals\n\n- Loro rich text uses style anchors to represent mark boundaries.\n- Overlap and expansion behavior are first-class concerns.\n- Overlappable styles are often best modeled by unique keys with a shared prefix pattern such as `comment:alice` and `comment:bob`.\n\n## Guardrails\n\n- Do not model editable prose as `string` in a `LoroMap`.\n- Do not store collaborative selections as plain indices.\n- Do not mix old and new ProseMirror cursor APIs accidentally; check the installed package version and current API docs first.\n","isInternal":false,"tokens":555,"sizeBytes":2492},{"name":"sync-versioning-and-events.md","path":"skills/loro/references/sync-versioning-and-events.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/loro/references/sync-versioning-and-events.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Sync, Versioning, And Events\n\n## General Sync Guarantees\n\n- If two peers eventually hold the same set of operations, they converge to the same state.\n- Delivery order, duplication, and temporary disconnection are transport concerns, not document-consistency failures.\n- For steady-state collaboration, sync updates rather than full snapshots whenever possible.\n\n## Sync Patterns\n\n- Give every peer a unique peer ID. Reusing peer IDs can make updates look duplicated and break convergence.\n- Prefer update exchange over whole snapshots for steady-state sync:\n  - `subscribeLocalUpdates(...)` for push-based transport.\n  - `export({ mode: \"update\", from })` when you track a known sync point.\n- Use `importBatch(...)` for multiple updates or mixed snapshot/update payloads. It performs one diff calculation and emits one combined event.\n- `EphemeralStore` local updates should be transported separately from persisted document updates.\n\n## Version Representations\n\n- `VersionVector`: explicit peer-to-counter map. Best for synchronization, inclusion checks, and self-contained network state.\n- `Frontiers`: compact boundary operations. Best for checkpoints and time travel.\n- Convert between them when needed; vectors are explicit, frontiers are compact.\n\n## State Vs History\n\n- `version()` / `frontiers()`: the current visible DocState.\n- `oplogVersion()` / `oplogFrontiers()`: the latest history known to the OpLog.\n- When attached, state and history usually align.\n- After `checkout(...)`, DocState can diverge from OpLog. That is detached mode.\n\n## Attached Vs Detached\n\n- Detached document state means “viewing history” or otherwise not showing the latest OpLog.\n- Detached container state means “not yet inserted into a document.”\n- These are separate concepts.\n\n## `checkout(...)` Versus `revertTo(...)`\n\n- `checkout(frontiers)`: move document state to an old version. This puts the doc into detached mode.\n- `checkoutToLatest()` or `attach()`: return to the latest attached state.\n- `revertTo(frontiers)`: generate new operations that transform the current document into the target historical state. The doc stays attached.\n\n## Peer IDs\n\n- Every operation ID is `(peerId, counter)`.\n- Never reuse peer IDs across concurrent sessions.\n- Do not use user IDs as peer IDs.\n\n## Operations, Changes, Transactions\n\n- Operations are atomic edits.\n- Changes are logical groups of operations with metadata.\n- Transactions batch operations for event emission and grouping.\n- Loro transactions are not ACID transactions and do not provide rollback semantics.\n- Changes can carry timestamp, commit message, dependencies, peer identity, and other metadata.\n- Consecutive operations may merge into one Change depending on merge rules and timing configuration.\n\n## Import Status\n\n- `ImportStatus.success` tells you what applied.\n- `ImportStatus.pending` tells you what is blocked on missing dependencies.\n- Check pending ranges in out-of-order networks.\n\n## Event Timing Caveat\n\n- Some older examples describe JS events as microtask-delayed.\n- Modern `loro-crdt` dispatches events synchronously at the JS boundary.\n- Check the installed package version and current API docs before relying on old timing examples.\n\n## Event Sources\n\n- Events can be triggered by local commits, imports, and checkouts.\n- Implicit commits happen around operations like export, import, and checkout.\n\n## `subscribePreCommit(...)`\n\n- Use it when commit metadata or change-level hooks must catch both explicit and implicit commits.\n- It is the right place for setting commit message and timestamp.\n- Combined with `exportJsonInIdSpan(...)`, it can drive change hashing or Merkle-DAG-like workflows.\n\n## Timestamps\n\n- Timestamp recording is configurable.\n- `setRecordTimestamp(...)` and `setChangeMergeInterval(...)` affect how changes merge over time.\n- These settings are runtime configuration, not durable document state.\n\n## Inspector\n\n- Use Loro Inspector when you need to browse current state plus full edit history interactively.\n- Prefer it for “what happened to this doc?” debugging before writing custom debug UI.\n\n## Sync Debugging\n\n- If imports arrive out of order, inspect `ImportStatus.pending`.\n- If checkout seems stale, compare DocState version to OpLog version.\n- If commit metadata hooks miss implicit commits, use `subscribePreCommit(...)` rather than adding ad hoc commit calls.\n\n## Undo, Cursor, And Ephemeral Presence\n\n- `UndoManager` is local to one peer. When peer identity changes, the undo and redo stacks reset.\n- Use `onPush` and `onPop` to store selection state together with undo items.\n- Use `groupStart()` and `groupEnd()` when one UX action spans multiple commits.\n- Use `Cursor`, not absolute indices, for selections and carets that must survive concurrent edits.\n- Store two cursors for a selection: anchor and head.\n- Persist the updated cursor returned by `doc.getCursorPos(cursor)` when available; it reduces future replay cost.\n- Use `EphemeralStore` for presence, cursor payloads, hover state, and other collaboration data that must not persist in the CRDT document.\n","isInternal":false,"tokens":1061,"sizeBytes":5088},{"name":"topic-map.md","path":"skills/loro/references/topic-map.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/loro/references/topic-map.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Topic Map\n\nUse this file to choose the right user-facing chapter inside the unified `loro` skill.\n\n## Route By User Ask\n\n- “I am new to Loro. How do I start?”\n  - Read `fit-and-architecture.md`\n- “Which package, language binding, or platform should I use?”\n  - Read `fit-and-architecture.md`\n- “Should I use Loro here?”\n  - Read `fit-and-architecture.md`\n- “Which container should I choose?”\n  - Read `containers-and-encoding.md`\n- “How should I sync, persist, time-travel, use undo, or debug imports?”\n  - Read `sync-versioning-and-events.md`\n- “How do I integrate rich text editors?”\n  - Read `richtext-and-editors.md`\n- “How do I use loro-mirror with React?”\n  - Read `mirror-and-react.md`\n- “How will Loro behave at scale?”\n  - Read `performance-and-tradeoffs.md`\n\n## Getting Started And Product Fit\n\n- Install choices, language bindings, first example, local-first framing\n  - Read `fit-and-architecture.md`\n- When CRDTs are the wrong fit\n  - Read `fit-and-architecture.md`\n- Package entry points and ecosystem overview\n  - Read `fit-and-architecture.md`\n\n## Containers, Composition, Storage\n\n- Choosing between `LoroMap`, `LoroList`, `LoroMovableList`, `LoroTree`, `LoroCounter`, `LoroText`\n  - Read `containers-and-encoding.md`\n- Composition rules, container states, container IDs, overwrite hazards\n  - Read `containers-and-encoding.md`\n- Snapshot, update, shallow snapshot, updates-in-range\n  - Read `containers-and-encoding.md`\n- Persistence, redaction, history trimming\n  - Read `containers-and-encoding.md`\n\n## Sync, Versions, History, Events\n\n- Peer sync, update exchange, realtime sync, offline merge\n  - Read `sync-versioning-and-events.md`\n- Frontiers, version vectors, OpLog vs DocState\n  - Read `sync-versioning-and-events.md`\n- Checkout, time travel, attached vs detached state\n  - Read `sync-versioning-and-events.md`\n- Peer IDs, import status, transactions, changes, timestamps\n  - Read `sync-versioning-and-events.md`\n- Event timing, `subscribePreCommit`, Inspector\n  - Read `sync-versioning-and-events.md`\n- Undo, cursors, and ephemeral presence\n  - Read `sync-versioning-and-events.md`\n\n## Text, Rich Text, And Editors\n\n- `LoroText`, marks, delta APIs, `updateByLine`, stable selections\n  - Read `richtext-and-editors.md`\n- ProseMirror, Tiptap, CodeMirror, custom editor bindings\n  - Read `richtext-and-editors.md`\n- Rich text internals, style anchors, overlap, expansion rules\n  - Read `richtext-and-editors.md`\n\n## App-State Mirroring\n\n- `loro-mirror`, schemas, `$cid`, `idSelector`, validation\n  - Read `mirror-and-react.md`\n- `loro-mirror-react`, selectors, provider/hooks patterns\n  - Read `mirror-and-react.md`\n\n## Performance And Tradeoffs\n\n- Loading speed, encoded size, memory, update size\n  - Read `performance-and-tradeoffs.md`\n- Conflict-heavy vs low-conflict workloads\n  - Read `performance-and-tradeoffs.md`\n- When to use snapshots, shallow snapshots, or update streams\n  - Read `performance-and-tradeoffs.md`\n","isInternal":false,"tokens":764,"sizeBytes":2982},{"name":"SKILL.md","path":"skills/loro/SKILL.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/loro/SKILL.md","title":"loro","category":"anthropic-skill","format":"markdown","content":"---\nname: loro\ndescription: \"Practical guide for helping app developers evaluate, adopt, and use Loro for local-first collaboration. Use when Codex needs to answer questions or write examples for `loro-crdt`, `loro`, `loro-prosemirror`, `loro-codemirror`, `loro-mirror`, language bindings such as Swift/Python/C#/Go/React Native, or Loro-powered apps about: (1) Deciding whether Loro fits a product, (2) Getting started in JavaScript/TypeScript, Rust, or another supported binding, (3) Choosing CRDT containers and document structure, (4) Designing sync, persistence, snapshots, versioning, undo, presence, or time travel, (5) Integrating rich-text editors and stable selections, (6) Mirroring app state with React, or (7) Understanding performance and tradeoffs.\"\n---\n\n# Loro\n\nUse this skill to help users build applications with Loro. Start from the user's product goal, then choose the narrowest chapter that answers it. Load a second chapter only when the task crosses domains.\n\n## Select A Chapter\n\n- Read [references/topic-map.md](references/topic-map.md) if the task is broad and you need to route it.\n- Read [references/fit-and-architecture.md](references/fit-and-architecture.md) for product fit, installation, language/package choices, first examples, and core mental models.\n- Read [references/containers-and-encoding.md](references/containers-and-encoding.md) for choosing containers, shaping documents, exporting updates, snapshots, persistence, shallow snapshots, and redaction.\n- Read [references/sync-versioning-and-events.md](references/sync-versioning-and-events.md) for realtime/offline sync, version vectors, frontiers, checkout, undo, presence, timestamps, events, and Inspector.\n- Read [references/richtext-and-editors.md](references/richtext-and-editors.md) for `LoroText`, cursors, `applyDelta`, `updateByLine`, `loro-prosemirror`, Tiptap, and CodeMirror.\n- Read [references/mirror-and-react.md](references/mirror-and-react.md) for `loro-mirror`, `$cid`, `idSelector`, validation, selectors, and React integration.\n- Read [references/performance-and-tradeoffs.md](references/performance-and-tradeoffs.md) for scaling, document/update size, loading speed, and workload tradeoffs.\n\n## Route Common Tasks\n\n- “I am new to Loro / should I use it / show me a first example”\n  - Start with `fit-and-architecture.md`\n- “Which language package or binding should I use?”\n  - Start with `fit-and-architecture.md`\n- “Build a collaborative document model / choose data types / persist history”\n  - Start with `containers-and-encoding.md`\n  - Add `sync-versioning-and-events.md` if version/history behavior matters\n- “Sync devices, store data, use snapshots, time travel, undo, or presence”\n  - Start with `sync-versioning-and-events.md`\n- “Integrate ProseMirror, Tiptap, CodeMirror, or custom rich text”\n  - Start with `richtext-and-editors.md`\n  - Add `sync-versioning-and-events.md` if undo/version/event behavior matters\n- “Model app state with loro-mirror or loro-mirror-react”\n  - Start with `mirror-and-react.md`\n  - Add `containers-and-encoding.md` if schema semantics depend on container choice\n- “Explain performance, large documents, loading, update size, or tradeoffs”\n  - Start with `performance-and-tradeoffs.md`\n- “Decide whether Loro is the right tool”\n  - Start with `fit-and-architecture.md`\n  - Add `performance-and-tradeoffs.md` if workload scale matters\n\n## Execute The Task\n\n1. Classify the task before reading everything.\n2. Load one primary chapter.\n3. Load at most one secondary chapter for cross-domain work.\n4. Keep solutions grounded in Loro semantics:\n   - choose data types by merge behavior,\n   - distinguish state version from history version,\n   - keep ephemeral state out of persisted CRDT data,\n   - use stable cursors for collaborative selections,\n   - design sync around updates and snapshots rather than a central locking protocol.\n\n## Keep Guardrails\n\n- Do not assume CRDTs are the right fit for hard invariants, exclusivity, or authorization-at-write-time problems.\n- Do not model editable text as plain strings when user intent requires merged edits.\n- Do not reuse peer IDs across concurrent sessions.\n- Do not confuse detached documents with detached containers.\n- Do not persist cursor presence, hover state, or connection state inside the main document; use ephemeral state.\n","frontmatter":{"name":"loro","description":"Practical guide for helping app developers evaluate, adopt, and use Loro for local-first collaboration. Use when Codex needs to answer questions or write examples for `loro-crdt`, `loro`, `loro-prosemirror`, `loro-codemirror`, `loro-mirror`, language bindings such as Swift/Python/C#/Go/React Native, or Loro-powered apps about: (1) Deciding whether Loro fits a product, (2) Getting started in JavaScript/TypeScript, Rust, or another supported binding, (3) Choosing CRDT containers and document structure, (4) Designing sync, persistence, snapshots, versioning, undo, presence, or time travel, (5) Integrating rich-text editors and stable selections, (6) Mirroring app state with React, or (7) Understanding performance and tradeoffs."},"isInternal":false,"tokens":997,"sizeBytes":4362},{"name":"ide.md","path":"skills/moonbit/ide.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/moonbit/ide.md","title":"Moonbit Skill","category":"anthropic-skill","format":"markdown","content":"## Code Navigation with `moon ide`\n\n**ALWAYS use `moon ide` for code navigation in MoonBit projects instead of manual file searching, grep, or semantic search.**\n\nThis tool provides two essential commands for precise code exploration:\n\n### Core Commands\n\n- `moon ide goto-definition` - Find where a symbol is defined\n- `moon ide find-references` - Find all usages of a symbol\n\n### Query System\n\nSymbol lookup uses a two-part query system for precise results:\n\n#### 1. Symbol Name Query (`-query`)\n\nFuzzy search for symbol names with package filtering support:\n\n```bash\n# Find any symbol named 'symbol'\nmoon ide goto-definition -query 'symbol'\n\n# Find methods of a specific type\nmoon ide goto-definition -query 'Type::method'\n\n# Find trait method implementations\nmoon ide goto-definition -query 'Trait for Type with method'\n\n# Find symbol in specific package using @pkg prefix\nmoon ide goto-definition -query '@moonbitlang/x encode'\n\n# Find symbol in multiple packages (searches in pkg1 OR pkg2)\nmoon ide goto-definition -query '@username/mymodule/pkg1 @username/mymodule/pkg2 helper'\n\n# Find symbol in nested package\nmoon ide goto-definition -query '@username/mymodule/mypkg helper'\n```\n\n**Supported symbols**: functions, constants, let bindings, types, structs, enums, traits\n\n**Package filtering**: Prefix your query with `@package_name` to scope the search. Multiple `@pkg` prefixes create an OR condition.\n\n#### 2. Tag-based Filtering (`-tags`)\n\nPre-filter symbols by characteristics before name matching:\n\n**Visibility tags**:\n\n- `pub` - Public symbols\n- `pub all` - Public structs with all public fields\n- `pub open` - Public traits with all methods public\n- `priv` - Private symbols\n\n**Symbol type tags**:\n\n- `type` - Type definitions (struct, enum, typealias, abstract)\n- `error` - Error type definitions\n- `enum` - Enum definitions and variants\n- `struct` - Struct definitions\n- `alias` - Type/function/trait aliases\n- `let` - Top-level let bindings\n- `const` - Constant definitions\n- `fn` - Function definitions\n- `trait` - Trait definitions\n- `impl` - Trait implementations\n- `test` - Named test functions\n\n**Combine tags with logical operators**:\n\n```bash\n# Public functions only\nmoon ide goto-definition -tags 'pub fn' -query 'my_func'\n\n# Functions or constants\nmoon ide goto-definition -tags 'fn | const' -query 'helper'\n\n# Public functions or constants\nmoon ide goto-definition -tags 'pub (fn | const)' -query 'api'\n\n# Public types or traits\nmoon ide goto-definition -tags 'pub (type | trait)' -query 'MyType'\n```\n\n### Practical Examples\n\n```bash\n# Find public function definition\nmoon ide goto-definition -tags 'pub fn' -query 'maximum'\n\n# Find all references to a struct\nmoon ide find-references -tags 'struct' -query 'Rectangle'\n\n# Find trait implementations\nmoon ide goto-definition -tags 'impl' -query 'Show for MyType'\n\n# Find errors in specific package\nmoon ide goto-definition -tags 'error' -query '@mymodule/parser ParseError'\n\n# Find symbol across multiple packages\nmoon ide goto-definition -query '@moonbitlang/x @moonbitlang/core encode'\n\n# Combine package filtering with tags\nmoon ide goto-definition -tags 'pub fn' -query '@username/myapp helper'\n```\n\n### Query Processing\n\nThe tool processes queries in this order:\n\n1. Filter symbols by `-tags` conditions\n2. Extract package scope from `@pkg` prefixes in `-query`\n3. Fuzzy match remaining symbols by name\n4. Return top 3 best matches with location information\n\n**Best Practice**: Start with `-tags` to reduce noise, then use `@pkg` prefixes in `-query` to scope by package for precise navigation.\n","isInternal":false,"tokens":840,"sizeBytes":3577},{"name":"README.md","path":"skills/moonbit/README.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/moonbit/README.md","title":"Moonbit Skill","category":"anthropic-skill","format":"markdown","content":"# MoonBit Agent Skill\n\nThis repository contains a [Agent Skill](https://agentskills.io/home) that teaches AI coding agents the MoonBit language and its toolchain.\n\n## Integrate the Skill into your agent\n\nDifferent AI assistants require different configuration methods. Below are guides for popular coding assistants:\n\n### Codex CLI\n\n```shell\nmkdir -p ~/.codex/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ~/.codex/skills/moonbit\n```\n\nDocumentation: https://developers.openai.com/codex/skills\n\n### Claude Code\n\n```shell\nmkdir -p ~/.claude/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ~/.claude/skills/moonbit\n```\n\nDocumentation: https://code.claude.com/docs/en/skills\n\n### GitHub Copilot for VS Code\n\n```shell\n# enable moonbit skill for current repository\nmkdir -p ./.github/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ./.github/skills/moonbit\n```\n\nNote: Agent Skills support in VS Code is currently in preview and available only in [VS Code Insiders](https://code.visualstudio.com/insiders/). Enable the `chat.useAgentSkills` setting to use Agent Skills. See [Use Agent Skills in VS Code](https://code.visualstudio.com/docs/copilot/customization/agent-skills) for details.\n\n### Cursor & Cursor CLI\n\n> Agent Skills are available only in the Cursor nightly release channel.\n\nDocumentation: https://cursor.com/cn/docs/context/skills\n\n### Gemini CLI\n\nIt seems that Gemini CLI will support agent skills in next release: https://github.com/google-gemini/gemini-cli/issues/15327\n\n","isInternal":false,"tokens":369,"sizeBytes":1546},{"name":"advanced-moonbit-build.md","path":"skills/moonbit/references/advanced-moonbit-build.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/moonbit/references/advanced-moonbit-build.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"## Conditional Compilation\n\nTarget specific backends/modes in `moon.pkg.json`:\n\n```json\n{\n  \"targets\": {\n    \"wasm_only.mbt\": [\"wasm\"],\n    \"js_only.mbt\": [\"js\"],\n    \"debug_only.mbt\": [\"debug\"],\n    \"wasm_or_js.mbt\": [\"wasm\", \"js\"], // for wasm or js backend\n    \"not_js.mbt\": [\"not\", \"js\"], // for nonjs backend\n    \"complex.mbt\": [\"or\", [\"and\", \"wasm\", \"release\"], [\"and\", \"js\", \"debug\"]] // more complex conditions\n  }\n}\n```\n\n**Available conditions:**\n\n- **Backends**: `\"wasm\"`, `\"wasm-gc\"`, `\"js\"`, `\"native\"`\n- **Build modes**: `\"debug\"`, `\"release\"`\n- **Logical operators**: `\"and\"`, `\"or\"`, `\"not\"`\n\n## Link Configuration\n\n### Basic Linking\n\n```json\n{\n  \"link\": true, // Enable linking for this package\n  // OR for advanced cases:\n  \"link\": {\n    \"wasm\": {\n      \"exports\": [\"hello\", \"foo:bar\"], // Export functions\n      \"heap-start-address\": 1024, // Memory layout\n      \"import-memory\": {\n        // Import external memory\n        \"module\": \"env\",\n        \"name\": \"memory\"\n      },\n      \"export-memory-name\": \"memory\" // Export memory with name\n    },\n    \"wasm-gc\": {\n      \"exports\": [\"hello\"],\n      \"use-js-builtin-string\": true, // JS String Builtin support\n      \"imported-string-constants\": \"_\" // String namespace\n    },\n    \"js\": {\n      \"exports\": [\"hello\"],\n      \"format\": \"esm\" // \"esm\", \"cjs\", or \"iife\"\n    },\n    \"native\": {\n      \"cc\": \"gcc\", // C compiler\n      \"cc-flags\": \"-O2 -DMOONBIT\", // Compile flags\n      \"cc-link-flags\": \"-s\" // Link flags\n    }\n  }\n}\n```\n\n## Warning Control\n\nDisable specific warnings in `moon.mod.json` or `moon.pkg.json`:\n\n```json\n{\n  \"warn-list\": \"-2-29\" // Disable unused variable (2) & unused package (29)\n}\n```\n\n**Common warning numbers:**\n\n- `1` - Unused function\n- `2` - Unused variable\n- `11` - Partial pattern matching\n- `12` - Unreachable code\n- `29` - Unused package\n\nUse `moonc build-package -warn-help` to see all available warnings.\n\n## Pre-build Commands\n\nEmbed external files as MoonBit code:\n\n```json\n{\n  \"pre-build\": [\n    {\n      \"input\": \"data.txt\",\n      \"output\": \"embedded.mbt\",\n      \"command\": \":embed -i $input -o $output --name data --text\"\n    },\n    ... // more embed commands\n  ]\n}\n```\n\nGenerated code example:\n\n```mbt check\n///|\nlet data : String =\n  #|hello,\n  #|world\n  #|\n```\n","isInternal":false,"tokens":674,"sizeBytes":2269},{"name":"moonbit-language-fundamentals.mbt.md","path":"skills/moonbit/references/moonbit-language-fundamentals.mbt.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/moonbit/references/moonbit-language-fundamentals.mbt.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# MoonBit Language Fundamentals\n\n\n## Quick reference:\n\n```mbt check\n///|\n/// comments doc string\npub fn sum(x : Int, y : Int) -> Int {\n  x + y\n}\n\n///|\nstruct Rect {\n  width : Int\n  height : Int\n}\n\n///|\nfn Rect::area(self : Rect) -> Int {\n  self.width * self.height\n}\n\n///|\npub impl Show for Rect with output(_self, logger) {\n  logger.write_string(\"Rect\")\n}\n\n///|\nenum MyOption {\n  MyNone\n  MySome(Int)\n} derive(Show, ToJson, Eq, Compare)\n\n///|\n///  match + loops are expressions\ntest \"everything is expression in MoonBit\" {\n  // tuple\n  let (n, opt) = (1, MySome(2))\n  // if expressions return values\n  let msg : String = if n > 0 { \"pos\" } else { \"non-pos\" }\n  let res = match opt {\n    MySome(x) => {\n      inspect(x, content=\"2\")\n      1\n    }\n    MyNone => 0\n  }\n  let status : Result[Int, String] = Ok(10)\n  // match expressions return values\n  let description = match status {\n    Ok(value) => \"Success: \\{value}\"\n    Err(error) => \"Error: \\{error}\"\n  }\n  let array = [1, 2, 3, 4, 5]\n  let mut i = 0 // mutable bindings (local only, globals are immutable)\n  let target = 3\n  // loops return values with 'break'\n  let found : Int? = while i < array.length() {\n    if array[i] == target {\n      break Some(i) // Exit with value\n    }\n    i = i + 1\n  } else { // Value when loop completes normally\n    None\n  }\n  assert_eq(found, Some(2)) // Found at index 2\n}\n\n///|\n/// global bindings\npub let my_name : String = \"MoonBit\"\n\n///|\npub const PI : Double = 3.14159 // constants use UPPER_SNAKE or PascalCase\n\n///|\npub fn maximum(xs : Array[Int]) -> Int raise {\n  // Toplevel functions are *mutually recursive* by default\n  // `raise` annotation means the function would raise any Error\n  //  Only add `raise XXError` when you do need track the specific error type\n  match xs {\n    [] => fail(\"Empty array\") // fail() is built-in for generic errors\n    [x] => x\n    // pattern match over array, the `.. rest` is a rest pattern\n    // it is of type `ArrayView[Int]` which is a slice\n    [x, .. rest] => {\n      let mut max_val = x // `mut` only allowed in local bindings\n      for y in rest {\n        if y > max_val {\n          max_val = y\n        }\n      }\n      max_val // return can be omitted if the last expression is the return value\n    }\n  }\n}\n\n///|\n/// pub(all) means it can be both read and created outside the package\npub(all) struct Point {\n  x : Int\n  mut y : Int\n} derive(Show, ToJson)\n\n///|\npub enum MyResult[T, E] {\n  MyOk(T) // semicolon `;` is optional when we have a newline\n  MyErr(E) // Enum variants must start uppercase\n} derive(Show, Eq, ToJson)\n// pub means it can only be pattern matched outside the package\n// but it can not be created outside the package, use `pub(all)` otherwise\n\n///|\n/// pub (open) means the trait can be implemented for outside packages\npub(open) trait Comparable {\n  compare(Self, Self) -> Int // `Self` refers to the implementing type\n}\n\n///|\ntest \"inspect test\" {\n  let result = sum(1, 2)\n  inspect(result, content=\"3\")\n  // The `content` can be auto-corrected by running `moon test --update`\n  let point = Point::{ x: 10, y: 20 }\n  // For complex structures, use @json.inspect for better readability:\n  @json.inspect(point, content={ \"x\": 10, \"y\": 20 })\n}\n```\n\n\n## Complex Types\n\n```mbt check\n///|\npub type UserId = Int // Int is aliased to UserId - like symlink\n\n///|\n///  Tuple-struct for callback\npub struct Handler((String) -> Unit) // A newtype wrapper\n\n///|\n/// Tuple-struct syntax for single-field newtypes\nstruct Meters(Int) // Tuple-struct syntax\n\n///|\nlet distance : Meters = Meters(100)\n\n///|\nlet raw : Int = distance.0 // Access first field with .0\n\n///|\nstruct Addr {\n  host : String\n  port : Int\n} derive(Show, Eq, ToJson, FromJson)\n\n///|\n/// Structural types with literal syntax\nlet config : Addr = Addr::{\n  // `Type::` can be omitted since the type is already known\n  host: \"localhost\",\n  port: 8080,\n}\n\n\n```\n\n## Common Derivable Traits\n\nMost types can automatically derive standard traits using the `derive(...)` syntax:\n\n- **`Show`** - Enables `to_string()` and string interpolation with `\\{value}`\n- **`Eq`** - Enables `==` and `!=` equality operators\n- **`Compare`** - Enables `<`, `>`, `<=`, `>=` comparison operators\n- **`ToJson`** - Enables `@json.inspect()` for readable test output\n- **`Hash`** - Enables use as Map keys\n\n```mbt check\n///|\nstruct Coordinate {\n  x : Int\n  y : Int\n} derive(Show, Eq, ToJson)\n\n///|\nenum Status {\n  Active\n  Inactive\n} derive(Show, Eq, Compare)\n```\n\n**Best practice**: Always derive `Show` and `Eq` for data types. Add `ToJson` if you plan to test them with `@json.inspect()`.\n\n## Reference Semantics by Default\n\nMoonBit passes most types by reference semantically (the optimizer may copy\nimmutables):\n\n```mbt check\n///|\n///  Structs with 'mut' fields are always passed by reference\nstruct Counter {\n  mut value : Int\n}\n\n///|\nfn increment(c : Counter) -> Unit {\n  c.value += 1 // Modifies the original\n}\n\n///|\n/// Arrays and Maps are mutable references\nfn modify_array(arr : Array[Int]) -> Unit {\n  arr[0] = 999 // Modifies original array\n}\n\n///|\ntest \"reference semantics\" {\n  let counter : Ref[Int] = Ref::{ val: 0 }\n  counter.val += 1\n  assert_true(counter.val is 1)\n  let arr : Array[Int] = [1, 2, 3] // unlike Rust, no `mut` keyword needed\n  modify_array(arr)\n  assert_true(arr[0] is 999)\n  let mut x = 3 // `mut` neeed for re-assignment to the bindings\n  x += 2\n  assert_true(x is 5)\n}\n```\n\n## Pattern Matching\n\n```mbt check\n///|\n#warnings(\"-unused_value\")\ntest \"pattern match over Array, struct and StringView\" {\n  let arr : Array[Int] = [10, 20, 25, 30]\n  match arr {\n    [] => ... // empty array\n    [single] => ... // single element\n    [first, .. middle, rest] => {\n      let _ : ArrayView[Int] = middle // middle is ArrayView[Int]  \n      assert_true(first is 10 && middle is [20, 25] && rest is 30)\n    }\n  }\n  fn process_point(point : Point) -> Unit {\n    match point {\n      { x: 0, y: 0 } => ...\n      { x, y } if x == y => ...\n      { x, .. } if x < 0 => ...\n      ...\n    }\n  }\n  /// StringView pattern matching for parsing\n  fn is_palindrome(s : StringView) -> Bool {\n    loop s {\n      [] | [_] => true\n      [a, .. rest, b] if a == b => continue rest\n      // a is of type Char, rest is of type StringView\n      _ => false\n    }\n  }\n\n\n}\n```\n\n## Functional `loop` control flow\n\nThe `loop` construct is unique to MoonBit:\n\n```mbt check\n///|\n/// Functional loop with pattern matching on loop variables\n/// @list.List is from the standard library\nfn sum_list(list : @list.List[Int]) -> Int {\n  loop (list, 0) {\n    (Empty, acc) => acc // Base case returns accumulator\n    (More(x, tail=rest), acc) => continue (rest, x + acc) // Recurse with new values\n  }\n}\n\n///|\n///  Multiple loop variables with complex control flow\nfn find_pair(arr : Array[Int], target : Int) -> (Int, Int)? {\n  loop (0, arr.length() - 1) {\n    (i, j) if i >= j => None\n    (i, j) => {\n      let sum = arr[i] + arr[j]\n      if sum == target {\n        Some((i, j)) // Found pair\n      } else if sum < target {\n        continue (i + 1, j) // Move left pointer\n      } else {\n        continue (i, j - 1) // Move right pointer\n      }\n    }\n  }\n}\n```\n\n**Note**: You must provide a payload to `loop`. If you want an infinite loop, use `while true { ... }` instead. The syntax `loop { ... }` without arguments is invalid.\n\n\n## Methods and Traits\n\nMethods use `Type::method_name` syntax, traits require explicit implementation:\n\n```mbt check\n///|\nstruct Rectangle {\n  width : Double\n  height : Double\n}\n\n///|\n// Methods are prefixed with Type::\nfn Rectangle::area(self : Rectangle) -> Double {\n  self.width * self.height\n}\n\n///|\n/// Static methods don't need self\nfn Rectangle::new(w : Double, h : Double) -> Rectangle {\n  { width: w, height: h }\n}\n\n///|\n/// Show trait now uses output(self, logger) for custom formatting\n/// to_string() is automatically derived from this\npub impl Show for Rectangle with output(self, logger) {\n  logger.write_string(\"Rectangle(\\{self.width}x\\{self.height})\")\n}\n\n///|\n/// Traits can have non-object-safe methods\ntrait Named {\n  name() -> String // No 'self' parameter - not object-safe\n}\n\n///|\n/// Trait bounds in generics\nfn[T : Show + Named] describe(value : T) -> String {\n  \"\\{T::name()}: \\{value.to_string()}\"\n}\n\n///|\n///  Trait implementation\nimpl Hash for Rectangle with hash_combine(self, hasher) {\n  hasher..combine(self.width)..combine(self.height)\n}\n```\n\n## Operator Overloading\n\nMoonBit supports operator overloading through traits:\n\n```mbt check\n///|\nstruct Vector(Int, Int)\n\n///|\n/// Implement arithmetic operators\npub impl Add for Vector with add(self, other) {\n  Vector(self.0 + other.0, self.1 + other.1)\n}\n\n///|\nstruct Person {\n  age : Int\n} derive(Eq)\n\n///|\n/// Comparison operators\npub impl Compare for Person with compare(self, other) {\n  self.age.compare(other.age)\n}\n\n///|\ntest \"overloading\" {\n  let v1 : Vector = Vector(1, 2)\n  let v2 : Vector = Vector(3, 4)\n  let _v3 : Vector = v1 + v2\n\n}\n```\n\n## Access Control Modifiers\n\nMoonBit has fine-grained visibility control:\n\n```mbt check\n///|\n/// `fn` defaults to Private - only visible in current package\nfn internal_helper() -> Unit {\n  ...\n}\n\n///|\npub fn get_value() -> Int {\n  ...\n}\n\n///|\n// Struct (default) - type visible, implementation hidden\nstruct DataStructure {}\n\n///|\n/// `pub struct` defaults to readonly - can read, pattern match, but not create\npub struct Config {}\n\n///|\n///  Public all - full access\npub(all) struct Config2 {}\n\n///|\n/// Abstract trait (default) - cannot be implemented by\n/// types outside this package\npub trait MyTrait {}\n\n///|\n///  Open for extension\npub(open) trait Extendable {}\n```\n","isInternal":false,"tokens":2693,"sizeBytes":9616},{"name":"moonbit-language-fundamentals.md","path":"skills/moonbit/references/moonbit-language-fundamentals.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/moonbit/references/moonbit-language-fundamentals.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"moonbit-language-fundamentals.mbt.md","isInternal":false,"tokens":9,"sizeBytes":36},{"name":"SKILL.mbt.md","path":"skills/moonbit/SKILL.mbt.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/moonbit/SKILL.mbt.md","title":"Moonbit Skill","category":"anthropic-skill","format":"markdown","content":"SKILL.md","isInternal":false,"tokens":3,"sizeBytes":8},{"name":"SKILL.md","path":"skills/moonbit/SKILL.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/skills/moonbit/SKILL.md","title":"moonbit-agent-guide","category":"anthropic-skill","format":"markdown","content":"---\nname: moonbit-agent-guide\ndescription: Guide for writing, refactoring, and testing MoonBit projects. Use when working in MoonBit modules or packages, organizing MoonBit files, using moon tooling (build/check/test/doc/ide), or following MoonBit-specific layout, documentation, and testing conventions.\n---\n\n# MoonBit Project Layouts\n\nMoonBit use the `.mbt` extension and interface files `.mbti`. At\nthe top-level of a MoonBit project there is a `moon.mod.json` file specifying\nthe metadata of the project. The project may contain multiple packages, each\nwith its own `moon.pkg.json` file.\n\n## Example layout\n\n```\nmy_module\n├── moon.mod.json             # Module metadata, source field(optional) specifies the source directory of the module\n├── moon.pkg.json             # Package metadata (each directory is a package like Golang)\n├── README.mbt.md             # Markdown with tested code blocks (`test \"...\" { ... }`)\n├── README.md -> README.mbt.md\n├── cmd                       # Command line directory\n│   └── main\n│       ├── main.mbt\n│       └── moon.pkg.json     # executable package with {\"is_main\": true}\n├── liba/                     # Library packages\n│   └── moon.pkg.json         # Referenced by other packages as `@username/my_module/liba`\n│   └── libb/                 # Library packages\n│       └── moon.pkg.json     # Referenced by other packages as `@username/my_module/liba/libb`\n├── user_pkg.mbt              # Root packages, referenced by other packages as `@username/my_module`\n├── user_pkg_wbtest.mbt       # White-box tests (only needed for testing internal private members, similar to Golang's package mypackage)\n└── user_pkg_test.mbt         # Black-box tests\n└── ...                       # More package files, symbols visible to current package (like Golang)\n```\n\n- **Module**:  `moon.mod.json` file in the project directory.\n  A MoonBit *module* is like a Go module,it is a collection of packages in subdirectories, usually corresponding to a repository or project.\n  Module boundaries matter for dependency management and import paths.\n\n- **Package**: a `moon.pkg.json` file per directory. \n  All subcommands of `moon` will\n  still be executed in the directory of the module (where `moon.mod.json` is\n  located), not the current package.\n  A MoonBit *package* is the actual compilation unit (like a Go package).\n  All source files in the same package are concatenated into one unit.\n  The `package` name in the source defines the package, not the file name.\n  Imports refer to module + package paths, NEVER to file names.\n\n- **Files**:\n  A `.mbt` file is just a chunk of source inside a package.\n  File names do NOT create modules or namespaces.\n  You may freely split/merge/move declarations between files in the same package.\n  Any declaration in a package can reference any other declaration in that package, regardless of file.\n\n\n## Coding/layout rules you MUST follow:\n\n1. Prefer many small, cohesive files over one large file.\n   - Group related types and functions into focused files (e.g. http_client.mbt, router.mbt).\n   - If a file is getting large or unfocused, create a new file and move related declarations into it.\n\n2. You MAY freely move declarations between files inside the same package.\n   - 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.\n   - It is safe to refactor by splitting or merging files inside a package.\n\n3. File names are purely organizational.\n   - Do NOT assume file names define modules, and do NOT use file names in type paths.\n   - Choose file names to describe a feature or responsibility, not to mirror type names rigidly.\n\n4. When adding new code:\n   - Prefer adding it to an existing file that matches the feature.\n   - If no good file exists, create a new file under the same package with a descriptive name.\n   - Avoid creating giant “misc” or “util” files.\n\n5. Tests:\n   - Place tests in dedicated test files (e.g. *_test.mbt) within the appropriate package.\n     For a package, besides `*_test.mbt`files,`*.mbt.md`are also blackbox test files, the code block `mbt check` are treated as test cases, they serve both purposes: documentation and tests.      \n     You may have `README.mbt.md` files with `mbt check` code examples, you can also symlink `README.mbt.md` to `README.md`\n     to make it integrate better with GitHub.\n   - It is fine—and encouraged—to have multiple small test files.\n\n6. Interface files(`pkg.generated.mbti`) \n   `pkg.generated.mbti` is 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.\n   They are generated using `moon info`, 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.\n   \n   You can also use `moon doc @moonbitlang/core/strconv` to explore the public API of a package interactively and `moon ide peek-def 'Array::join'` to read\n   the definition.\n\n# Common Pitfalls to Avoid\n\n- **Don't use uppercase for variables/functions** - compilation error\n- **Don't forget `mut` for mutable record fields** - immutable by default\n- **Don't ignore error handling** - errors must be explicitly handled\n- **Don't use `return` unnecessarily** - last expression is the return value\n- **Don't create methods without Type:: prefix** - methods need explicit type prefix\n- **Don't forget to handle array bounds** - use `get()` for safe access\n- **Don't forget @package prefix when calling functions from other packages**\n- **Don't use ++ or -- (not supported)** - use `i = i + 1` or `i += 1`\n- **Don't add explicit `try` for error-raising functions** - errors propagate automatically (unlike Swift)\n- **Legacy syntax**: Older code may use `function_name!(...)` or `function_name(...)?` - these are deprecated; use normal calls and `try?` for Result conversion\n\n\n# `moon` Essentials\n\n## Essential Commands\n\n- `moon new my_project` - Create new project\n- `moon run cmd/main` - Run main package\n- `moon build` - Build project\n- `moon check` - Type check without building, use it REGULARLY, it is fast\n- `moon info` - Type check and generate `mbti` files\n  run it to see if any public interfaces changed.\n- `moon check --target all` - Type check for all backends\n- `moon add package` - Add dependency\n- `moon remove package` - Remove dependency\n- `moon fmt` - Format code\n\n### Test Commands\n\n- `moon test` - Run all tests\n- `moon test --update` - Update snapshots\n- `moon test -v` - Verbose output with test names\n- `moon test [dirname|filename]` - Test specific directory or file\n- `moon coverage analyze` - Analyze coverage\n- `moon test --filter 'globl'` - Run tests matching filter\n  ```\n  moon test float/float_test.mbt --filter \"Float::*\"\n  ```\n## `README.mbt.md` Generation Guide\n\n- Output `README.mbt.md` in the package directory. \n  `*.mbt.md` file and docstring contents treats `mbt check` specially.\n  `mbt check` block will be included directly as code and also run by `moon check` and `moon test`.  If you don't want the code snippets to be checked, explicit `mbt nocheck` is preferred.\n  If you are only referencing types from the package, you should use `mbt nocheck` which will only be syntax highlighted.\n  Symlink `README.mbt.md` to `README.md` to adapt to systems that expect `README.md`. \n    \n## Testing Guide\n\nUse snapshot tests as it is easy to update when behavior changes.\n\n- **Snapshot Tests**: `inspect(value, content=\"...\")`. If unknown, write `inspect(value)` and run `moon test --update` (or `moon test -u`).\n  - Use regular `inspect()` for simple values (uses `Show` trait)\n  - Use `@json.inspect()` for complex nested structures (uses `ToJson` trait, produces more readable output)\n  - It is encouraged to `inspect` or `@json.inspect` the whole return value of a function if\n    the whole return value is not huge, this makes test simple. You need `impl (Show|ToJson) for YourType` or `derive (Show, ToJson)`.\n- **Update workflow**: After changing code that affects output, run `moon test --update` to regenerate snapshots, then review the diffs in your test files (the `content=` parameter will be updated automatically).\n\n- Black-box by default: Call only public APIs via `@package.fn`. Use white-box tests only when private members matter.\n- Grouping: Combine related checks in one `test \"...\" { ... }` block for speed and clarity.\n- Panics: Name test with prefix `test \"panic ...\" {...}`; if the call returns a value, wrap it with `ignore(...)` to silence warnings.\n- Errors: Use `try? f()` to get `Result[...]` and `inspect` it when a function may raise.\n- Verify: Run `moon test` (or `-u` to update snapshots) and `moon fmt` afterwards.\n\n### Docstring tests \n\nPublic APIs are encouraged to have docstring tests.\n````mbt check\n///|\n/// Get the largest element of a non-empty `Array`.\n///\n/// # Example\n/// ```mbt check\n/// test {\n///   inspect(sum_array([1, 2, 3, 4, 5, 6]), content=\"21\")\n/// }\n/// ```\n///\n/// # Panics\n/// Panics if the `xs` is empty.\npub fn sum_array(xs : Array[Int]) -> Int {\n  xs.fold(init=0, (a, b) => a + b)\n}\n````\n\nThe MoonBit code in docstring will be type checked and tested automatically.\n(using `moon test --update`). In docstrings, `mbt check` should only contain `test` or `async test`.\n\n## Spec-driven Development\n\n- The spec can be written in a readonly `spec.mbt` file (name is conventional, not mandatory) with stub code marked as declarations:\n\n```mbt check\n///|\n#declaration_only\npub type Yaml\n\n///|\n#declaration_only\npub fn Yaml::to_string(y : Yaml) -> String raise {\n  ...\n}\n\n///|\n#declaration_only\npub fn parse_yaml(s : String) -> Yaml raise {\n  ...\n}\n```\n\n- Add `spec_easy_test.mbt`, `spec_difficult_test.mbt` etc to test the spec functions; everything will be type-checked(`moon check`).\n- The AI or students can implement the `declaration_only` functions in different files thanks to our package organization.\n- Run `moon test` to check everything is correct.\n\n- `#declaration_only` is supported for functions, methods, and types.\n- The `pub type Yaml` line is an intentionally opaque placeholder; the implementer chooses its representation.\n- Note the spec file can also contain normal code, not just declarations.\n\n## `moon doc` for API Discovery\n\n**CRITICAL**: `moon doc '<query>'` is your PRIMARY tool for discovering available APIs, functions, types, and methods in MoonBit. Always prefer `moon doc` over other approaches when exploring what APIs are available, it is **more powerful and accurate** than `grep_search` or any regex-based searching tools. \n\n\n`moon doc` uses a specialized query syntax designed for symbol lookup:\n- **Empty query**: `moon doc ''`\n\n  - In a module: shows all available packages in current module, including dependencies and moonbitlang/core\n  - In a package: shows all symbols in current package\n  - Outside package: shows all available packages\n\n- **Function/value lookup**: `moon doc \"[@pkg.]value_or_function_name\"`\n  \n- **Type lookup**: `moon doc \"[@pkg.]Type_name\"` (builtin type does not need package prefix)\n\n- **Method/field lookup**: `moon doc \"[@pkg.]Type_name::method_or_field_name\"`\n\n- **Package exploration**: `moon doc \"@pkg\"`\n  - Show package `pkg` and list all its exported symbols\n  - Example: `moon doc \"@json\"` - explore entire `@json` package\n  - Example: `moon doc \"@encoding/utf8\"` - explore nested package\n\n- **Globbing**: Use `*` wildcard for partial matches, e.g. `moon doc \"String::*rev*\"` to find all String methods with \"rev\" in their name\n\n### `moon doc` Examples\n\n````bash\n# search for String methods in standard library:\n$ moon doc \"String\"\n\ntype String\n\n  pub fn String::add(String, String) -> String\n  # ... more methods omitted ...\n\n$ moon doc \"@buffer\" # list all symbols in  package buffer:\nmoonbitlang/core/buffer\n\nfn from_array(ArrayView[Byte]) -> Buffer\n# ... omitted ...\n\n$ moon doc \"@buffer.new\" # list the specific function in a package:\npackage \"moonbitlang/core/buffer\"\n\npub fn new(size_hint? : Int) -> Buffer\n  Creates ... omitted ...\n\n\n$ moon doc \"String::*rev*\"  # globbing\npackage \"moonbitlang/core/string\"\n\npub fn String::rev(String) -> String\n  Returns ... omitted ...\n  # ... more\n\npub fn String::rev_find(String, StringView) -> Int?\n  Returns ... omitted ...\n````\n**Best practice**: When implementing a feature, start with `moon doc` queries to discover available APIs before writing code. This is faster and more accurate than searching through files.\n\n## `moon ide [peek-def|outline|find-references]` for code navigation and refactoring\n\nFor project-local symbols and navigation, use `moon ide outline .` to scan a package, `moon ide find-references <symbol>` to locate usages, and `moon ide peek-def` for inline definition context and locate toplevel symbols. \n\nThese tools save tokens and more precise than grepping(grep display results in both definition and call site including comments too).\n\n### `moon ide peek-def sym [-loc filename:line:col]` example\n\nWhen the user ask: Can you check if `Parser::read_u32_leb128` is implemented correctly?\n\nIn this case, You can run `moon ide peek-def Parser::read_u32_leb128` to get the definition context: (this is better than `grep` since it searches the whole project by semantics)\n\n``` file src/parse.mbt\nL45:|///|\nL46:|fn Parser::read_u32_leb128(self : Parser) -> UInt raise ParseError {\nL47:|  ...\n...:| }\n```\nNow you want to see the definition of `Parser` struct, you can run:\n\n```bash\n$ moon ide peek-def Parser -loc src/parse.mbt:46:4\nDefinition found at file src/parse.mbt\n  | ///|\n2 | priv struct Parser {\n  |             ^^^^^^\n  |   bytes : Bytes\n  |   mut pos : Int\n  | }  \n  | \n```\nFor the `-loc` argument, the line number must be precise; the column can be approximate since \nthe positonal argument `Parser` helps locate the position.\n\nIf the sym is toplevel symbol, the location can be omitted:\n````bash\n$ moon ide peek-def String::rev\nFound 1 symbols matching 'String::rev':\n\n`pub fn String::rev` in package moonbitlang/core/builtin at /Users/usrname/.moon/lib/core/builtin/string_methods.mbt:1039-1044\n1039 | ///|\n     | /// Returns a new string with the characters in reverse order. It respects\n     | /// Unicode characters and surrogate pairs but not grapheme clusters.\n     | pub fn String::rev(self : String) -> String {\n     |   self[:].rev()\n     | }         \n````\n\n### `moon ide outline [dir|file]` and `moon ide find-references <sym>` for Package Symbols\n\nUse this to scan a package or file for top-level symbols and locate usages without grepping\n\n- `moon ide outline dir` outlines the current package directory (per-file headers)\n- `moon ide outline parser.mbt` outlines a single file\n- Useful when you need a quick inventory of a package, or to find the right file before `goto-definition`\n- `moon ide find-references TranslationUnit` finds all references to a symbol in the current module\n\n```bash\n$ moon ide outline .\nspec.mbt:\n L003 | pub(all) enum CStandard {\n        ...\n L013 | pub(all) struct Position {\n        ...\n```\n\n```bash\n$ moon ide find-references TranslationUnit\n```\n\n## Package Management\n\n### Adding Dependencies\n\n```sh\nmoon add moonbitlang/x        # Add latest version\nmoon add moonbitlang/x@0.4.6  # Add specific version\n```\n\n### Updating Dependencies\n\n```sh\nmoon update                   # Update package index\n```\n\n### Typical Module configurations (`moon.mod.json`)\n\n```json\n{\n  \"name\": \"username/hello\", // Required format for published modules\n  \"version\": \"0.1.0\",\n  \"source\": \".\", // Source directory(optional, default: \".\")\n  \"repository\": \"\", // Git repository URL\n  \"keywords\": [], // Search keywords\n  \"description\": \"...\", // Module description\n  \"deps\": {\n    // Dependencies from mooncakes.io, using`moon add` to add dependencies\n    \"moonbitlang/x\": \"0.4.6\"\n  }\n}\n```\n\n### Typical Package configuration (`moon.pkg.json`)\n\n```json\n{\n  \"is_main\": true,                 // Creates executable when true\n  \"import\": [                      // Package dependencies\n    \"username/hello/liba\",         // Simple import, use @liba.foo() to call functions\n    {\n      \"path\": \"moonbitlang/x/encoding\",\n      \"alias\": \"libb\"              // Custom alias, use @libb.encode() to call functions\n    }\n  ],\n  \"test-import\": [...],            // Imports for black-box tests, similar to import\n  \"wbtest-import\": [...]           // Imports for white-box tests, similar to import (rarely used)\n}\n```\n\nPackages per directory, packages without `moon.pkg.json` are not recognized.\n\n### Package Importing (used in moon.pkg.json)\n\n- **Import format**: `\"module_name/package_path\"`\n- **Usage**: `@alias.function()` to call imported functions\n- **Default alias**: Last part of path (e.g., `liba` for `username/hello/liba`)\n- **Package reference**: Use `@packagename` in test files to reference the\n  tested package\n\n**Package Alias Rules**:\n\n- Import `\"username/hello/liba\"` → use `@liba.function()` (default alias is last path segment)\n- Import with custom alias `{\"path\": \"moonbitlang/x/encoding\", \"alias\": \"enc\"}` → use `@enc.function()`\n- In `_test.mbt` or `_wbtest.mbt` files, the package being tested is auto-imported\n\nExample:\n\n```mbt\n///|\n/// In main.mbt after importing \"username/hello/liba\" in `moon.pkg.json`\nfn main {\n  println(@liba.hello()) // Calls hello() from liba package\n}\n```\n\n### Using Standard Library (moonbitlang/core)\n\n**MoonBit standard library (moonbitlang/core) packages are automatically imported** - DO NOT add them to dependencies:\n\n- ❌ **DO NOT** use `moon add` to add standard library packages like `moonbitlang/core/strconv`\n- ❌ **DO NOT** add standard library packages to `\"deps\"` field of `moon.mod.json`\n- ❌ **DO NOT** add standard library packages to `\"import\"` field of `moon.pkg.json`\n- ✅ **DO** use them directly: `@strconv.parse_int()`, `@list.List`, `@array.fold()`, etc.\n\nIf you get an error like \"cannot import `moonbitlang/core/strconv`\", remove it from imports - it's automatically available.\n\n### Creating Packages\n\nTo add a new package `fib` under `.`:\n\n1. Create directory: `./fib/`\n2. Add `./fib/moon.pkg.json`: `{}` -- Minimal valid moon.pkg.json\n3. Add `.mbt` files with your code\n4. Import in dependent packages:\n\n   ```json\n   {\n     \"import\": [\n        \"username/hello/fib\",\n        ...\n     ]\n   }\n   ```\nFor more advanced topics like `conditional compilation`, `link configuration`, `warning control`, and `pre-build commands`, see `references/advanced-moonbit-build.md`.\n\n# MoonBit Language Tour\n\n## Core facts\n\n- **Expression‑oriented**: `if`, `match`, loops return values; last expression is the return.\n- **References by default**: Arrays/Maps/structs mutate via reference; use `Ref[T]` for primitive mutability.\n- **Blocks**: Separate top‑level items with `///|`. Generate code block‑by‑block.\n- **Visibility**: `fn` private by default; `pub` exposes read/construct as allowed; `pub(all)` allows external construction.\n- **Naming convention**: lower_snake for values/functions; UpperCamel for types/enums; enum variants start UpperCamel.\n- **Packages**: No `import` in code files; call via `@alias.fn`. Configure imports in `moon.pkg.json`.\n- **Placeholders**: `...` is a valid placeholder in MoonBit code for incomplete implementations.\n- **Global values**: immutable by default and generally require type annotations.\n- **Garbage collection**: MoonBit has a GC, there is no lifetime annotation, there's no ownership system.\n  Unlike Rust, like F#, `let mut` is only needed when you want to reassign a variable, not for mutating fields of a struct or elements of an array/map.\n- **Delimit top-level items with `///|` comments** so tools can split the file reliably.\n\n## MoonBit Error Handling (Checked Errors)\n\nMoonBit uses checked error-throwing functions, not unchecked exceptions. All errors are subtype of `Error`, we can declare our own error types by `suberror`.\nUse `raise` in signatures to declare error types and let errors propagate by\ndefault. Use `try?` to convert to `Result[...]` in tests, or `try { } catch { }`\nto handle errors explicitly.\n\n```mbt check\n///|\n/// Declare error types with 'suberror'\nsuberror ValueError String\n\n///|\n/// Tuple struct to hold position info\nstruct Position(Int, Int) derive(ToJson, Show, Eq) \n\n///|\n/// ParseError is subtype of Error\npub(all) suberror ParseError {\n  InvalidChar(pos~:Position, Char) // pos is labeled\n  InvalidEof(pos~:Position)\n  InvalidNumber(pos~:Position, String)\n  InvalidIdentEscape(pos~:Position)\n} derive(Eq, ToJson, Show)\n\n///|\n/// Functions declare what they can throw\nfn parse_int(s : String, position~ : Position) -> Int raise ParseError {\n  // 'raise' throws an error\n  if s is \"\" {\n    raise ParseError::InvalidEof(pos=position)\n  }\n  ... // parsing logic\n}\n\n///|\n/// Just declare `raise` to not track specific error types\nfn div(x : Int, y : Int) -> Int raise {\n  if y is 0 {\n    fail(\"Division by zero\")\n  }\n  x / y\n}\n\n///|\ntest \"inspect raise function\" {\n  let result : Result[Int, Error] = try? div(1, 0) \n  guard result is Err(Failure(msg)) && msg.contains(\"Division by zero\") else {\n    fail(\"Expected error\")\n  }  \n}\n\n// Three ways to handle errors:\n\n///|\n/// Propagate automatically\nfn use_parse(position~: Position) -> Int raise ParseError {\n  let x = parse_int(\"123\", position=position)\n  // Error auto-propagates by default.\n  // Unlike Swift, you do not need to mark `try` for functions that can raise\n  // errors; the compiler infers it automatically. This keeps error handling\n  // explicit but concise.\n  x * 2\n}\n\n///|\n/// Mark `raise` for all possible errors, do not care which error it is.\n/// For quick prototypes, `raise` is acceptable.\nfn use_parse2(position~: Position) -> Int raise {\n  let x = parse_int(\"123\", position=position)\n  x * 2\n}\n\n///|\n/// Convert to Result with try?\nfn safe_parse(s : String, position~: Position) -> Result[Int, ParseError] {\n  let val1 : Result[_] = try? parse_int(s, position=position) // Returns Result[Int, ParseError]\n  // try! is rarely used - it panics on error, similar to unwrap() in Rust\n  // let val2 : Int = try! parse_int(s) // Returns Int otherwise crash\n\n  // Alternative explicit handling:\n  let val3 = try parse_int(s, position=position) catch {\n    err => Err(err)\n  } noraise { // noraise block is optional - handles the success case\n    v => Ok(v)\n  }\n  ...\n}\n\n///|\n/// Handle with try-catch\nfn handle_parse(s : String, position~: Position) -> Int {\n  try parse_int(s, position=position) catch {\n    ParseError::InvalidEof => {\n      println(\"Parse failed: InvalidEof\")\n      -1 // Default value\n    }\n    _ => 2\n  }\n}\n```\n\nImportant: When calling a function that can raise errors, if you only want to\npropagate the error, you do not need any marker; the compiler infers it.\n\n## Integers, Char\n\nMoonBit supports Byte, Int16, Int, UInt16, UInt, Int64, UInt64, etc. When the type is known,\nthe literal can be overloaded:\n\n```mbt check\n///|\ntest \"integer and char literal overloading disambiguation via type in the current context\" {\n  let a0 = 1 // a is Int by default\n  let (int, uint, uint16, int64, byte) : (Int, UInt, UInt16, Int64, Byte) = (\n    1, 1, 1, 1, 1,\n  )\n  assert_eq(int, uint16.to_int())\n  let a1 : Int = 'b' // this also works, a5 will be the unicode value\n  let a2 : Char = 'b'\n}\n```\n## Bytes (Immutable)\n\n```mbt check\n///|\ntest \"bytes literals overloading and indexing\" {\n  let b0 : Bytes = b\"abcd\"\n  let b1 : Bytes = \"abcd\" // b\" prefix is optional, when we know the type\n  let b2 : Bytes = [0xff, 0x00, 0x01] // Array literal overloading\n  guard b0 is [b'a', ..] && b0[1] is b'b' else {\n    // Bytes can be pattern matched as BytesView and indexed\n    fail(\"unexpected bytes content\")\n  }\n  \n}\n```\n## Array (Resizable)\n\n```mbt check\n///|\ntest \"array literals overloading: disambiguation via type in the current context\" {\n  let a0 : Array[Int] = [1, 2, 3] // resizable\n  let a1 : FixedArray[Int] = [1, 2, 3] // Fixed size\n  let a2 : ReadOnlyArray[Int] = [1, 2, 3] \n  let a3 : ArrayView[Int] = [1, 2, 3]\n}\n```\n## String (Immutable UTF-16)\n`s[i]` returns a code unit (UInt16), `s.get_char(i)` returns `Char?`.\nSince MoonBit supports char literal overloading, you can write code snippets like this:\n\n```mbt check\n///|\ntest \"string indexing and utf8 encode/decode\" {\n  let s = \"hello world\"\n  let b0 : UInt16 = s[0]\n  guard(b0 is ('\\n' | 'h' | 'b' | 'a'..='z') && s is [..\"hello\", ..rest]) else {\n    fail(\"unexpected string content\")\n  }\n  guard rest is \" world\" // otherwise will crash (guard without else)\n  \n  // In check mode (expression with explicit type), ('\\n' : UInt16) is valid.\n  \n  // Using get_char for Option handling\n  let b1 : Char? = s.get_char(0)\n  assert_true(b1 is Some('a'..='z'))\n\n  // ⚠️ Important: Variables won't work with direct indexing\n  let eq_char : Char = '='\n  // s[0] == eq_char // ❌ Won't compile - eq_char is not a literal, lhs is UInt while rhs is Char\n  // Use: s[0] == '=' or s.get_char(0) == Some(eq_char)\n  let bytes = @encoding/utf8.encode(\"中文\") // utf8 encode package is in stdlib\n  assert_true(bytes is [0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87])\n  let s2 : String = @encoding/utf8.decode(bytes) // decode utf8 bytes back to String\n  assert_true(s2 is \"中文\")\n  for c in \"中文\" {\n    let _ : Char = c // unicode safe iteration  \n    println(\"char: \\{c}\") // iterate over chars\n  }\n}\n```\n\n### String Interpolation && StringBuilder\n\nMoonBit uses `\\{}` for string interpolation, for custom types, it needs implement trait `Show`\n\n```mbt check\n///|\ntest \"string interpolation basics\" {\n\n  let name : String = \"Moon\"\n  let config = { \"cache\": 123 }\n  let version = 1.0\n  println(\"Hello \\{name} v\\{version}\") // \"Hello Moon v1.0\"\n  // ❌ Wrong - quotes inside interpolation not allowed:\n  // println(\"  - Checking if 'cache' section exists: \\{config[\"cache\"]}\")\n\n  // ✅ Correct - extract to variable first:\n  let has_key = config[\"cache\"] // `\"` not allowed in interpolation\n  println(\"  - Checking if 'cache' section exists: \\{has_key}\")\n  \n  let sb = StringBuilder::new()\n  sb..write_char('[') // dotdot for imperative method chaining\n    ..write_view([1,2,3].map((x) => \"\\{x}\").join(\",\"))\n    ..write_char(']')\n  inspect(sb.to_string(), content=\"[1,2,3]\")\n}\n```\n\nExpressions inside `\\{}` can only be _basic expressions_ (no quotes, newlines, or nested interpolations). String literals are not allowed as it makes lexing too difficult.\n\n\n### Multiple line strings\n\n```mbt check\n///|\ntest \"multi-line string literals\" {  \n  let multi_line_string : String =\n    #|Hello \"world\"\n    #|World\n    #|\n  let multi_line_string_with_interp : String =\n    $|Line 1 \"\"\n    $|Line 2 \\{1+2}\n    $|\n  // no escape in `#|`, \n  // only escape '\\{..}` in `$|`\n  assert_eq(multi_line_string, \"Hello \\\"world\\\"\\nWorld\\n\")  \n  assert_eq(multi_line_string_with_interp, \"Line 1 \\\"\\\"\\nLine 2 3\\n\")\n}\n```\n\n## Map (Mutable, Insertion-Order Preserving)\n\n```mbt check\n///|\ntest \"map literals and common operations\" {\n  // Map literal syntax\n  let map : Map[String, Int] = { \"a\": 1, \"b\": 2, \"c\": 3 }  \n  let empty : Map[String, Int] = {} // Empty map, preferred\n  let also_empty : Map[String, Int] = Map::new()\n  // From array of pairs\n  let from_pairs : Map[String, Int] = Map::from_array([(\"x\", 1), (\"y\", 2)])\n\n  // Set/update value\n  map[\"new-key\"] = 3\n  map[\"a\"] = 10 // Updates existing key\n\n  // Get value - returns Option[T]\n  guard map is { \"new-key\": 3, \"missing\"? : None, .. } else {\n    fail(\"unexpected map contents\")\n  }\n\n  // Direct access (panics if key missing)\n  let value : Int = map[\"a\"] // value = 10\n\n  // Iteration preserves insertion order\n  for k, v in map {\n    println(\"\\{k}: \\{v}\") // Prints: a: 10, b: 2, c: 3, new-key: 3\n  }\n\n  // Other common operations\n  map.remove(\"b\")\n  guard map is { \"a\": 10, \"c\": 3, \"new-key\": 3, .. } && map.length() == 3 else {\n    // \"b\" is gone, only 3 elements left  \n    fail(\"unexpected map contents after removal\")\n  }\n}\n```\n\n## View Types\n\n**Key Concept**: View types (`StringView`, `BytesView`, `ArrayView[T]`) are zero-copy, non-owning read-only slices created with the `[:]` syntax. They don't allocate memory and are ideal for passing sub-sequences without copying data, for function which takes String, Bytes, Array, they also take *View(implicit conversion).\n\n- `String` → `StringView` via `s[:]` or `s[start:end]`\n- `Bytes` → `BytesView` via `b[:]` or `b[start:end]`\n- `Array[T]`, `FixedArray[T]`, `ReadOnlyArray[T] → `ArrayView[T]` via `a[:]` or `a[start:end]`\n\n**Important**: StringView slice is slightly different due to unicode safety:\n`s[a:b]` may raise an error at surrogate boundaries (UTF-16 encoding edge case). You have two options:\n\n- Use `try! s[a:b]` if you're certain the boundaries are valid (crashes on invalid boundaries)\n- Let the error propagate to the caller for proper handling\n\n**When to use views**:\n\n- Pattern matching with rest patterns (`[first, .. rest]`)\n- Passing slices to functions without allocation overhead\n- Avoiding unnecessary copies of large sequences\n\nConvert back with `.to_string()`, `.to_bytes()`, or `.to_array()` when you need ownership. (`moon doc StringView`)\n\n## User defined types(`enum`, `struct`)\n\n```mbt check\n///|\nenum Tree[T] {\n  Leaf(T) // Unlike Rust, no comma here\n  Node(left~ : Tree[T], T, right~ : Tree[T]) // enum can use labels\n} derive(Show, ToJson) // derive traits for Tree\n\n///|\npub fn Tree::sum(tree : Tree[Int]) -> Int {\n  match tree {\n    Leaf(x) => x \n    // we don't need to write Tree::Leaf, when `tree` has a known type\n    Node(left~, x, right~) => left.sum() + x + right.sum() // method invoked in dot notation\n  }\n}\n\n///|\nstruct Point {\n  x : Int\n  y : Int\n} derive(Show, ToJson) // derive traits for Point\n\ntest \"user defined types: enum and struct\" {\n  @json.inspect(Point::{ x: 10, y: 20 }, content=({\"x\":10,\"y\":20}))\n}\n\n```\n\n## Functional `for` loop\n\n\n```mbt check\npub fn binary_search(\n  arr : ArrayView[Int],\n  value : Int,\n) -> Result[Int, Int] {\n  let len = arr.length()\n  // functional for loop:\n  // initial state ; [predicate] ; [post-update] {\n  // loop body with `continue` to update state\n  //} else { // exit block\n  // }\n  // predicate and post-update are optional\n  for i = 0, j = len; i < j; {\n    // post-update is omitted, we use `continue` to update state\n    let h = i + (j - i) / 2\n    if arr[h] < value {\n      continue h + 1, j // functional update of loop state\n    } else {\n      continue i, h // functional update of loop state\n    }\n  } else { // exit of for loop\n    if i < len && arr[i] == value {\n      Ok(i)\n    } else {\n      Err(i)\n    }\n  } where {\n    invariant : 0 <= i && i <= j && j <= len,\n    invariant : i == 0 || arr[i - 1] < value,\n    invariant : j == len || arr[j] >= value,\n    reasoning :\n      #|For a sorted array, the boundary invariants are witnesses:\n      #|  - `arr[i-1] < value` implies all arr[0..i) < value (by sortedness)\n      #|  - `arr[j] >= value` implies all arr[j..len) >= value (by sortedness)\n      #|\n      #|Preservation proof:\n      #|  - When arr[h] < value: new_i = h+1, and arr[new_i - 1] = arr[h] < value ✓\n      #|  - When arr[h] >= value: new_j = h, and arr[new_j] = arr[h] >= value ✓\n      #|\n      #|Termination: j - i decreases each iteration (h is strictly between i and j)\n      #|\n      #|Correctness at exit (i == j):\n      #|  - By invariants: arr[0..i) < value and arr[i..len) >= value\n      #|  - So if value exists, it can only be at index i\n      #|  - If arr[i] != value, then value is absent and i is the insertion point\n      #|\n  }\n}\n\n///|\ntest \"functional for loop control flow\" {\n  let arr : Array[Int] = [1, 3, 5, 7, 9]\n  inspect(binary_search(arr,5), content=\"Ok(2)\") // Array to ArrayView implicit conversion when passing as arguments\n  inspect(binary_search(arr,6), content=\"Err(3)\")\n  // for iteration is supported too\n  for i, v in arr {\n    println(\"\\{i}: \\{v}\") // `i` is index, `v` is value\n  }\n}\n```\nYou are *STRONGLY ENCOURAGED* to use functional `for` loops instead of imperative loops\n*WHENEVER POSSIBLE*, as they are easier to reason about.\n\n### Loop Invariants with `where` Clause\n\nThe `where` clause attaches **machine-checkable invariants** and **human-readable reasoning** to functional `for` loops. This enables formal verification thinking while keeping the code executable. Note for trivial loops, you are encouraged to convert it into `for .. in` so no reasoning is needed.\n\n**Syntax:**\n```mbt nocheck\nfor ... {\n  ...\n} where {\n  invariant : <boolean_expr>,   // checked at runtime in debug builds\n  invariant : <boolean_expr>,   // multiple invariants allowed\n  reasoning : <string>         // documentation for proof sketch\n}\n```\n\n**Writing Good Invariants:**\n\n1. **Make them checkable**: Invariants must be valid MoonBit boolean expressions using loop variables and captured values.\n\n2. **Use boundary witnesses**: For properties over ranges (e.g., \"all elements in arr[0..i) satisfy P\"), check only boundary elements. For sorted arrays, `arr[i-1] < value` implies all `arr[0..i) < value`.\n\n3. **Handle edge cases with `||`**: Use patterns like `i == 0 || arr[i-1] < value` to handle boundary conditions where the check would be out of bounds.\n\n4. **Cover three aspects in reasoning**:\n   - **Preservation**: Why each `continue` maintains the invariants\n   - **Termination**: Why the loop eventually exits (e.g., a decreasing measure)\n   - **Correctness**: Why the invariants at exit imply the desired postcondition\n\n## Label and Optional Parameters\n\nGood example: use labeled and optional parameters\n\n```mbt check\n///|\nfn g(\n  positional : Int,\n  required~ : Int,\n  optional? : Int, // no default => Option\n  optional_with_default? : Int = 42, // default => plain Int\n) -> String {\n  // These are the inferred types inside the function body.\n  let _ : Int = positional\n  let _ : Int = required\n  let _ : Int? = optional\n  let _ : Int = optional_with_default\n  \"\\{positional},\\{required},\\{optional},\\{optional_with_default}\"\n}\n\n///|\ntest {\n  inspect(g(1, required=2), content=\"1,2,None,42\")\n  inspect(g(1, required=2, optional=3), content=\"1,2,Some(3),42\")\n  inspect(g(1, required=4, optional_with_default=100), content=\"1,4,None,100\")\n}\n```\n\nMisuse: `arg : Type?` is not an optional parameter.\nCallers still must pass it (as `None`/`Some(...)`).\n\n```mbt check\n///|\nfn with_config(a : Int?, b : Int?, c : Int) -> String {\n  \"\\{a},\\{b},\\{c}\"\n}\n\n///|\ntest {\n  inspect(with_config(None, None, 1), content=\"None,None,1\")\n  inspect(with_config(Some(5), Some(5), 1), content=\"Some(5),Some(5),1\")\n}\n```\n\nAnti-pattern: `arg? : Type?` (no default => double Option).\nIf you want a defaulted optional parameter, write `b? : Int = 1`, not `b? : Int? = Some(1)`.\n\n```mbt check\n///|\nfn f_misuse(a? : Int?, b? : Int = 1) -> Unit {\n  let _ : Int?? = a // rarely intended\n  let _ : Int = b\n\n}\n// How to fix: declare `(a? : Int, b? : Int = 1)` directly.\n\n///|\nfn f_correct(a? : Int, b? : Int = 1) -> Unit {\n  let _ : Int? = a\n  let _ : Int = b\n\n}\n\n///|\ntest {\n  f_misuse(b=3)\n  f_misuse(a=Some(5), b=2) // works but confusing\n  f_correct(b=2)\n  f_correct(a=5)\n}\n```\n\nBad example: `arg : APIOptions` (use labeled optional parameters instead)\n\n```mbt check\n///|\n/// Do not use struct to group options.\nstruct APIOptions {\n  width : Int?\n  height : Int?\n}\n\n///|\nfn not_idiomatic(opts : APIOptions, arg : Int) -> Unit {\n\n}\n\n///|\ntest {\n  // Hard to use in call site\n  not_idiomatic({ width : Some(5), height : None }, 10)\n  not_idiomatic({ width : None, height : None }, 10)\n}\n```\n\n## More details\n\nFor deeper syntax, types, and examples, read `references/moonbit-language-fundamentals.mbt.md`.\n","frontmatter":{"name":"moonbit-agent-guide","description":"Guide for writing, refactoring, and testing MoonBit projects. Use when working in MoonBit modules or packages, organizing MoonBit files, using moon tooling (build/check/test/doc/ide), or following MoonBit-specific layout, documentation, and testing conventions."},"isInternal":false,"tokens":9524,"sizeBytes":35827},{"name":"README.md","path":"packages/fractional-index/README.md","rawUrl":"https://raw.githubusercontent.com/loro-dev/loro/HEAD/packages/fractional-index/README.md","title":"fractional-index Documentation","category":"plugin-manifest","format":"markdown","content":"# @loro-dev/fractional-index\n\nTypeScript implementation of Loro's Rust `loro_fractional_index` crate.\n\nThis package creates compact string positions that sort lexicographically. The\npublic API always accepts and returns canonical uppercase hex strings, so indexes\nare easy to store, compare, serialize, and use as object or map keys.\n\n- No runtime dependencies.\n- ESM output with TypeScript declarations.\n- Public indexes are plain strings.\n- Generated strings are byte-for-byte compatible with the Rust crate's\n  `Display` output.\n- Golden tests are generated from the Rust implementation in this repository.\n\n## Install\n\n```sh\npnpm add @loro-dev/fractional-index\n```\n\n```sh\nnpm install @loro-dev/fractional-index\n```\n\n```sh\nyarn add @loro-dev/fractional-index\n```\n\n## Quick Start\n\n```ts\nimport { FractionalIndex, compare } from \"@loro-dev/fractional-index\";\n\nconst first = FractionalIndex.default();\nconst before = FractionalIndex.newBefore(first);\nconst after = FractionalIndex.newAfter(first);\nconst middle = FractionalIndex.newBetween(first, after);\n\nconsole.log(first); // \"80\"\nconsole.log(before); // \"7F80\"\nconsole.log(after); // \"8180\"\nconsole.log(middle); // \"817F80\"\n\nconst ordered = [after, first, before].sort(compare);\nconsole.log(ordered); // [\"7F80\", \"80\", \"8180\"]\n\nJSON.stringify({ position: first }); // \"{\\\"position\\\":\\\"80\\\"}\"\n```\n\nGenerated indexes are canonical uppercase hex strings. For generated values,\nordinary string comparison also follows byte order:\n\n```ts\nbefore < first; // true\nfirst < after; // true\n```\n\nUse `compare(a, b)` when sorting values that may have been parsed from external\ninput, because it compares by bytes after parsing.\n\n## Data Model\n\nAn index string is the uppercase hex encoding of the same bytes used by Rust.\nGenerated indexes include the `0x80` terminator byte.\n\n```ts\nconst index = FractionalIndex.default(); // \"80\"\n```\n\nThe public API does not expose byte arrays. Internally, the implementation still\nuses bytes to stay aligned with the Rust algorithm.\n\n## Creating Indexes\n\n### Default\n\n```ts\nconst index = FractionalIndex.default(); // \"80\"\n```\n\nThis matches `FractionalIndex::default()` in Rust.\n\n### Before And After\n\n```ts\nconst base = FractionalIndex.default();\n\nconst before = FractionalIndex.newBefore(base); // \"7F80\"\nconst after = FractionalIndex.newAfter(base); // \"8180\"\n```\n\n### Between Two Indexes\n\n```ts\nconst left = FractionalIndex.default();\nconst right = FractionalIndex.newAfter(left);\nconst between = FractionalIndex.newBetween(left, right);\n\nif (between) {\n  console.log(left < between); // true for canonical generated strings\n  console.log(between < right); // true\n}\n```\n\n`newBetween()` returns `undefined` when the Rust crate would return `None`.\nFor byte sequences that trigger a Rust panic, this package throws an `Error`\ninstead of returning a misleading value.\n\n### General Constructor\n\n`FractionalIndex.new(lower, upper)` mirrors Rust's `FractionalIndex::new`:\n\n```ts\nFractionalIndex.new(undefined, undefined); // default \"80\"\nFractionalIndex.new(existing, undefined); // after existing\nFractionalIndex.new(undefined, existing); // before existing\nFractionalIndex.new(left, right); // between left and right\n```\n\n`null` and `undefined` are both treated as an absent bound.\n\n## Generating Many Indexes\n\nUse `generateNEvenly()` when you know how many positions you need. It produces\nstrictly sorted indexes inside the open interval `(lower, upper)`.\n\n```ts\nconst values = FractionalIndex.generateNEvenly(undefined, undefined, 5);\n\nconsole.log(values);\n// [\"7E80\", \"7F80\", \"80\", \"817F80\", \"8180\"]\n```\n\nBounded generation:\n\n```ts\nconst lower = FractionalIndex.newBefore(FractionalIndex.default());\nconst upper = FractionalIndex.newAfter(FractionalIndex.default());\n\nconst values = FractionalIndex.generateNEvenly(lower, upper, 100);\n```\n\nThe method returns `undefined` if both bounds are provided and `lower >= upper`.\n\n## Jitter\n\nThe Rust crate can append random bytes after the terminator. This package exposes\nthe same behavior through `JitterOptions`.\n\n```ts\nconst index = FractionalIndex.jitterDefault({ jitter: 3 });\nconsole.log(index.length); // 8 hex chars: 0x80 plus 3 random bytes\n```\n\nFor deterministic tests or replicated fixtures, provide `randomByte`:\n\n```ts\nconst bytes = [1, 2, 3];\nlet offset = 0;\n\nconst index = FractionalIndex.jitterDefault({\n  jitter: 3,\n  randomByte: () => bytes[offset++],\n});\n\nconsole.log(index); // \"80010203\"\n```\n\nJitter variants:\n\n```ts\nFractionalIndex.jitterDefault({ jitter: 2 });\nFractionalIndex.newJitter(lower, upper, { jitter: 2 });\nFractionalIndex.newBeforeJitter(index, { jitter: 2 });\nFractionalIndex.newAfterJitter(index, { jitter: 2 });\nFractionalIndex.newBetweenJitter(left, right, { jitter: 2 });\nFractionalIndex.generateNEvenlyJitter(lower, upper, 10, { jitter: 2 });\n```\n\n`jitter` and `randomByte` must both be integers in `[0, 255]`, matching Rust's\n`u8` boundary.\n\n## Parsing And Serialization\n\n```ts\nconst fromHex = FractionalIndex.fromHexString(\"80ff\");\nconsole.log(fromHex); // \"80FF\"\n```\n\nCompatibility notes:\n\n- `fromHexString()` accepts uppercase or lowercase hex and returns canonical\n  uppercase hex.\n- Like Rust, `fromHexString()` ignores a trailing odd nibble. `\"80A\"` parses as\n  `\"80\"`.\n- Invalid hex pairs throw `SyntaxError`.\n\n## API Reference\n\n```ts\ntype FractionalIndex = string;\n\ninterface JitterOptions {\n  jitter?: number;\n  randomByte?: () => number;\n}\n```\n\n### Namespace API\n\n```ts\nFractionalIndex.TERMINATOR; // 128\n\nFractionalIndex.default(): FractionalIndex;\nFractionalIndex.fromHexString(hex): FractionalIndex;\n\nFractionalIndex.new(lower?, upper?): FractionalIndex | undefined;\nFractionalIndex.newBefore(index): FractionalIndex;\nFractionalIndex.newAfter(index): FractionalIndex;\nFractionalIndex.newBetween(left, right): FractionalIndex | undefined;\nFractionalIndex.generateNEvenly(lower, upper, n): FractionalIndex[] | undefined;\n\nFractionalIndex.jitterDefault(options?): FractionalIndex;\nFractionalIndex.newJitter(lower, upper, options?): FractionalIndex | undefined;\nFractionalIndex.newBeforeJitter(index, options?): FractionalIndex;\nFractionalIndex.newAfterJitter(index, options?): FractionalIndex;\nFractionalIndex.newBetweenJitter(left, right, options?): FractionalIndex | undefined;\nFractionalIndex.generateNEvenlyJitter(\n  lower,\n  upper,\n  n,\n  options?,\n): FractionalIndex[] | undefined;\n\nFractionalIndex.compare(left, right): number;\nFractionalIndex.equals(left, right): boolean;\nFractionalIndex.isFractionalIndex(value): value is FractionalIndex;\n```\n\n### Top-Level Helpers\n\nNamespace methods are also available as named exports. Since `new` is a\nJavaScript keyword, `FractionalIndex.new()` is exported as `newIndex()`:\n\n```ts\ndefaultIndex();\nfromHexString(hex);\ncompare(left, right);\nequals(left, right);\nnewIndex(lower, upper);\nnewBefore(index);\nnewAfter(index);\nnewBetween(left, right);\ngenerateNEvenly(lower, upper, n);\njitterDefault(options);\nnewJitter(lower, upper, options);\nnewBeforeJitter(index, options);\nnewAfterJitter(index, options);\nnewBetweenJitter(left, right, options);\ngenerateNEvenlyJitter(lower, upper, n, options);\nisFractionalIndex(value);\n```\n\n## Testing Against Rust\n\nThe golden fixture used by the TypeScript tests is generated from the Rust crate:\n\n```sh\npnpm --filter @loro-dev/fractional-index fixtures:generate\npnpm --filter @loro-dev/fractional-index check\n```\n\nThe fixture covers:\n\n- Default, before, after, and between generation.\n- Long before/after chains.\n- `generate_n_evenly` for bounded and unbounded ranges.\n- `None` cases.\n- Rust panic edge cases.\n- Jitter byte placement.\n- Hex serialization.\n\n## Development Commands\n\nThis package uses Vite+ (`vp`) for build, test, lint, and format orchestration.\n\n```sh\npnpm --filter @loro-dev/fractional-index format\npnpm --filter @loro-dev/fractional-index lint\npnpm --filter @loro-dev/fractional-index typecheck\npnpm --filter @loro-dev/fractional-index test\npnpm --filter @loro-dev/fractional-index build\npnpm --filter @loro-dev/fractional-index check\n```\n\n`lint` runs oxlint in type-aware mode with warnings denied. `format` and\n`format:check` use oxfmt. `typecheck` uses `tsgo`. `build` runs `vp pack` and\nemits the ESM bundle, declarations, and sourcemap to `dist/`.\n\n## Performance Notes\n\nString indexes are optimized for JavaScript ergonomics: comparison, JSON,\nstorage, and use as keys are all straightforward. The implementation parses\nstrings to byte arrays internally for generation so it can stay aligned with the\nRust byte algorithm. For the expected workload of normal list/tree positioning,\nthis keeps the API simple without a meaningful practical performance cost.\n","isInternal":false,"tokens":2101,"sizeBytes":8638}],"systemPromptSnippet":"<yakaai_skills repo=\"loro-dev/loro\">\n<!-- File: AGENTS.md (Tokens: ~2374 | Category: root-instruction) -->\n# Repository Guidelines\n\n## Project Snapshot\n\nLoro is a Rust CRDT workspace with JS/WASM packaging and a MoonBit codec.\n\n- `crates/loro`: public Rust API; avoid breaking downstream users.\n- `crates/loro-internal`: core CRDT logic. Read its\n  [AGENTS.md](crates/loro-internal/AGENTS.md) before changing import/export,\n  encoding, state, diff, checkout, or replay behavior.\n- `crates/loro-wasm`: `loro-crdt` WASM/TypeScript package. Read its\n  [AGENTS.md](crates/loro-wasm/AGENTS.md) before changing bindings, exports,\n  wrappers, or build scripts.\n- `crates/delta`, `crates/rle`, `crates/kv-store`, `crates/fractional_index`,\n  `crates/loro-common`, and `packages/fractional-index`: shared primitives and\n  packages.\n- `moon/`: MoonBit Loro binary codec; use [skills/moonbit/SKILL.md](skills/moonbit/SKILL.md).\n\n## Context Index\n\n- Undo/redo item boundaries when remote edits make an inverse a no-op:\n  [context/undo-history-boundaries.md](context/undo-history-boundaries.md).\n- Rust undo failure rollback and transaction writer serialization:\n  [context/undo-atomicity.md](context/undo-atomicity.md).\n- Encoding/import/export modes, current vs outdated formats, shallow snapshots:\n  [context/internal-encoding.md](context/internal-encoding.md).\n- Mergeable container model, marker/cid rules, tests, and common pitfalls:\n  [context/mergeable-containers.md](context/mergeable-containers.md).\n- `import_batch` force-detach, batch-wide rollback scope, and the never-exit-detached\n  invariant: [context/import-batch-atomicity.md](context/import-batch-atomicity.md).\n- Which root containers are visible (history-touched vs handle-acquired), and\n  why replays materialize empty roots:\n  [context/root-container-visibility.md](context/root-container-visibility.md).\n- Imports that reuse local op ids (a shared peer id): the known-history check,\n  what counts as equal, and what it cannot catch:\n  [context/import-peer-id-reuse.md](context/import-peer-id-reuse.md).\n- `apply_diff`/`revert_to` rollback of a failed batch, reused op ids, other\n  threads: [context/apply-diff-atomicity.md](context/apply-diff-atomicity.md).\n- Movable-list `Move`/`Set` import validation, and why a move of a deleted element\n  is applied rather than rejected:\n  [context/movable-list-op-validation.md](context/movable-list-op-validation.md).\n- Shallow-snapshot dead-style redaction (null-only, both-expand exclusion,\n  root-whitelisted latest state):\n  [context/shallow-snapshot-style-redaction.md](context/shallow-snapshot-style-redaction.md).\n- Rich-text insert positions next to style anchors, the insert cursor cache,\n  and delete `start_id`s: [context/richtext-insert-positions.md](context/richtext-insert-positions.md).\n- Tree diff cache transitions and why their lamport window comes from the two\n  versions, not the replay base: [context/tree-checkout-window.md](context/tree-checkout-window.md).\n- Tree event invariants (revived subtrees get `Create`s) and the two event\n  paths, diff-calculator vs raw ops: [context/tree-events.md](context/tree-events.md).\n- Deep tree traversal, snapshot order, and iterative result disposal:\n  [context/tree-depth.md](context/tree-depth.md).\n- loro.js tree diff item order, index counting, apply resolution, and batch dry-run:\n  [context/loro-js-tree-diff.md](context/loro-js-tree-diff.md).\n- loro.js concurrent tree moves, skipped cycles, replay, checkout, and undo:\n  [context/loro-js-tree-moves.md](context/loro-js-tree-moves.md).\n- User-facing Loro usage, sync, editor integration, and performance guidance:\n  [skills/loro/SKILL.md](skills/loro/SKILL.md).\n- Pure TypeScript runtime indexes, complexity contracts, benchmarks, and remaining gaps:\n  [context/loro-js-performance.md](context/loro-js-performance.md).\n- loro.js vs Rust randomized Text differential tests and the Rust behaviors they\n  work around: [context/loro-js-rust-differential.md](context/loro-js-rust-differential.md).\n- loro.js rich-text style anchors, entity positions, and Rust's insert/delete/mark\n  position rules: [context/loro-js-richtext-anchors.md](context/loro-js-richtext-anchors.md).\n- loro.js multi-peer differential fuzzing against replay, checkout, event, and\n  Rust/WASM oracles: [context/loro-js-differential-fuzz.md](context/loro-js-differential-fuzz.md).\n- loro.js MovableList model, the MovableList Rust differential suite\n  (`loro-js/tests/differential/`), and known loro.js/Rust divergences:\n  [context/loro-js-movable-list.md](context/loro-js-movable-list.md).\n- WASM panic/OOM reporting channels, `__wbindgen_start` glue invariant, and\n  trap-testing recipes:\n  [context/wasm-error-reporting.md](context/wasm-error-reporting.md).\n- WASM container id wrapper identity, lazy caching, and benchmark:\n  [context/wasm-container-id-cache.md](context/wasm-container-id-cache.md).\n- Bounded decoded-value cache in `InnerStore` (second-chance FIFO, eviction\n  safety contract, loro-dev/loro#1092):\n  [context/container-value-cache.md](context/container-value-cache.md).\n- Deep plain value decoding, Drop, and WASM conversion stack safety:\n  [context/deep-value-stack-safety.md](context/deep-value-stack-safety.md).\n- How the arena learns a container's parent (parsed changes, state KV, the op\n  log's creator resolver), its locking (including `ChangeStore`'s lock order),\n  and import rollback: [context/arena-parent-links.md](context/arena-parent-links.md).\n- Why a failed import's rollback keeps arena indices (DocState, caches and handlers\n  are keyed by them) and what it drops instead:\n  [context/failed-import-arena-indices.md](context/failed-import-arena-indices.md).\n- Which deletions `DocState::is_deleted` caches, and how tree/movable-list\n  children are revived: [context/dead-container-cache.md](context/dead-container-cache.md).\n- Movable-list `apply_diff`/undo: delete + re-insert of a child becomes a move,\n  cursor invariant, pitfalls: [context/movable-list-apply-diff.md](context/movable-list-apply-diff.md).\n- Unknown container types (newer-version containers): never created locally,\n  `apply_diff`/undo pre-check, events, test forging:\n  [context/unknown-containers.md](context/unknown-containers.md).\n- Why parsed change blocks keep text and list values out of doc-wide arenas\n  (`ValueSlice`, tracker tables): [context/text-arena-growth.md](context/text-arena-growth.md).\n- User callbacks that panic (subscribers, pre-commit, local updates): no poisoned\n  locks, lost events or hangs: [context/callback-panics.md](context/callback-panics.md).\n- Context backlog: [context/CONTEXT-GAPS.md](context/CONTEXT-GAPS.md).\n\n## Commands\n\n- JS deps: `pnpm install --frozen-lockfile`.\n- Rust build/check/format/lint: `cargo build`, `cargo check -p loro-internal`,\n  `cargo fmt --all`, `pnpm check`.\n- Rust tests: `pnpm test`; internal doctests: `cargo test -p loro-internal --doc`.\n- Loom: `pnpm test-loom`.\n- WASM: `pnpm release-wasm`, or `pnpm -C crates/loro-wasm build-dev`.\n- Bundlers after WASM packaging changes: `pnpm test-bundlers`; browser runtime:\n  `pnpm --dir examples/bundler-smoke-tests run test:browser`.\n- Fractional-index TS: `pnpm test-fractional-index`.\n- Fuzz smoke: `pnpm run-fuzz-corpus`.\n- MoonBit codec, when `moon` is available: from `moon/`, run `moon check`,\n  `moon test`, `moon fmt`.\n\nUse narrow checks first. Ask before broad fuzzing or long browser matrices.\n\n## Working Rules\n\n- Start with `git status --short --branch`; treat uncommitted changes as user\n  work unless you made them.\n- Before editing, read every `AGENTS.md` from root to target directory. Keep\n  `CLAUDE.md` as a symlink to the nearest `AGENTS.md`.\n- Use `rg` / `rg --files` for search.\n- Public API changes in `loro` or `loro-crdt` should be backward-compatible when\n  possible. Prefer new `try_*` APIs over breaking signatures.\n- Internal corruption should fail fast; invalid external input should return\n  `Err`. Returning wrong state is worse than panicking on an impossible internal\n  invariant.\n- Add regression tests near behavior: `crates/loro/tests`,\n  `crates/loro-internal/tests`, module tests, `crates/loro-wasm/tests`, or\n  `moon/loro_codec/*_test.mbt`.\n- Add a changeset for publishing behavior or package output changes.\n- Do not hand-edit generated WASM package output; regenerate it with package\n  scripts.\n\n## Self-Maintained Agent Context\n\n- Treat \"why was that hard to find?\" as a context bug. Add a nearby\n  `AGENTS.md` pointer or a `context/` article, or append a line to\n  [context/CONTEXT-GAPS.md](context/CONTEXT-GAPS.md).\n- Keep root context short. If an `AGENTS.md` grows past about 4000 characters, move\n  detail into a linked `context/` article.\n- Header context articles with `Verified against code YYYY-MM-DD`, anchor claims\n  to files/symbols, and link them from root plus the nearest per-directory\n  `AGENTS.md`.\n- If code changes make an `AGENTS.md` or context article stale, update the docs\n  in the same change.\n- When a commit needs non-obvious rationale, land that rationale in the nearest\n  context file and keep the commit message as a pointer.\n\n## Commit And PR Notes\n\nHistory uses short imperative commits, often prefixed by `fix:`, `test:`,\n`chore:`, or `refactor:`. PRs should include summary, rationale, validation, and\nlinked issues or traces when relevant.\n- Structured WASM reads, node identity, ranges and performance responsibilities:\n  [context/wasm-container-tree.md](context/wasm-container-tree.md).\n\n<!-- File: loro-js/AGENTS.md (Tokens: ~743 | Category: root-instruction) -->\n# loro.js\n\nPure TypeScript implementation of Loro (`loro-js/src`). It must read and write\nthe same binary and JSON data as Rust (`loro-crdt`) and give the same results.\n\n## Context\n\n- Concurrent tree moves, skipped cycles, replay, checkout, and undo:\n  [context/loro-js-tree-moves.md](../context/loro-js-tree-moves.md).\n- Undo/redo no-op return values and item boundaries:\n  [context/undo-history-boundaries.md](../context/undo-history-boundaries.md).\n- Index structures, complexity contracts, and benchmarks:\n  [context/loro-js-performance.md](../context/loro-js-performance.md).\n- Randomized Text comparison with Rust (build the nodejs WASM package first):\n  [context/loro-js-rust-differential.md](../context/loro-js-rust-differential.md).\n- Multi-peer fuzzing of all containers against replay, checkout, event, and\n  shallow-snapshot oracles, optionally in lockstep with Rust:\n  [context/loro-js-differential-fuzz.md](../context/loro-js-differential-fuzz.md).\n- MovableList model (Rust's positions + LWW elements) and its multi-peer Rust\n  differential suite (`tests/differential/`):\n  [context/loro-js-movable-list.md](../context/loro-js-movable-list.md).\n- Rich text: style anchors live in the Text sequence and op positions count\n  them. Read [context/loro-js-richtext-anchors.md](../context/loro-js-richtext-anchors.md)\n  before changing Text positions, marks, or Text snapshot state.\n- Encoding formats: [context/internal-encoding.md](../context/internal-encoding.md)\n  and `docs/encoding*.md`.\n\n## Interop fixtures\n\n- Rust output read by loro.js: `tests/fixtures/rust/*.blob` and `*.json`.\n- loro.js output read by Rust: `pnpm fixtures:rewrite` runs\n  `scripts/rewrite-rust-fixture.mjs`, which writes `tests/fixtures/rust/*.ts.blob`;\n  `crates/loro/tests/loro_js_interop.rs` imports them. Container state encoders\n  live in `src/runtime/document.ts` (`#containerState`) and must follow\n  `docs/encoding-container-states.md`.\n- loro.js 0.2 output read by later versions: `scripts/write-legacy-fixtures.mjs`\n  writes `tests/fixtures/loro-js-0.2/` with a 0.2 build; `tests/legacy-data.test.ts`\n  pins that loro.js and Rust read it the same way. Later versions read 0.2 data\n  with Rust's semantics, with no version marker (README \"Upgrading from 0.2\"; the\n  decision is in [context/loro-js-rust-differential.md](../context/loro-js-rust-differential.md)).\n\n## Commands\n\nFrom `loro-js/`: `pnpm test`, `pnpm typecheck`, `pnpm lint`, `pnpm format:check`,\n`pnpm build`, or `pnpm check` for all of them. From the root, `pnpm test-loro-js`\nruns the tests and fails if the Rust WASM reference is missing (CI runs it after\n`release-wasm`). Benchmarks: `pnpm bench:b4`,\n`pnpm bench:complexity -- 1000,2000,4000,8000`.\n\n<!-- File: CLAUDE.md (Tokens: ~3 | Category: claude-rule) -->\nAGENTS.md\n\n<!-- File: loro-js/CLAUDE.md (Tokens: ~3 | Category: claude-rule) -->\nAGENTS.md\n\n<!-- File: skills/loro/agents/openai.yaml (Tokens: ~62 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Loro\"\n  short_description: \"Guide for adopting and using Loro in apps\"\n  default_prompt: \"Use $loro to design or explain a Loro-powered app, from choosing a language binding through modeling, sync, editors, React state, and performance.\"\n\n<!-- File: skills/loro/references/containers-and-encoding.md (Tokens: ~1076 | Category: anthropic-skill) -->\n# Containers And Encoding\n\n## Container Choice\n\n- `LoroMap`: LWW key-value storage. Good for object-like state, coordinates, metadata, URLs, and fields where overwriting is preferable to merging.\n- `LoroList`: ordered sequence with insert/delete semantics.\n- `LoroMovableList`: ordered sequence with native move and set semantics. Prefer for drag-and-drop or reorder-heavy UIs.\n- `LoroTree`: hierarchical moves plus node-local data maps. Prefer for outlines, layers, nested blocks, or parent-child structures.\n- `LoroCounter`: additive numeric CRDT. Use when concurrent increments/decrements must accumulate.\n- `LoroText`: collaborative text. Use `updateByLine(...)` when line-oriented reconciliation is preferable to raw whole-string replacement.\n\n## Behavioral Notes\n\n- `LoroMap` compares concurrent writes by logical time and retains the winning value.\n- Setting a map entry to the same value is a no-op, so it does not create history.\n- `LoroList` and `LoroMovableList` both support stable cursors; use them when positions must survive concurrent edits.\n\n## Choice Pitfalls\n\n- Do not store editable prose as a plain string in a map unless LWW semantics are desired.\n- Do not model coordinates as `[x, y]` in a list. Concurrent delete+insert can create invalid arrays. Use a map.\n- Do not model arbitrary graphs directly. Loro documents compose as trees, not DAGs with shared children.\n\n## Container States And Composition\n\n- Detached containers come from constructors like `new LoroMap()`.\n- Attached containers belong to a document and have stable `ContainerID`s.\n- Adding a detached container to a document returns an attached version; the original object remains detached.\n- Root containers come from `doc.getMap(...)`, `doc.getText(...)`, `doc.getList(...)`, `doc.getTree(...)`, and so on.\n- For map-key children that may be lazily created by multiple peers, use `ensureMergeable*` in JS/TS or `ensure_mergeable_*` in Rust.\n- Use `setContainer(...)` / `insertContainer(...)` for regular child creation or replacement; list-position `insertContainer(...)` is unchanged.\n\n## Mergeable Map Children And Overwrite Hazards\n\n- Root container IDs derive from root name plus type.\n- Regular child container IDs derive from the operation that created them.\n- Mergeable map-key child IDs derive from the parent map, key, and type, so concurrent first creation at the same key converges to the same child.\n- Prefer `ensureMergeableText`, `ensureMergeableMap`, `ensureMergeableList`, `ensureMergeableMovableList`, `ensureMergeableTree`, or `ensureMergeableCounter` for dynamic fields, lazy migrations, per-date lists, and other map-key children that should behave as one shared child.\n- `getOrCreateContainer` / `get_or_create_container` is legacy regular child creation; do not recommend it for lazy map-key children.\n\n## Tree Specifics\n\n- `LoroTree` gives each node an associated `Map` container via `node.data`.\n- Fractional indices order siblings. Use them when child ordering matters.\n- When many peers insert at the same sibling position, peer ID acts as a tiebreaker for equal fractional indices.\n- Fractional index jitter reduces collisions at some encoding-size cost.\n- `getNodes(...)` and node JSON views are useful when a flat inspection of the forest is easier than recursive traversal.\n\n## List Vs Movable List\n\n- Use `LoroList` when delete+insert is acceptable and native move identity is unnecessary.\n- Use `LoroMovableList` for kanban columns, cards, playlist reordering, or any UX where “move this item” is semantically distinct from delete+insert.\n\n## Counter\n\n- `Counter` aggregates applied values from all peers.\n- It is the right choice for additive metrics, not for values with hard invariants.\n\n## Export Modes\n\n- `update`: sync delta payloads.\n- `updates-in-range`: bounded history export.\n- `snapshot`: full state checkpoint.\n- `shallow-snapshot`: current state plus truncated history.\n\n## Import Choices\n\n- `import(...)`: one payload at a time.\n- `importBatch(...)`: preferred for multiple updates or mixed snapshot/update payloads because diffing and event emission are coalesced.\n- Imports can succeed partially when dependencies are missing. Pending ranges mean the document knows about those operations but cannot apply them yet.\n\n## Persistence Pattern\n\n1. Periodically save a snapshot.\n2. Frequently persist updates, often after each local edit or on a debounce.\n3. On load, import the snapshot and outstanding updates.\n4. Recompact by exporting a fresh snapshot and deleting replayed updates.\n\n## Shallow Snapshots And Redaction\n\n- Use shallow snapshots when old history can be archived or discarded.\n- They are often much smaller than full snapshots.\n- Peers can only sync if they have versions after the shallow start point.\n- Archive full history before trimming if old history may still matter.\n- Redaction replaces sensitive payloads while preserving enough structure for future synchronization.\n- If old peers still hold unsanitized history, sensitive data still exists there.\n\n<!-- File: skills/loro/references/fit-and-architecture.md (Tokens: ~976 | Category: anthropic-skill) -->\n# Getting Started And Fit\n\n## When Loro Fits\n\n- Collaborative text and structured documents.\n- Offline-first applications that later synchronize.\n- Multi-device sync where eventual consistency is acceptable.\n- Apps that benefit from complete history, time travel, or version checkpoints.\n\n## When Loro Does Not Fit By Itself\n\n- Financial or accounting invariants.\n- Exclusive ownership or booking/locking semantics.\n- Authorization decisions that must be enforced at write time.\n- Arbitrary graph-shaped or non-JSON-like data without an adaptation layer.\n\n## Install\n\n- JavaScript/TypeScript: install `loro-crdt`.\n- Rust: install the `loro` crate.\n- Use editor integrations when available instead of writing editor sync from scratch:\n  - `loro-prosemirror` for ProseMirror and Tiptap-style editors.\n  - `loro-codemirror` for CodeMirror 6.\n- Use `loro-mirror` and `loro-mirror-react` when the app already thinks in immutable state and actions.\n\n## Language And Package Index\n\n- JavaScript/TypeScript: [`loro-crdt`](https://www.npmjs.com/package/loro-crdt). Start here for web apps and most examples in the Loro docs.\n- Rust: [`loro`](https://crates.io/crates/loro) and [`docs.rs/loro`](https://docs.rs/loro). Use for native Rust apps, services, CLIs, and custom infrastructure.\n- Swift: [`loro-swift`](https://github.com/loro-dev/loro-swift). Use for Swift/iOS/macOS experiments and native apps.\n- Python: [`loro-py`](https://github.com/loro-dev/loro-py). Use for Python apps, scripts, and server-side tooling.\n- React Native: [`loro-react-native`](https://github.com/loro-dev/loro-react-native). Use for mobile apps that need native React Native bindings.\n- C#: [`loro-cs`](https://github.com/sensslen/loro-cs). Community-maintained .NET/C# binding; check its README and release state before adopting.\n- Go: [`loro-go`](https://github.com/aholstenson/loro-go). Community-maintained Go binding; check platform support and API completeness before adopting.\n- Cross-language FFI base: [`loro-ffi`](https://github.com/loro-dev/loro-ffi). Use this as the reference for generated/native bindings and as a starting point for new language bindings.\n\nPrefer the official JS/TS or Rust package when there is no product reason to choose another language. For community bindings, verify platform binaries, Loro core version, and API coverage before making product commitments.\n\n## First JavaScript Example\n\n```ts\nimport { LoroDoc } from \"loro-crdt\";\n\nconst docA = new LoroDoc();\nconst listA = docA.getList(\"items\");\nlistA.insert(0, \"A\");\nlistA.insert(1, \"B\");\n\nconst update = docA.export({ mode: \"update\" });\n\nconst docB = new LoroDoc();\ndocB.import(update);\n\nconsole.log(docB.toJSON()); // { items: [\"A\", \"B\"] }\n```\n\n## First Design Questions\n\n1. What parts of the state should merge when edited concurrently?\n2. Which data needs durable history, and which data is only presence or UI state?\n3. Do users need text/rich-text intent preservation, ordered moves, tree moves, or simple last-write-wins fields?\n4. How will peers exchange updates, and where will snapshots or updates be persisted?\n\n## Conceptual Model\n\n- Loro is a CRDT framework for local-first apps.\n- It trades strict coordination for strong eventual consistency.\n- Each peer edits locally, exports updates, imports updates from other peers, and converges after seeing the same operations.\n- Loro records history, so versioning and time travel are core concepts rather than an afterthought.\n\n## Document Shape Constraints\n\n- Loro documents are JSON-like.\n- Map keys are strings.\n- The composed document structure is tree-shaped, not a general graph with shared children.\n\n## Entry Points\n\n- Core packages and language bindings are listed in `Language And Package Index`.\n- Ecosystem integrations include editor bindings, state-mirroring layers, React Native, and Inspector.\n\n## Practical Start Path\n\n1. Pick container types in `containers-and-encoding.md`.\n2. Decide sync and persistence shape in `sync-versioning-and-events.md`.\n3. Add editor or React integration only after the document model is clear.\n4. Use Inspector during development to inspect state and history.\n\n<!-- File: skills/loro/references/mirror-and-react.md (Tokens: ~685 | Category: anthropic-skill) -->\n# Mirror And React\n\n## Mirror Intent\n\n- `loro-mirror` keeps an immutable app-state view in sync with a `LoroDoc`.\n- Local `setState(...)` edits become granular CRDT operations.\n- Remote CRDT events patch the mirrored app state back in.\n- The common mental model is still “immutable app state plus typed actions”, not direct mutation of raw CRDT containers everywhere.\n\n## Root Schema\n\n- Build the root with `schema({...})`.\n- Keep root fields as Loro containers: `LoroMap`, `LoroList`, `LoroMovableList`, `LoroText`.\n- Put primitives inside those containers, not at the root.\n\n## Field Types\n\n- `schema.String`, `schema.Number`, `schema.Boolean`: concrete primitive fields.\n- `schema.Any`: dynamic JSON-like payload when the shape is truly unknown.\n- `schema.Ignore`: local-only or derived fields that should not sync to Loro.\n\n## Maps, Lists, And `$cid`\n\n- `schema.LoroMap({...})`: nested object container.\n- `schema.LoroMap(...).catchall(valueSchema)`: add dynamic keys while preserving known keys.\n- `schema.LoroMapRecord(valueSchema)`: homogeneous record-like map.\n- Every mirrored `LoroMap` includes a read-only `$cid`.\n- `$cid` matches the underlying Loro container ID.\n- Use `$cid` as a stable key or default `idSelector`, especially for list items.\n- Never try to persist or mutate `$cid` from app code.\n- Do not invent a `withCid`-style option; mirrored map values already receive `$cid` automatically.\n\n## Lists\n\n- `LoroList(itemSchema, idSelector?)`: ordered collection. Add `idSelector` for stable add/remove/update/move diffs.\n- `LoroMovableList(itemSchema, idSelector)`: native move semantics, ideal for drag-and-drop.\n- If a list item is a map, `(item) => item.$cid` is often the right `idSelector`.\n\n## Defaults And Validation\n\n- Explicit `defaultValue` wins.\n- Required fields without explicit defaults fall back to built-in defaults.\n- `validateUpdates` is enabled by default in `Mirror`. Keep it on unless a measured hot path proves otherwise.\n- Use `validateSchema(...)` when you need an explicit validation pass during migration or debugging.\n\n## React Patterns\n\n- Create a stable `LoroDoc` instance.\n- Create helpers through `createLoroContext(schema)` or `useLoroStore(...)`.\n- Wrap the tree in `LoroProvider` when using the context pattern.\n- Use the narrowest hook that solves the task:\n  - `useLoroState` for the full mirrored state\n  - `useLoroSelector` for focused subscriptions\n  - `useLoroAction` for write paths\n- Keep the provider `doc` stable across renders.\n- Prefer `useLoroSelector` over pulling the full state into every component.\n- Use mirrored list item `$cid` values as React keys.\n\n## Practical Mental Model\n\n- Subscribe to order at collection boundaries.\n- Subscribe to content at item boundaries.\n- Pass `$cid`s downward and reselect locally instead of passing large mirrored objects through the whole tree.\n- Keep view-local state outside the mirror unless collaborators must share it.\n\n<!-- File: skills/loro/references/performance-and-tradeoffs.md (Tokens: ~428 | Category: anthropic-skill) -->\n# Performance And Tradeoffs\n\nUse this chapter when users ask whether Loro can handle a workload, how to store data efficiently, or why one sync/storage design is preferable to another.\n\n## What To Compare\n\n- Encoded document size and update size.\n- Snapshot export/import time.\n- Update import time.\n- Memory footprint while editing and loading.\n- Conflict-heavy collaboration versus mostly independent edits.\n- Initial load path versus steady-state sync path.\n\n## Practical Defaults\n\n- Use update exchange for live collaboration.\n- Use snapshots for fast startup checkpoints.\n- Store frequent small updates between snapshots when durable replay is needed.\n- Recompact by exporting a fresh snapshot after enough updates accumulate.\n- Consider shallow snapshots when old history can be archived or discarded.\n\n## Workload-Specific Advice\n\n- Collaborative text: use `LoroText`; do not model text as a plain string just to reduce apparent complexity.\n- Reorder-heavy collections: use `LoroMovableList` instead of delete+insert if move identity matters.\n- Hierarchies: use `LoroTree`; avoid forcing tree-shaped data into ad hoc map/list structures.\n- High-frequency presence or cursor movement: use `EphemeralStore`, not the persisted document.\n- Hard invariants such as balances, bookings, or permissions still need application/server-side validation outside the CRDT merge.\n\n## Benchmark Interpretation\n\n- Treat benchmarks as workload indicators, not universal rankings.\n- A smaller full snapshot does not automatically mean smaller incremental updates.\n- A fast import path matters most for startup and bulk sync.\n- A compact update path matters most for live collaboration and bandwidth-constrained clients.\n- Shallow snapshots reduce retained history, but peers with only older history may need a fresh snapshot or archived history to sync.\n\n## Explain Tradeoffs\n\n- Loro optimizes for local editing, automatic merging, history, and version control.\n- Strong eventual consistency means peers converge after receiving the same operations.\n- Loro does not provide central locking, serializable transactions, or write-time authorization by itself.\n- Pick containers by merge semantics first, then tune storage and sync format for performance.\n\n<!-- File: skills/loro/references/richtext-and-editors.md (Tokens: ~555 | Category: anthropic-skill) -->\n# Rich Text And Editors\n\n## Rich Text Rules\n\n- Use `LoroText` for collaboratively edited text.\n- Keep rich text style config in sync across peers:\n  - `after`\n  - `before`\n  - `none`\n  - `both`\n- If two peers use different `configTextStyle(...)`, they can interpret the same boundary insert differently.\n\n## Text API Notes\n\n- `update(...)` rewrites based on a target text snapshot.\n- `updateByLine(...)` is useful when line-oriented reconciliation is more appropriate than raw whole-string replacement.\n- `toDelta()` preserves marks and annotations.\n- `toJSON()` / `toString()` return plain text only.\n\n## `applyDelta(...)` Caveat\n\n- `applyDelta(...)` is ideal for editor bindings because it matches event diffs.\n- Delta inserts must include the full attribute set of the inserted range.\n- If CRDT inheritance would add marks but the delta omits them, `applyDelta(...)` removes those attributes.\n- Out-of-range formatting can cause Loro to materialize newlines to satisfy editor assumptions.\n\n## Stable Selections\n\n- Use `text.getCursor(...)` to create stable positions.\n- Use two cursors for selections: anchor and head.\n- Resolve live offsets with `doc.getCursorPos(...)`.\n- Persist updated cursors returned from resolution to reduce replay cost.\n- JavaScript text offsets are UTF-16 indices.\n\n## ProseMirror And Tiptap\n\n- Start with `loro-prosemirror` for ProseMirror and Tiptap.\n- It already covers document sync, collaborative undo and redo, and cursor presence.\n- The current baseline is `CursorEphemeralStore` plus `LoroEphemeralCursorPlugin`.\n- Give each editor instance its own `containerId` when several editors share one `LoroDoc`.\n- Reuse the same container only if several views intentionally co-edit the exact same content.\n\n## CodeMirror\n\n- Use the official CodeMirror integration when the editor is CM6-based.\n- Keep awareness/presence, undo, and document sync at the Loro layer rather than inventing a separate editor-level protocol.\n\n## Rich Text Internals\n\n- Loro rich text uses style anchors to represent mark boundaries.\n- Overlap and expansion behavior are first-class concerns.\n- Overlappable styles are often best modeled by unique keys with a shared prefix pattern such as `comment:alice` and `comment:bob`.\n\n## Guardrails\n\n- Do not model editable prose as `string` in a `LoroMap`.\n- Do not store collaborative selections as plain indices.\n- Do not mix old and new ProseMirror cursor APIs accidentally; check the installed package version and current API docs first.\n\n<!-- File: skills/loro/references/sync-versioning-and-events.md (Tokens: ~1061 | Category: anthropic-skill) -->\n# Sync, Versioning, And Events\n\n## General Sync Guarantees\n\n- If two peers eventually hold the same set of operations, they converge to the same state.\n- Delivery order, duplication, and temporary disconnection are transport concerns, not document-consistency failures.\n- For steady-state collaboration, sync updates rather than full snapshots whenever possible.\n\n## Sync Patterns\n\n- Give every peer a unique peer ID. Reusing peer IDs can make updates look duplicated and break convergence.\n- Prefer update exchange over whole snapshots for steady-state sync:\n  - `subscribeLocalUpdates(...)` for push-based transport.\n  - `export({ mode: \"update\", from })` when you track a known sync point.\n- Use `importBatch(...)` for multiple updates or mixed snapshot/update payloads. It performs one diff calculation and emits one combined event.\n- `EphemeralStore` local updates should be transported separately from persisted document updates.\n\n## Version Representations\n\n- `VersionVector`: explicit peer-to-counter map. Best for synchronization, inclusion checks, and self-contained network state.\n- `Frontiers`: compact boundary operations. Best for checkpoints and time travel.\n- Convert between them when needed; vectors are explicit, frontiers are compact.\n\n## State Vs History\n\n- `version()` / `frontiers()`: the current visible DocState.\n- `oplogVersion()` / `oplogFrontiers()`: the latest history known to the OpLog.\n- When attached, state and history usually align.\n- After `checkout(...)`, DocState can diverge from OpLog. That is detached mode.\n\n## Attached Vs Detached\n\n- Detached document state means “viewing history” or otherwise not showing the latest OpLog.\n- Detached container state means “not yet inserted into a document.”\n- These are separate concepts.\n\n## `checkout(...)` Versus `revertTo(...)`\n\n- `checkout(frontiers)`: move document state to an old version. This puts the doc into detached mode.\n- `checkoutToLatest()` or `attach()`: return to the latest attached state.\n- `revertTo(frontiers)`: generate new operations that transform the current document into the target historical state. The doc stays attached.\n\n## Peer IDs\n\n- Every operation ID is `(peerId, counter)`.\n- Never reuse peer IDs across concurrent sessions.\n- Do not use user IDs as peer IDs.\n\n## Operations, Changes, Transactions\n\n- Operations are atomic edits.\n- Changes are logical groups of operations with metadata.\n- Transactions batch operations for event emission and grouping.\n- Loro transactions are not ACID transactions and do not provide rollback semantics.\n- Changes can carry timestamp, commit message, dependencies, peer identity, and other metadata.\n- Consecutive operations may merge into one Change depending on merge rules and timing configuration.\n\n## Import Status\n\n- `ImportStatus.success` tells you what applied.\n- `ImportStatus.pending` tells you what is blocked on missing dependencies.\n- Check pending ranges in out-of-order networks.\n\n## Event Timing Caveat\n\n- Some older examples describe JS events as microtask-delayed.\n- Modern `loro-crdt` dispatches events synchronously at the JS boundary.\n- Check the installed package version and current API docs before relying on old timing examples.\n\n## Event Sources\n\n- Events can be triggered by local commits, imports, and checkouts.\n- Implicit commits happen around operations like export, import, and checkout.\n\n## `subscribePreCommit(...)`\n\n- Use it when commit metadata or change-level hooks must catch both explicit and implicit commits.\n- It is the right place for setting commit message and timestamp.\n- Combined with `exportJsonInIdSpan(...)`, it can drive change hashing or Merkle-DAG-like workflows.\n\n## Timestamps\n\n- Timestamp recording is configurable.\n- `setRecordTimestamp(...)` and `setChangeMergeInterval(...)` affect how changes merge over time.\n- These settings are runtime configuration, not durable document state.\n\n## Inspector\n\n- Use Loro Inspector when you need to browse current state plus full edit history interactively.\n- Prefer it for “what happened to this doc?” debugging before writing custom debug UI.\n\n## Sync Debugging\n\n- If imports arrive out of order, inspect `ImportStatus.pending`.\n- If checkout seems stale, compare DocState version to OpLog version.\n- If commit metadata hooks miss implicit commits, use `subscribePreCommit(...)` rather than adding ad hoc commit calls.\n\n## Undo, Cursor, And Ephemeral Presence\n\n- `UndoManager` is local to one peer. When peer identity changes, the undo and redo stacks reset.\n- Use `onPush` and `onPop` to store selection state together with undo items.\n- Use `groupStart()` and `groupEnd()` when one UX action spans multiple commits.\n- Use `Cursor`, not absolute indices, for selections and carets that must survive concurrent edits.\n- Store two cursors for a selection: anchor and head.\n- Persist the updated cursor returned by `doc.getCursorPos(cursor)` when available; it reduces future replay cost.\n- Use `EphemeralStore` for presence, cursor payloads, hover state, and other collaboration data that must not persist in the CRDT document.\n\n<!-- File: skills/loro/references/topic-map.md (Tokens: ~764 | Category: anthropic-skill) -->\n# Topic Map\n\nUse this file to choose the right user-facing chapter inside the unified `loro` skill.\n\n## Route By User Ask\n\n- “I am new to Loro. How do I start?”\n  - Read `fit-and-architecture.md`\n- “Which package, language binding, or platform should I use?”\n  - Read `fit-and-architecture.md`\n- “Should I use Loro here?”\n  - Read `fit-and-architecture.md`\n- “Which container should I choose?”\n  - Read `containers-and-encoding.md`\n- “How should I sync, persist, time-travel, use undo, or debug imports?”\n  - Read `sync-versioning-and-events.md`\n- “How do I integrate rich text editors?”\n  - Read `richtext-and-editors.md`\n- “How do I use loro-mirror with React?”\n  - Read `mirror-and-react.md`\n- “How will Loro behave at scale?”\n  - Read `performance-and-tradeoffs.md`\n\n## Getting Started And Product Fit\n\n- Install choices, language bindings, first example, local-first framing\n  - Read `fit-and-architecture.md`\n- When CRDTs are the wrong fit\n  - Read `fit-and-architecture.md`\n- Package entry points and ecosystem overview\n  - Read `fit-and-architecture.md`\n\n## Containers, Composition, Storage\n\n- Choosing between `LoroMap`, `LoroList`, `LoroMovableList`, `LoroTree`, `LoroCounter`, `LoroText`\n  - Read `containers-and-encoding.md`\n- Composition rules, container states, container IDs, overwrite hazards\n  - Read `containers-and-encoding.md`\n- Snapshot, update, shallow snapshot, updates-in-range\n  - Read `containers-and-encoding.md`\n- Persistence, redaction, history trimming\n  - Read `containers-and-encoding.md`\n\n## Sync, Versions, History, Events\n\n- Peer sync, update exchange, realtime sync, offline merge\n  - Read `sync-versioning-and-events.md`\n- Frontiers, version vectors, OpLog vs DocState\n  - Read `sync-versioning-and-events.md`\n- Checkout, time travel, attached vs detached state\n  - Read `sync-versioning-and-events.md`\n- Peer IDs, import status, transactions, changes, timestamps\n  - Read `sync-versioning-and-events.md`\n- Event timing, `subscribePreCommit`, Inspector\n  - Read `sync-versioning-and-events.md`\n- Undo, cursors, and ephemeral presence\n  - Read `sync-versioning-and-events.md`\n\n## Text, Rich Text, And Editors\n\n- `LoroText`, marks, delta APIs, `updateByLine`, stable selections\n  - Read `richtext-and-editors.md`\n- ProseMirror, Tiptap, CodeMirror, custom editor bindings\n  - Read `richtext-and-editors.md`\n- Rich text internals, style anchors, overlap, expansion rules\n  - Read `richtext-and-editors.md`\n\n## App-State Mirroring\n\n- `loro-mirror`, schemas, `$cid`, `idSelector`, validation\n  - Read `mirror-and-react.md`\n- `loro-mirror-react`, selectors, provider/hooks patterns\n  - Read `mirror-and-react.md`\n\n## Performance And Tradeoffs\n\n- Loading speed, encoded size, memory, update size\n  - Read `performance-and-tradeoffs.md`\n- Conflict-heavy vs low-conflict workloads\n  - Read `performance-and-tradeoffs.md`\n- When to use snapshots, shallow snapshots, or update streams\n  - Read `performance-and-tradeoffs.md`\n\n<!-- File: skills/loro/SKILL.md (Tokens: ~997 | Category: anthropic-skill) -->\n---\nname: loro\ndescription: \"Practical guide for helping app developers evaluate, adopt, and use Loro for local-first collaboration. Use when Codex needs to answer questions or write examples for `loro-crdt`, `loro`, `loro-prosemirror`, `loro-codemirror`, `loro-mirror`, language bindings such as Swift/Python/C#/Go/React Native, or Loro-powered apps about: (1) Deciding whether Loro fits a product, (2) Getting started in JavaScript/TypeScript, Rust, or another supported binding, (3) Choosing CRDT containers and document structure, (4) Designing sync, persistence, snapshots, versioning, undo, presence, or time travel, (5) Integrating rich-text editors and stable selections, (6) Mirroring app state with React, or (7) Understanding performance and tradeoffs.\"\n---\n\n# Loro\n\nUse this skill to help users build applications with Loro. Start from the user's product goal, then choose the narrowest chapter that answers it. Load a second chapter only when the task crosses domains.\n\n## Select A Chapter\n\n- Read [references/topic-map.md](references/topic-map.md) if the task is broad and you need to route it.\n- Read [references/fit-and-architecture.md](references/fit-and-architecture.md) for product fit, installation, language/package choices, first examples, and core mental models.\n- Read [references/containers-and-encoding.md](references/containers-and-encoding.md) for choosing containers, shaping documents, exporting updates, snapshots, persistence, shallow snapshots, and redaction.\n- Read [references/sync-versioning-and-events.md](references/sync-versioning-and-events.md) for realtime/offline sync, version vectors, frontiers, checkout, undo, presence, timestamps, events, and Inspector.\n- Read [references/richtext-and-editors.md](references/richtext-and-editors.md) for `LoroText`, cursors, `applyDelta`, `updateByLine`, `loro-prosemirror`, Tiptap, and CodeMirror.\n- Read [references/mirror-and-react.md](references/mirror-and-react.md) for `loro-mirror`, `$cid`, `idSelector`, validation, selectors, and React integration.\n- Read [references/performance-and-tradeoffs.md](references/performance-and-tradeoffs.md) for scaling, document/update size, loading speed, and workload tradeoffs.\n\n## Route Common Tasks\n\n- “I am new to Loro / should I use it / show me a first example”\n  - Start with `fit-and-architecture.md`\n- “Which language package or binding should I use?”\n  - Start with `fit-and-architecture.md`\n- “Build a collaborative document model / choose data types / persist history”\n  - Start with `containers-and-encoding.md`\n  - Add `sync-versioning-and-events.md` if version/history behavior matters\n- “Sync devices, store data, use snapshots, time travel, undo, or presence”\n  - Start with `sync-versioning-and-events.md`\n- “Integrate ProseMirror, Tiptap, CodeMirror, or custom rich text”\n  - Start with `richtext-and-editors.md`\n  - Add `sync-versioning-and-events.md` if undo/version/event behavior matters\n- “Model app state with loro-mirror or loro-mirror-react”\n  - Start with `mirror-and-react.md`\n  - Add `containers-and-encoding.md` if schema semantics depend on container choice\n- “Explain performance, large documents, loading, update size, or tradeoffs”\n  - Start with `performance-and-tradeoffs.md`\n- “Decide whether Loro is the right tool”\n  - Start with `fit-and-architecture.md`\n  - Add `performance-and-tradeoffs.md` if workload scale matters\n\n## Execute The Task\n\n1. Classify the task before reading everything.\n2. Load one primary chapter.\n3. Load at most one secondary chapter for cross-domain work.\n4. Keep solutions grounded in Loro semantics:\n   - choose data types by merge behavior,\n   - distinguish state version from history version,\n   - keep ephemeral state out of persisted CRDT data,\n   - use stable cursors for collaborative selections,\n   - design sync around updates and snapshots rather than a central locking protocol.\n\n## Keep Guardrails\n\n- Do not assume CRDTs are the right fit for hard invariants, exclusivity, or authorization-at-write-time problems.\n- Do not model editable text as plain strings when user intent requires merged edits.\n- Do not reuse peer IDs across concurrent sessions.\n- Do not confuse detached documents with detached containers.\n- Do not persist cursor presence, hover state, or connection state inside the main document; use ephemeral state.\n\n<!-- File: skills/moonbit/ide.md (Tokens: ~840 | Category: anthropic-skill) -->\n## Code Navigation with `moon ide`\n\n**ALWAYS use `moon ide` for code navigation in MoonBit projects instead of manual file searching, grep, or semantic search.**\n\nThis tool provides two essential commands for precise code exploration:\n\n### Core Commands\n\n- `moon ide goto-definition` - Find where a symbol is defined\n- `moon ide find-references` - Find all usages of a symbol\n\n### Query System\n\nSymbol lookup uses a two-part query system for precise results:\n\n#### 1. Symbol Name Query (`-query`)\n\nFuzzy search for symbol names with package filtering support:\n\n```bash\n# Find any symbol named 'symbol'\nmoon ide goto-definition -query 'symbol'\n\n# Find methods of a specific type\nmoon ide goto-definition -query 'Type::method'\n\n# Find trait method implementations\nmoon ide goto-definition -query 'Trait for Type with method'\n\n# Find symbol in specific package using @pkg prefix\nmoon ide goto-definition -query '@moonbitlang/x encode'\n\n# Find symbol in multiple packages (searches in pkg1 OR pkg2)\nmoon ide goto-definition -query '@username/mymodule/pkg1 @username/mymodule/pkg2 helper'\n\n# Find symbol in nested package\nmoon ide goto-definition -query '@username/mymodule/mypkg helper'\n```\n\n**Supported symbols**: functions, constants, let bindings, types, structs, enums, traits\n\n**Package filtering**: Prefix your query with `@package_name` to scope the search. Multiple `@pkg` prefixes create an OR condition.\n\n#### 2. Tag-based Filtering (`-tags`)\n\nPre-filter symbols by characteristics before name matching:\n\n**Visibility tags**:\n\n- `pub` - Public symbols\n- `pub all` - Public structs with all public fields\n- `pub open` - Public traits with all methods public\n- `priv` - Private symbols\n\n**Symbol type tags**:\n\n- `type` - Type definitions (struct, enum, typealias, abstract)\n- `error` - Error type definitions\n- `enum` - Enum definitions and variants\n- `struct` - Struct definitions\n- `alias` - Type/function/trait aliases\n- `let` - Top-level let bindings\n- `const` - Constant definitions\n- `fn` - Function definitions\n- `trait` - Trait definitions\n- `impl` - Trait implementations\n- `test` - Named test functions\n\n**Combine tags with logical operators**:\n\n```bash\n# Public functions only\nmoon ide goto-definition -tags 'pub fn' -query 'my_func'\n\n# Functions or constants\nmoon ide goto-definition -tags 'fn | const' -query 'helper'\n\n# Public functions or constants\nmoon ide goto-definition -tags 'pub (fn | const)' -query 'api'\n\n# Public types or traits\nmoon ide goto-definition -tags 'pub (type | trait)' -query 'MyType'\n```\n\n### Practical Examples\n\n```bash\n# Find public function definition\nmoon ide goto-definition -tags 'pub fn' -query 'maximum'\n\n# Find all references to a struct\nmoon ide find-references -tags 'struct' -query 'Rectangle'\n\n# Find trait implementations\nmoon ide goto-definition -tags 'impl' -query 'Show for MyType'\n\n# Find errors in specific package\nmoon ide goto-definition -tags 'error' -query '@mymodule/parser ParseError'\n\n# Find symbol across multiple packages\nmoon ide goto-definition -query '@moonbitlang/x @moonbitlang/core encode'\n\n# Combine package filtering with tags\nmoon ide goto-definition -tags 'pub fn' -query '@username/myapp helper'\n```\n\n### Query Processing\n\nThe tool processes queries in this order:\n\n1. Filter symbols by `-tags` conditions\n2. Extract package scope from `@pkg` prefixes in `-query`\n3. Fuzzy match remaining symbols by name\n4. Return top 3 best matches with location information\n\n**Best Practice**: Start with `-tags` to reduce noise, then use `@pkg` prefixes in `-query` to scope by package for precise navigation.\n\n<!-- File: skills/moonbit/README.md (Tokens: ~369 | Category: anthropic-skill) -->\n# MoonBit Agent Skill\n\nThis repository contains a [Agent Skill](https://agentskills.io/home) that teaches AI coding agents the MoonBit language and its toolchain.\n\n## Integrate the Skill into your agent\n\nDifferent AI assistants require different configuration methods. Below are guides for popular coding assistants:\n\n### Codex CLI\n\n```shell\nmkdir -p ~/.codex/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ~/.codex/skills/moonbit\n```\n\nDocumentation: https://developers.openai.com/codex/skills\n\n### Claude Code\n\n```shell\nmkdir -p ~/.claude/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ~/.claude/skills/moonbit\n```\n\nDocumentation: https://code.claude.com/docs/en/skills\n\n### GitHub Copilot for VS Code\n\n```shell\n# enable moonbit skill for current repository\nmkdir -p ./.github/skills/\ngit clone https://github.com/moonbitlang/moonbit-agent-guide ./.github/skills/moonbit\n```\n\nNote: Agent Skills support in VS Code is currently in preview and available only in [VS Code Insiders](https://code.visualstudio.com/insiders/). Enable the `chat.useAgentSkills` setting to use Agent Skills. See [Use Agent Skills in VS Code](https://code.visualstudio.com/docs/copilot/customization/agent-skills) for details.\n\n### Cursor & Cursor CLI\n\n> Agent Skills are available only in the Cursor nightly release channel.\n\nDocumentation: https://cursor.com/cn/docs/context/skills\n\n### Gemini CLI\n\nIt seems that Gemini CLI will support agent skills in next release: https://github.com/google-gemini/gemini-cli/issues/15327\n\n<!-- File: skills/moonbit/references/advanced-moonbit-build.md (Tokens: ~674 | Category: anthropic-skill) -->\n## Conditional Compilation\n\nTarget specific backends/modes in `moon.pkg.json`:\n\n```json\n{\n  \"targets\": {\n    \"wasm_only.mbt\": [\"wasm\"],\n    \"js_only.mbt\": [\"js\"],\n    \"debug_only.mbt\": [\"debug\"],\n    \"wasm_or_js.mbt\": [\"wasm\", \"js\"], // for wasm or js backend\n    \"not_js.mbt\": [\"not\", \"js\"], // for nonjs backend\n    \"complex.mbt\": [\"or\", [\"and\", \"wasm\", \"release\"], [\"and\", \"js\", \"debug\"]] // more complex conditions\n  }\n}\n```\n\n**Available conditions:**\n\n- **Backends**: `\"wasm\"`, `\"wasm-gc\"`, `\"js\"`, `\"native\"`\n- **Build modes**: `\"debug\"`, `\"release\"`\n- **Logical operators**: `\"and\"`, `\"or\"`, `\"not\"`\n\n## Link Configuration\n\n### Basic Linking\n\n```json\n{\n  \"link\": true, // Enable linking for this package\n  // OR for advanced cases:\n  \"link\": {\n    \"wasm\": {\n      \"exports\": [\"hello\", \"foo:bar\"], // Export functions\n      \"heap-start-address\": 1024, // Memory layout\n      \"import-memory\": {\n        // Import external memory\n        \"module\": \"env\",\n        \"name\": \"memory\"\n      },\n      \"export-memory-name\": \"memory\" // Export memory with name\n    },\n    \"wasm-gc\": {\n      \"exports\": [\"hello\"],\n      \"use-js-builtin-string\": true, // JS String Builtin support\n      \"imported-string-constants\": \"_\" // String namespace\n    },\n    \"js\": {\n      \"exports\": [\"hello\"],\n      \"format\": \"esm\" // \"esm\", \"cjs\", or \"iife\"\n    },\n    \"native\": {\n      \"cc\": \"gcc\", // C compiler\n      \"cc-flags\": \"-O2 -DMOONBIT\", // Compile flags\n      \"cc-link-flags\": \"-s\" // Link flags\n    }\n  }\n}\n```\n\n## Warning Control\n\nDisable specific warnings in `moon.mod.json` or `moon.pkg.json`:\n\n```json\n{\n  \"warn-list\": \"-2-29\" // Disable unused variable (2) & unused package (29)\n}\n```\n\n**Common warning numbers:**\n\n- `1` - Unused function\n- `2` - Unused variable\n- `11` - Partial pattern matching\n- `12` - Unreachable code\n- `29` - Unused package\n\nUse `moonc build-package -warn-help` to see all available warnings.\n\n## Pre-build Commands\n\nEmbed external files as MoonBit code:\n\n```json\n{\n  \"pre-build\": [\n    {\n      \"input\": \"data.txt\",\n      \"output\": \"embedded.mbt\",\n      \"command\": \":embed -i $input -o $output --name data --text\"\n    },\n    ... // more embed commands\n  ]\n}\n```\n\nGenerated code example:\n\n```mbt check\n///|\nlet data : String =\n  #|hello,\n  #|world\n  #|\n```\n\n<!-- File: skills/moonbit/references/moonbit-language-fundamentals.mbt.md (Tokens: ~2693 | Category: anthropic-skill) -->\n# MoonBit Language Fundamentals\n\n\n## Quick reference:\n\n```mbt check\n///|\n/// comments doc string\npub fn sum(x : Int, y : Int) -> Int {\n  x + y\n}\n\n///|\nstruct Rect {\n  width : Int\n  height : Int\n}\n\n///|\nfn Rect::area(self : Rect) -> Int {\n  self.width * self.height\n}\n\n///|\npub impl Show for Rect with output(_self, logger) {\n  logger.write_string(\"Rect\")\n}\n\n///|\nenum MyOption {\n  MyNone\n  MySome(Int)\n} derive(Show, ToJson, Eq, Compare)\n\n///|\n///  match + loops are expressions\ntest \"everything is expression in MoonBit\" {\n  // tuple\n  let (n, opt) = (1, MySome(2))\n  // if expressions return values\n  let msg : String = if n > 0 { \"pos\" } else { \"non-pos\" }\n  let res = match opt {\n    MySome(x) => {\n      inspect(x, content=\"2\")\n      1\n    }\n    MyNone => 0\n  }\n  let status : Result[Int, String] = Ok(10)\n  // match expressions return values\n  let description = match status {\n    Ok(value) => \"Success: \\{value}\"\n    Err(error) => \"Error: \\{error}\"\n  }\n  let array = [1, 2, 3, 4, 5]\n  let mut i = 0 // mutable bindings (local only, globals are immutable)\n  let target = 3\n  // loops return values with 'break'\n  let found : Int? = while i < array.length() {\n    if array[i] == target {\n      break Some(i) // Exit with value\n    }\n    i = i + 1\n  } else { // Value when loop completes normally\n    None\n  }\n  assert_eq(found, Some(2)) // Found at index 2\n}\n\n///|\n/// global bindings\npub let my_name : String = \"MoonBit\"\n\n///|\npub const PI : Double = 3.14159 // constants use UPPER_SNAKE or PascalCase\n\n///|\npub fn maximum(xs : Array[Int]) -> Int raise {\n  // Toplevel functions are *mutually recursive* by default\n  // `raise` annotation means the function would raise any Error\n  //  Only add `raise XXError` when you do need track the specific error type\n  match xs {\n    [] => fail(\"Empty array\") // fail() is built-in for generic errors\n    [x] => x\n    // pattern match over array, the `.. rest` is a rest pattern\n    // it is of type `ArrayView[Int]` which is a slice\n    [x, .. rest] => {\n      let mut max_val = x // `mut` only allowed in local bindings\n      for y in rest {\n        if y > max_val {\n          max_val = y\n        }\n      }\n      max_val // return can be omitted if the last expression is the return value\n    }\n  }\n}\n\n///|\n/// pub(all) means it can be both read and created outside the package\npub(all) struct Point {\n  x : Int\n  mut y : Int\n} derive(Show, ToJson)\n\n///|\npub enum MyResult[T, E] {\n  MyOk(T) // semicolon `;` is optional when we have a newline\n  MyErr(E) // Enum variants must start uppercase\n} derive(Show, Eq, ToJson)\n// pub means it can only be pattern matched outside the package\n// but it can not be created outside the package, use `pub(all)` otherwise\n\n///|\n/// pub (open) means the trait can be implemented for outside packages\npub(open) trait Comparable {\n  compare(Self, Self) -> Int // `Self` refers to the implementing type\n}\n\n///|\ntest \"inspect test\" {\n  let result = sum(1, 2)\n  inspect(result, content=\"3\")\n  // The `content` can be auto-corrected by running `moon test --update`\n  let point = Point::{ x: 10, y: 20 }\n  // For complex structures, use @json.inspect for better readability:\n  @json.inspect(point, content={ \"x\": 10, \"y\": 20 })\n}\n```\n\n\n## Complex Types\n\n```mbt check\n///|\npub type UserId = Int // Int is aliased to UserId - like symlink\n\n///|\n///  Tuple-struct for callback\npub struct Handler((String) -> Unit) // A newtype wrapper\n\n///|\n/// Tuple-struct syntax for single-field newtypes\nstruct Meters(Int) // Tuple-struct syntax\n\n///|\nlet distance : Meters = Meters(100)\n\n///|\nlet raw : Int = distance.0 // Access first field with .0\n\n///|\nstruct Addr {\n  host : String\n  port : Int\n} derive(Show, Eq, ToJson, FromJson)\n\n///|\n/// Structural types with literal syntax\nlet config : Addr = Addr::{\n  // `Type::` can be omitted since the type is already known\n  host: \"localhost\",\n  port: 8080,\n}\n\n\n```\n\n## Common Derivable Traits\n\nMost types can automatically derive standard traits using the `derive(...)` syntax:\n\n- **`Show`** - Enables `to_string()` and string interpolation with `\\{value}`\n- **`Eq`** - Enables `==` and `!=` equality operators\n- **`Compare`** - Enables `<`, `>`, `<=`, `>=` comparison operators\n- **`ToJson`** - Enables `@json.inspect()` for readable test output\n- **`Hash`** - Enables use as Map keys\n\n```mbt check\n///|\nstruct Coordinate {\n  x : Int\n  y : Int\n} derive(Show, Eq, ToJson)\n\n///|\nenum Status {\n  Active\n  Inactive\n} derive(Show, Eq, Compare)\n```\n\n**Best practice**: Always derive `Show` and `Eq` for data types. Add `ToJson` if you plan to test them with `@json.inspect()`.\n\n## Reference Semantics by Default\n\nMoonBit passes most types by reference semantically (the optimizer may copy\nimmutables):\n\n```mbt check\n///|\n///  Structs with 'mut' fields are always passed by reference\nstruct Counter {\n  mut value : Int\n}\n\n///|\nfn increment(c : Counter) -> Unit {\n  c.value += 1 // Modifies the original\n}\n\n///|\n/// Arrays and Maps are mutable references\nfn modify_array(arr : Array[Int]) -> Unit {\n  arr[0] = 999 // Modifies original array\n}\n\n///|\ntest \"reference semantics\" {\n  let counter : Ref[Int] = Ref::{ val: 0 }\n  counter.val += 1\n  assert_true(counter.val is 1)\n  let arr : Array[Int] = [1, 2, 3] // unlike Rust, no `mut` keyword needed\n  modify_array(arr)\n  assert_true(arr[0] is 999)\n  let mut x = 3 // `mut` neeed for re-assignment to the bindings\n  x += 2\n  assert_true(x is 5)\n}\n```\n\n## Pattern Matching\n\n```mbt check\n///|\n#warnings(\"-unused_value\")\ntest \"pattern match over Array, struct and StringView\" {\n  let arr : Array[Int] = [10, 20, 25, 30]\n  match arr {\n    [] => ... // empty array\n    [single] => ... // single element\n    [first, .. middle, rest] => {\n      let _ : ArrayView[Int] = middle // middle is ArrayView[Int]  \n      assert_true(first is 10 && middle is [20, 25] && rest is 30)\n    }\n  }\n  fn process_point(point : Point) -> Unit {\n    match point {\n      { x: 0, y: 0 } => ...\n      { x, y } if x == y => ...\n      { x, .. } if x < 0 => ...\n      ...\n    }\n  }\n  /// StringView pattern matching for parsing\n  fn is_palindrome(s : StringView) -> Bool {\n    loop s {\n      [] | [_] => true\n      [a, .. rest, b] if a == b => continue rest\n      // a is of type Char, rest is of type StringView\n      _ => false\n    }\n  }\n\n\n}\n```\n\n## Functional `loop` control flow\n\nThe `loop` construct is unique to MoonBit:\n\n```mbt check\n///|\n/// Functional loop with pattern matching on loop variables\n/// @list.List is from the standard library\nfn sum_list(list : @list.List[Int]) -> Int {\n  loop (list, 0) {\n    (Empty, acc) => acc // Base case returns accumulator\n    (More(x, tail=rest), acc) => continue (rest, x + acc) // Recurse with new values\n  }\n}\n\n///|\n///  Multiple loop variables with complex control flow\nfn find_pair(arr : Array[Int], target : Int) -> (Int, Int)? {\n  loop (0, arr.length() - 1) {\n    (i, j) if i >= j => None\n    (i, j) => {\n      let sum = arr[i] + arr[j]\n      if sum == target {\n        Some((i, j)) // Found pair\n      } else if sum < target {\n        continue (i + 1, j) // Move left pointer\n      } else {\n        continue (i, j - 1) // Move right pointer\n      }\n    }\n  }\n}\n```\n\n**Note**: You must provide a payload to `loop`. If you want an infinite loop, use `while true { ... }` instead. The syntax `loop { ... }` without arguments is invalid.\n\n\n## Methods and Traits\n\nMethods use `Type::method_name` syntax, traits require explicit implementation:\n\n```mbt check\n///|\nstruct Rectangle {\n  width : Double\n  height : Double\n}\n\n///|\n// Methods are prefixed with Type::\nfn Rectangle::area(self : Rectangle) -> Double {\n  self.width * self.height\n}\n\n///|\n/// Static methods don't need self\nfn Rectangle::new(w : Double, h : Double) -> Rectangle {\n  { width: w, height: h }\n}\n\n///|\n/// Show trait now uses output(self, logger) for custom formatting\n/// to_string() is automatically derived from this\npub impl Show for Rectangle with output(self, logger) {\n  logger.write_string(\"Rectangle(\\{self.width}x\\{self.height})\")\n}\n\n///|\n/// Traits can have non-object-safe methods\ntrait Named {\n  name() -> String // No 'self' parameter - not object-safe\n}\n\n///|\n/// Trait bounds in generics\nfn[T : Show + Named] describe(value : T) -> String {\n  \"\\{T::name()}: \\{value.to_string()}\"\n}\n\n///|\n///  Trait implementation\nimpl Hash for Rectangle with hash_combine(self, hasher) {\n  hasher..combine(self.width)..combine(self.height)\n}\n```\n\n## Operator Overloading\n\nMoonBit supports operator overloading through traits:\n\n```mbt check\n///|\nstruct Vector(Int, Int)\n\n///|\n/// Implement arithmetic operators\npub impl Add for Vector with add(self, other) {\n  Vector(self.0 + other.0, self.1 + other.1)\n}\n\n///|\nstruct Person {\n  age : Int\n} derive(Eq)\n\n///|\n/// Comparison operators\npub impl Compare for Person with compare(self, other) {\n  self.age.compare(other.age)\n}\n\n///|\ntest \"overloading\" {\n  let v1 : Vector = Vector(1, 2)\n  let v2 : Vector = Vector(3, 4)\n  let _v3 : Vector = v1 + v2\n\n}\n```\n\n## Access Control Modifiers\n\nMoonBit has fine-grained visibility control:\n\n```mbt check\n///|\n/// `fn` defaults to Private - only visible in current package\nfn internal_helper() -> Unit {\n  ...\n}\n\n///|\npub fn get_value() -> Int {\n  ...\n}\n\n///|\n// Struct (default) - type visible, implementation hidden\nstruct DataStructure {}\n\n///|\n/// `pub struct` defaults to readonly - can read, pattern match, but not create\npub struct Config {}\n\n///|\n///  Public all - full access\npub(all) struct Config2 {}\n\n///|\n/// Abstract trait (default) - cannot be implemented by\n/// types outside this package\npub trait MyTrait {}\n\n///|\n///  Open for extension\npub(open) trait Extendable {}\n```\n\n<!-- File: skills/moonbit/references/moonbit-language-fundamentals.md (Tokens: ~9 | Category: anthropic-skill) -->\nmoonbit-language-fundamentals.mbt.md\n\n<!-- File: skills/moonbit/SKILL.mbt.md (Tokens: ~3 | Category: anthropic-skill) -->\nSKILL.md\n\n<!-- File: skills/moonbit/SKILL.md (Tokens: ~9524 | Category: anthropic-skill) -->\n---\nname: moonbit-agent-guide\ndescription: Guide for writing, refactoring, and testing MoonBit projects. Use when working in MoonBit modules or packages, organizing MoonBit files, using moon tooling (build/check/test/doc/ide), or following MoonBit-specific layout, documentation, and testing conventions.\n---\n\n# MoonBit Project Layouts\n\nMoonBit use the `.mbt` extension and interface files `.mbti`. At\nthe top-level of a MoonBit project there is a `moon.mod.json` file specifying\nthe metadata of the project. The project may contain multiple packages, each\nwith its own `moon.pkg.json` file.\n\n## Example layout\n\n```\nmy_module\n├── moon.mod.json             # Module metadata, source field(optional) specifies the source directory of the module\n├── moon.pkg.json             # Package metadata (each directory is a package like Golang)\n├── README.mbt.md             # Markdown with tested code blocks (`test \"...\" { ... }`)\n├── README.md -> README.mbt.md\n├── cmd                       # Command line directory\n│   └── main\n│       ├── main.mbt\n│       └── moon.pkg.json     # executable package with {\"is_main\": true}\n├── liba/                     # Library packages\n│   └── moon.pkg.json         # Referenced by other packages as `@username/my_module/liba`\n│   └── libb/                 # Library packages\n│       └── moon.pkg.json     # Referenced by other packages as `@username/my_module/liba/libb`\n├── user_pkg.mbt              # Root packages, referenced by other packages as `@username/my_module`\n├── user_pkg_wbtest.mbt       # White-box tests (only needed for testing internal private members, similar to Golang's package mypackage)\n└── user_pkg_test.mbt         # Black-box tests\n└── ...                       # More package files, symbols visible to current package (like Golang)\n```\n\n- **Module**:  `moon.mod.json` file in the project directory.\n  A MoonBit *module* is like a Go module,it is a collection of packages in subdirectories, usually corresponding to a repository or project.\n  Module boundaries matter for dependency management and import paths.\n\n- **Package**: a `moon.pkg.json` file per directory. \n  All subcommands of `moon` will\n  still be executed in the directory of the module (where `moon.mod.json` is\n  located), not the current package.\n  A MoonBit *package* is the actual compilation unit (like a Go package).\n  All source files in the same package are concatenated into one unit.\n  The `package` name in the source defines the package, not the file name.\n  Imports refer to module + package paths, NEVER to file names.\n\n- **Files**:\n  A `.mbt` file is just a chunk of source inside a package.\n  File names do NOT create modules or namespaces.\n  You may freely split/merge/move declarations between files in the same package.\n  Any declaration in a package can reference any other declaration in that package, regardless of file.\n\n\n## Coding/layout rules you MUST follow:\n\n1. Prefer many small, cohesive files over one large file.\n   - Group related types and functions into focused files (e.g. http_client.mbt, router.mbt).\n   - If a file is getting large or unfocused, create a new file and move related declarations into it.\n\n2. You MAY freely move declarations between files inside the same package.\n   - 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.\n   - It is safe to refactor by splitting or merging files inside a package.\n\n3. File names are purely organizational.\n   - Do NOT assume file names define modules, and do NOT use file names in type paths.\n   - Choose file names to describe a feature or responsibility, not to mirror type names rigidly.\n\n4. When adding new code:\n   - Prefer adding it to an existing file that matches the feature.\n   - If no good file exists, create a new file under the same package with a descriptive name.\n   - Avoid creating giant “misc” or “util” files.\n\n5. Tests:\n   - Place tests in dedicated test files (e.g. *_test.mbt) within the appropriate package.\n     For a package, besides `*_test.mbt`files,`*.mbt.md`are also blackbox test files, the code block `mbt check` are treated as test cases, they serve both purposes: documentation and tests.      \n     You may have `README.mbt.md` files with `mbt check` code examples, you can also symlink `README.mbt.md` to `README.md`\n     to make it integrate better with GitHub.\n   - It is fine—and encouraged—to have multiple small test files.\n\n6. Interface files(`pkg.generated.mbti`) \n   `pkg.generated.mbti` is 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.\n   They are generated using `moon info`, 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.\n   \n   You can also use `moon doc @moonbitlang/core/strconv` to explore the public API of a package interactively and `moon ide peek-def 'Array::join'` to read\n   the definition.\n\n# Common Pitfalls to Avoid\n\n- **Don't use uppercase for variables/functions** - compilation error\n- **Don't forget `mut` for mutable record fields** - immutable by default\n- **Don't ignore error handling** - errors must be explicitly handled\n- **Don't use `return` unnecessarily** - last expression is the return value\n- **Don't create methods without Type:: prefix** - methods need explicit type prefix\n- **Don't forget to handle array bounds** - use `get()` for safe access\n- **Don't forget @package prefix when calling functions from other packages**\n- **Don't use ++ or -- (not supported)** - use `i = i + 1` or `i += 1`\n- **Don't add explicit `try` for error-raising functions** - errors propagate automatically (unlike Swift)\n- **Legacy syntax**: Older code may use `function_name!(...)` or `function_name(...)?` - these are deprecated; use normal calls and `try?` for Result conversion\n\n\n# `moon` Essentials\n\n## Essential Commands\n\n- `moon new my_project` - Create new project\n- `moon run cmd/main` - Run main package\n- `moon build` - Build project\n- `moon check` - Type check without building, use it REGULARLY, it is fast\n- `moon info` - Type check and generate `mbti` files\n  run it to see if any public interfaces changed.\n- `moon check --target all` - Type check for all backends\n- `moon add package` - Add dependency\n- `moon remove package` - Remove dependency\n- `moon fmt` - Format code\n\n### Test Commands\n\n- `moon test` - Run all tests\n- `moon test --update` - Update snapshots\n- `moon test -v` - Verbose output with test names\n- `moon test [dirname|filename]` - Test specific directory or file\n- `moon coverage analyze` - Analyze coverage\n- `moon test --filter 'globl'` - Run tests matching filter\n  ```\n  moon test float/float_test.mbt --filter \"Float::*\"\n  ```\n## `README.mbt.md` Generation Guide\n\n- Output `README.mbt.md` in the package directory. \n  `*.mbt.md` file and docstring contents treats `mbt check` specially.\n  `mbt check` block will be included directly as code and also run by `moon check` and `moon test`.  If you don't want the code snippets to be checked, explicit `mbt nocheck` is preferred.\n  If you are only referencing types from the package, you should use `mbt nocheck` which will only be syntax highlighted.\n  Symlink `README.mbt.md` to `README.md` to adapt to systems that expect `README.md`. \n    \n## Testing Guide\n\nUse snapshot tests as it is easy to update when behavior changes.\n\n- **Snapshot Tests**: `inspect(value, content=\"...\")`. If unknown, write `inspect(value)` and run `moon test --update` (or `moon test -u`).\n  - Use regular `inspect()` for simple values (uses `Show` trait)\n  - Use `@json.inspect()` for complex nested structures (uses `ToJson` trait, produces more readable output)\n  - It is encouraged to `inspect` or `@json.inspect` the whole return value of a function if\n    the whole return value is not huge, this makes test simple. You need `impl (Show|ToJson) for YourType` or `derive (Show, ToJson)`.\n- **Update workflow**: After changing code that affects output, run `moon test --update` to regenerate snapshots, then review the diffs in your test files (the `content=` parameter will be updated automatically).\n\n- Black-box by default: Call only public APIs via `@package.fn`. Use white-box tests only when private members matter.\n- Grouping: Combine related checks in one `test \"...\" { ... }` block for speed and clarity.\n- Panics: Name test with prefix `test \"panic ...\" {...}`; if the call returns a value, wrap it with `ignore(...)` to silence warnings.\n- Errors: Use `try? f()` to get `Result[...]` and `inspect` it when a function may raise.\n- Verify: Run `moon test` (or `-u` to update snapshots) and `moon fmt` afterwards.\n\n### Docstring tests \n\nPublic APIs are encouraged to have docstring tests.\n````mbt check\n///|\n/// Get the largest element of a non-empty `Array`.\n///\n/// # Example\n/// ```mbt check\n/// test {\n///   inspect(sum_array([1, 2, 3, 4, 5, 6]), content=\"21\")\n/// }\n/// ```\n///\n/// # Panics\n/// Panics if the `xs` is empty.\npub fn sum_array(xs : Array[Int]) -> Int {\n  xs.fold(init=0, (a, b) => a + b)\n}\n````\n\nThe MoonBit code in docstring will be type checked and tested automatically.\n(using `moon test --update`). In docstrings, `mbt check` should only contain `test` or `async test`.\n\n## Spec-driven Development\n\n- The spec can be written in a readonly `spec.mbt` file (name is conventional, not mandatory) with stub code marked as declarations:\n\n```mbt check\n///|\n#declaration_only\npub type Yaml\n\n///|\n#declaration_only\npub fn Yaml::to_string(y : Yaml) -> String raise {\n  ...\n}\n\n///|\n#declaration_only\npub fn parse_yaml(s : String) -> Yaml raise {\n  ...\n}\n```\n\n- Add `spec_easy_test.mbt`, `spec_difficult_test.mbt` etc to test the spec functions; everything will be type-checked(`moon check`).\n- The AI or students can implement the `declaration_only` functions in different files thanks to our package organization.\n- Run `moon test` to check everything is correct.\n\n- `#declaration_only` is supported for functions, methods, and types.\n- The `pub type Yaml` line is an intentionally opaque placeholder; the implementer chooses its representation.\n- Note the spec file can also contain normal code, not just declarations.\n\n## `moon doc` for API Discovery\n\n**CRITICAL**: `moon doc '<query>'` is your PRIMARY tool for discovering available APIs, functions, types, and methods in MoonBit. Always prefer `moon doc` over other approaches when exploring what APIs are available, it is **more powerful and accurate** than `grep_search` or any regex-based searching tools. \n\n\n`moon doc` uses a specialized query syntax designed for symbol lookup:\n- **Empty query**: `moon doc ''`\n\n  - In a module: shows all available packages in current module, including dependencies and moonbitlang/core\n  - In a package: shows all symbols in current package\n  - Outside package: shows all available packages\n\n- **Function/value lookup**: `moon doc \"[@pkg.]value_or_function_name\"`\n  \n- **Type lookup**: `moon doc \"[@pkg.]Type_name\"` (builtin type does not need package prefix)\n\n- **Method/field lookup**: `moon doc \"[@pkg.]Type_name::method_or_field_name\"`\n\n- **Package exploration**: `moon doc \"@pkg\"`\n  - Show package `pkg` and list all its exported symbols\n  - Example: `moon doc \"@json\"` - explore entire `@json` package\n  - Example: `moon doc \"@encoding/utf8\"` - explore nested package\n\n- **Globbing**: Use `*` wildcard for partial matches, e.g. `moon doc \"String::*rev*\"` to find all String methods with \"rev\" in their name\n\n### `moon doc` Examples\n\n````bash\n# search for String methods in standard library:\n$ moon doc \"String\"\n\ntype String\n\n  pub fn String::add(String, String) -> String\n  # ... more methods omitted ...\n\n$ moon doc \"@buffer\" # list all symbols in  package buffer:\nmoonbitlang/core/buffer\n\nfn from_array(ArrayView[Byte]) -> Buffer\n# ... omitted ...\n\n$ moon doc \"@buffer.new\" # list the specific function in a package:\npackage \"moonbitlang/core/buffer\"\n\npub fn new(size_hint? : Int) -> Buffer\n  Creates ... omitted ...\n\n\n$ moon doc \"String::*rev*\"  # globbing\npackage \"moonbitlang/core/string\"\n\npub fn String::rev(String) -> String\n  Returns ... omitted ...\n  # ... more\n\npub fn String::rev_find(String, StringView) -> Int?\n  Returns ... omitted ...\n````\n**Best practice**: When implementing a feature, start with `moon doc` queries to discover available APIs before writing code. This is faster and more accurate than searching through files.\n\n## `moon ide [peek-def|outline|find-references]` for code navigation and refactoring\n\nFor project-local symbols and navigation, use `moon ide outline .` to scan a package, `moon ide find-references <symbol>` to locate usages, and `moon ide peek-def` for inline definition context and locate toplevel symbols. \n\nThese tools save tokens and more precise than grepping(grep display results in both definition and call site including comments too).\n\n### `moon ide peek-def sym [-loc filename:line:col]` example\n\nWhen the user ask: Can you check if `Parser::read_u32_leb128` is implemented correctly?\n\nIn this case, You can run `moon ide peek-def Parser::read_u32_leb128` to get the definition context: (this is better than `grep` since it searches the whole project by semantics)\n\n``` file src/parse.mbt\nL45:|///|\nL46:|fn Parser::read_u32_leb128(self : Parser) -> UInt raise ParseError {\nL47:|  ...\n...:| }\n```\nNow you want to see the definition of `Parser` struct, you can run:\n\n```bash\n$ moon ide peek-def Parser -loc src/parse.mbt:46:4\nDefinition found at file src/parse.mbt\n  | ///|\n2 | priv struct Parser {\n  |             ^^^^^^\n  |   bytes : Bytes\n  |   mut pos : Int\n  | }  \n  | \n```\nFor the `-loc` argument, the line number must be precise; the column can be approximate since \nthe positonal argument `Parser` helps locate the position.\n\nIf the sym is toplevel symbol, the location can be omitted:\n````bash\n$ moon ide peek-def String::rev\nFound 1 symbols matching 'String::rev':\n\n`pub fn String::rev` in package moonbitlang/core/builtin at /Users/usrname/.moon/lib/core/builtin/string_methods.mbt:1039-1044\n1039 | ///|\n     | /// Returns a new string with the characters in reverse order. It respects\n     | /// Unicode characters and surrogate pairs but not grapheme clusters.\n     | pub fn String::rev(self : String) -> String {\n     |   self[:].rev()\n     | }         \n````\n\n### `moon ide outline [dir|file]` and `moon ide find-references <sym>` for Package Symbols\n\nUse this to scan a package or file for top-level symbols and locate usages without grepping\n\n- `moon ide outline dir` outlines the current package directory (per-file headers)\n- `moon ide outline parser.mbt` outlines a single file\n- Useful when you need a quick inventory of a package, or to find the right file before `goto-definition`\n- `moon ide find-references TranslationUnit` finds all references to a symbol in the current module\n\n```bash\n$ moon ide outline .\nspec.mbt:\n L003 | pub(all) enum CStandard {\n        ...\n L013 | pub(all) struct Position {\n        ...\n```\n\n```bash\n$ moon ide find-references TranslationUnit\n```\n\n## Package Management\n\n### Adding Dependencies\n\n```sh\nmoon add moonbitlang/x        # Add latest version\nmoon add moonbitlang/x@0.4.6  # Add specific version\n```\n\n### Updating Dependencies\n\n```sh\nmoon update                   # Update package index\n```\n\n### Typical Module configurations (`moon.mod.json`)\n\n```json\n{\n  \"name\": \"username/hello\", // Required format for published modules\n  \"version\": \"0.1.0\",\n  \"source\": \".\", // Source directory(optional, default: \".\")\n  \"repository\": \"\", // Git repository URL\n  \"keywords\": [], // Search keywords\n  \"description\": \"...\", // Module description\n  \"deps\": {\n    // Dependencies from mooncakes.io, using`moon add` to add dependencies\n    \"moonbitlang/x\": \"0.4.6\"\n  }\n}\n```\n\n### Typical Package configuration (`moon.pkg.json`)\n\n```json\n{\n  \"is_main\": true,                 // Creates executable when true\n  \"import\": [                      // Package dependencies\n    \"username/hello/liba\",         // Simple import, use @liba.foo() to call functions\n    {\n      \"path\": \"moonbitlang/x/encoding\",\n      \"alias\": \"libb\"              // Custom alias, use @libb.encode() to call functions\n    }\n  ],\n  \"test-import\": [...],            // Imports for black-box tests, similar to import\n  \"wbtest-import\": [...]           // Imports for white-box tests, similar to import (rarely used)\n}\n```\n\nPackages per directory, packages without `moon.pkg.json` are not recognized.\n\n### Package Importing (used in moon.pkg.json)\n\n- **Import format**: `\"module_name/package_path\"`\n- **Usage**: `@alias.function()` to call imported functions\n- **Default alias**: Last part of path (e.g., `liba` for `username/hello/liba`)\n- **Package reference**: Use `@packagename` in test files to reference the\n  tested package\n\n**Package Alias Rules**:\n\n- Import `\"username/hello/liba\"` → use `@liba.function()` (default alias is last path segment)\n- Import with custom alias `{\"path\": \"moonbitlang/x/encoding\", \"alias\": \"enc\"}` → use `@enc.function()`\n- In `_test.mbt` or `_wbtest.mbt` files, the package being tested is auto-imported\n\nExample:\n\n```mbt\n///|\n/// In main.mbt after importing \"username/hello/liba\" in `moon.pkg.json`\nfn main {\n  println(@liba.hello()) // Calls hello() from liba package\n}\n```\n\n### Using Standard Library (moonbitlang/core)\n\n**MoonBit standard library (moonbitlang/core) packages are automatically imported** - DO NOT add them to dependencies:\n\n- ❌ **DO NOT** use `moon add` to add standard library packages like `moonbitlang/core/strconv`\n- ❌ **DO NOT** add standard library packages to `\"deps\"` field of `moon.mod.json`\n- ❌ **DO NOT** add standard library packages to `\"import\"` field of `moon.pkg.json`\n- ✅ **DO** use them directly: `@strconv.parse_int()`, `@list.List`, `@array.fold()`, etc.\n\nIf you get an error like \"cannot import `moonbitlang/core/strconv`\", remove it from imports - it's automatically available.\n\n### Creating Packages\n\nTo add a new package `fib` under `.`:\n\n1. Create directory: `./fib/`\n2. Add `./fib/moon.pkg.json`: `{}` -- Minimal valid moon.pkg.json\n3. Add `.mbt` files with your code\n4. Import in dependent packages:\n\n   ```json\n   {\n     \"import\": [\n        \"username/hello/fib\",\n        ...\n     ]\n   }\n   ```\nFor more advanced topics like `conditional compilation`, `link configuration`, `warning control`, and `pre-build commands`, see `references/advanced-moonbit-build.md`.\n\n# MoonBit Language Tour\n\n## Core facts\n\n- **Expression‑oriented**: `if`, `match`, loops return values; last expression is the return.\n- **References by default**: Arrays/Maps/structs mutate via reference; use `Ref[T]` for primitive mutability.\n- **Blocks**: Separate top‑level items with `///|`. Generate code block‑by‑block.\n- **Visibility**: `fn` private by default; `pub` exposes read/construct as allowed; `pub(all)` allows external construction.\n- **Naming convention**: lower_snake for values/functions; UpperCamel for types/enums; enum variants start UpperCamel.\n- **Packages**: No `import` in code files; call via `@alias.fn`. Configure imports in `moon.pkg.json`.\n- **Placeholders**: `...` is a valid placeholder in MoonBit code for incomplete implementations.\n- **Global values**: immutable by default and generally require type annotations.\n- **Garbage collection**: MoonBit has a GC, there is no lifetime annotation, there's no ownership system.\n  Unlike Rust, like F#, `let mut` is only needed when you want to reassign a variable, not for mutating fields of a struct or elements of an array/map.\n- **Delimit top-level items with `///|` comments** so tools can split the file reliably.\n\n## MoonBit Error Handling (Checked Errors)\n\nMoonBit uses checked error-throwing functions, not unchecked exceptions. All errors are subtype of `Error`, we can declare our own error types by `suberror`.\nUse `raise` in signatures to declare error types and let errors propagate by\ndefault. Use `try?` to convert to `Result[...]` in tests, or `try { } catch { }`\nto handle errors explicitly.\n\n```mbt check\n///|\n/// Declare error types with 'suberror'\nsuberror ValueError String\n\n///|\n/// Tuple struct to hold position info\nstruct Position(Int, Int) derive(ToJson, Show, Eq) \n\n///|\n/// ParseError is subtype of Error\npub(all) suberror ParseError {\n  InvalidChar(pos~:Position, Char) // pos is labeled\n  InvalidEof(pos~:Position)\n  InvalidNumber(pos~:Position, String)\n  InvalidIdentEscape(pos~:Position)\n} derive(Eq, ToJson, Show)\n\n///|\n/// Functions declare what they can throw\nfn parse_int(s : String, position~ : Position) -> Int raise ParseError {\n  // 'raise' throws an error\n  if s is \"\" {\n    raise ParseError::InvalidEof(pos=position)\n  }\n  ... // parsing logic\n}\n\n///|\n/// Just declare `raise` to not track specific error types\nfn div(x : Int, y : Int) -> Int raise {\n  if y is 0 {\n    fail(\"Division by zero\")\n  }\n  x / y\n}\n\n///|\ntest \"inspect raise function\" {\n  let result : Result[Int, Error] = try? div(1, 0) \n  guard result is Err(Failure(msg)) && msg.contains(\"Division by zero\") else {\n    fail(\"Expected error\")\n  }  \n}\n\n// Three ways to handle errors:\n\n///|\n/// Propagate automatically\nfn use_parse(position~: Position) -> Int raise ParseError {\n  let x = parse_int(\"123\", position=position)\n  // Error auto-propagates by default.\n  // Unlike Swift, you do not need to mark `try` for functions that can raise\n  // errors; the compiler infers it automatically. This keeps error handling\n  // explicit but concise.\n  x * 2\n}\n\n///|\n/// Mark `raise` for all possible errors, do not care which error it is.\n/// For quick prototypes, `raise` is acceptable.\nfn use_parse2(position~: Position) -> Int raise {\n  let x = parse_int(\"123\", position=position)\n  x * 2\n}\n\n///|\n/// Convert to Result with try?\nfn safe_parse(s : String, position~: Position) -> Result[Int, ParseError] {\n  let val1 : Result[_] = try? parse_int(s, position=position) // Returns Result[Int, ParseError]\n  // try! is rarely used - it panics on error, similar to unwrap() in Rust\n  // let val2 : Int = try! parse_int(s) // Returns Int otherwise crash\n\n  // Alternative explicit handling:\n  let val3 = try parse_int(s, position=position) catch {\n    err => Err(err)\n  } noraise { // noraise block is optional - handles the success case\n    v => Ok(v)\n  }\n  ...\n}\n\n///|\n/// Handle with try-catch\nfn handle_parse(s : String, position~: Position) -> Int {\n  try parse_int(s, position=position) catch {\n    ParseError::InvalidEof => {\n      println(\"Parse failed: InvalidEof\")\n      -1 // Default value\n    }\n    _ => 2\n  }\n}\n```\n\nImportant: When calling a function that can raise errors, if you only want to\npropagate the error, you do not need any marker; the compiler infers it.\n\n## Integers, Char\n\nMoonBit supports Byte, Int16, Int, UInt16, UInt, Int64, UInt64, etc. When the type is known,\nthe literal can be overloaded:\n\n```mbt check\n///|\ntest \"integer and char literal overloading disambiguation via type in the current context\" {\n  let a0 = 1 // a is Int by default\n  let (int, uint, uint16, int64, byte) : (Int, UInt, UInt16, Int64, Byte) = (\n    1, 1, 1, 1, 1,\n  )\n  assert_eq(int, uint16.to_int())\n  let a1 : Int = 'b' // this also works, a5 will be the unicode value\n  let a2 : Char = 'b'\n}\n```\n## Bytes (Immutable)\n\n```mbt check\n///|\ntest \"bytes literals overloading and indexing\" {\n  let b0 : Bytes = b\"abcd\"\n  let b1 : Bytes = \"abcd\" // b\" prefix is optional, when we know the type\n  let b2 : Bytes = [0xff, 0x00, 0x01] // Array literal overloading\n  guard b0 is [b'a', ..] && b0[1] is b'b' else {\n    // Bytes can be pattern matched as BytesView and indexed\n    fail(\"unexpected bytes content\")\n  }\n  \n}\n```\n## Array (Resizable)\n\n```mbt check\n///|\ntest \"array literals overloading: disambiguation via type in the current context\" {\n  let a0 : Array[Int] = [1, 2, 3] // resizable\n  let a1 : FixedArray[Int] = [1, 2, 3] // Fixed size\n  let a2 : ReadOnlyArray[Int] = [1, 2, 3] \n  let a3 : ArrayView[Int] = [1, 2, 3]\n}\n```\n## String (Immutable UTF-16)\n`s[i]` returns a code unit (UInt16), `s.get_char(i)` returns `Char?`.\nSince MoonBit supports char literal overloading, you can write code snippets like this:\n\n```mbt check\n///|\ntest \"string indexing and utf8 encode/decode\" {\n  let s = \"hello world\"\n  let b0 : UInt16 = s[0]\n  guard(b0 is ('\\n' | 'h' | 'b' | 'a'..='z') && s is [..\"hello\", ..rest]) else {\n    fail(\"unexpected string content\")\n  }\n  guard rest is \" world\" // otherwise will crash (guard without else)\n  \n  // In check mode (expression with explicit type), ('\\n' : UInt16) is valid.\n  \n  // Using get_char for Option handling\n  let b1 : Char? = s.get_char(0)\n  assert_true(b1 is Some('a'..='z'))\n\n  // ⚠️ Important: Variables won't work with direct indexing\n  let eq_char : Char = '='\n  // s[0] == eq_char // ❌ Won't compile - eq_char is not a literal, lhs is UInt while rhs is Char\n  // Use: s[0] == '=' or s.get_char(0) == Some(eq_char)\n  let bytes = @encoding/utf8.encode(\"中文\") // utf8 encode package is in stdlib\n  assert_true(bytes is [0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87])\n  let s2 : String = @encoding/utf8.decode(bytes) // decode utf8 bytes back to String\n  assert_true(s2 is \"中文\")\n  for c in \"中文\" {\n    let _ : Char = c // unicode safe iteration  \n    println(\"char: \\{c}\") // iterate over chars\n  }\n}\n```\n\n### String Interpolation && StringBuilder\n\nMoonBit uses `\\{}` for string interpolation, for custom types, it needs implement trait `Show`\n\n```mbt check\n///|\ntest \"string interpolation basics\" {\n\n  let name : String = \"Moon\"\n  let config = { \"cache\": 123 }\n  let version = 1.0\n  println(\"Hello \\{name} v\\{version}\") // \"Hello Moon v1.0\"\n  // ❌ Wrong - quotes inside interpolation not allowed:\n  // println(\"  - Checking if 'cache' section exists: \\{config[\"cache\"]}\")\n\n  // ✅ Correct - extract to variable first:\n  let has_key = config[\"cache\"] // `\"` not allowed in interpolation\n  println(\"  - Checking if 'cache' section exists: \\{has_key}\")\n  \n  let sb = StringBuilder::new()\n  sb..write_char('[') // dotdot for imperative method chaining\n    ..write_view([1,2,3].map((x) => \"\\{x}\").join(\",\"))\n    ..write_char(']')\n  inspect(sb.to_string(), content=\"[1,2,3]\")\n}\n```\n\nExpressions inside `\\{}` can only be _basic expressions_ (no quotes, newlines, or nested interpolations). String literals are not allowed as it makes lexing too difficult.\n\n\n### Multiple line strings\n\n```mbt check\n///|\ntest \"multi-line string literals\" {  \n  let multi_line_string : String =\n    #|Hello \"world\"\n    #|World\n    #|\n  let multi_line_string_with_interp : String =\n    $|Line 1 \"\"\n    $|Line 2 \\{1+2}\n    $|\n  // no escape in `#|`, \n  // only escape '\\{..}` in `$|`\n  assert_eq(multi_line_string, \"Hello \\\"world\\\"\\nWorld\\n\")  \n  assert_eq(multi_line_string_with_interp, \"Line 1 \\\"\\\"\\nLine 2 3\\n\")\n}\n```\n\n## Map (Mutable, Insertion-Order Preserving)\n\n```mbt check\n///|\ntest \"map literals and common operations\" {\n  // Map literal syntax\n  let map : Map[String, Int] = { \"a\": 1, \"b\": 2, \"c\": 3 }  \n  let empty : Map[String, Int] = {} // Empty map, preferred\n  let also_empty : Map[String, Int] = Map::new()\n  // From array of pairs\n  let from_pairs : Map[String, Int] = Map::from_array([(\"x\", 1), (\"y\", 2)])\n\n  // Set/update value\n  map[\"new-key\"] = 3\n  map[\"a\"] = 10 // Updates existing key\n\n  // Get value - returns Option[T]\n  guard map is { \"new-key\": 3, \"missing\"? : None, .. } else {\n    fail(\"unexpected map contents\")\n  }\n\n  // Direct access (panics if key missing)\n  let value : Int = map[\"a\"] // value = 10\n\n  // Iteration preserves insertion order\n  for k, v in map {\n    println(\"\\{k}: \\{v}\") // Prints: a: 10, b: 2, c: 3, new-key: 3\n  }\n\n  // Other common operations\n  map.remove(\"b\")\n  guard map is { \"a\": 10, \"c\": 3, \"new-key\": 3, .. } && map.length() == 3 else {\n    // \"b\" is gone, only 3 elements left  \n    fail(\"unexpected map contents after removal\")\n  }\n}\n```\n\n## View Types\n\n**Key Concept**: View types (`StringView`, `BytesView`, `ArrayView[T]`) are zero-copy, non-owning read-only slices created with the `[:]` syntax. They don't allocate memory and are ideal for passing sub-sequences without copying data, for function which takes String, Bytes, Array, they also take *View(implicit conversion).\n\n- `String` → `StringView` via `s[:]` or `s[start:end]`\n- `Bytes` → `BytesView` via `b[:]` or `b[start:end]`\n- `Array[T]`, `FixedArray[T]`, `ReadOnlyArray[T] → `ArrayView[T]` via `a[:]` or `a[start:end]`\n\n**Important**: StringView slice is slightly different due to unicode safety:\n`s[a:b]` may raise an error at surrogate boundaries (UTF-16 encoding edge case). You have two options:\n\n- Use `try! s[a:b]` if you're certain the boundaries are valid (crashes on invalid boundaries)\n- Let the error propagate to the caller for proper handling\n\n**When to use views**:\n\n- Pattern matching with rest patterns (`[first, .. rest]`)\n- Passing slices to functions without allocation overhead\n- Avoiding unnecessary copies of large sequences\n\nConvert back with `.to_string()`, `.to_bytes()`, or `.to_array()` when you need ownership. (`moon doc StringView`)\n\n## User defined types(`enum`, `struct`)\n\n```mbt check\n///|\nenum Tree[T] {\n  Leaf(T) // Unlike Rust, no comma here\n  Node(left~ : Tree[T], T, right~ : Tree[T]) // enum can use labels\n} derive(Show, ToJson) // derive traits for Tree\n\n///|\npub fn Tree::sum(tree : Tree[Int]) -> Int {\n  match tree {\n    Leaf(x) => x \n    // we don't need to write Tree::Leaf, when `tree` has a known type\n    Node(left~, x, right~) => left.sum() + x + right.sum() // method invoked in dot notation\n  }\n}\n\n///|\nstruct Point {\n  x : Int\n  y : Int\n} derive(Show, ToJson) // derive traits for Point\n\ntest \"user defined types: enum and struct\" {\n  @json.inspect(Point::{ x: 10, y: 20 }, content=({\"x\":10,\"y\":20}))\n}\n\n```\n\n## Functional `for` loop\n\n\n```mbt check\npub fn binary_search(\n  arr : ArrayView[Int],\n  value : Int,\n) -> Result[Int, Int] {\n  let len = arr.length()\n  // functional for loop:\n  // initial state ; [predicate] ; [post-update] {\n  // loop body with `continue` to update state\n  //} else { // exit block\n  // }\n  // predicate and post-update are optional\n  for i = 0, j = len; i < j; {\n    // post-update is omitted, we use `continue` to update state\n    let h = i + (j - i) / 2\n    if arr[h] < value {\n      continue h + 1, j // functional update of loop state\n    } else {\n      continue i, h // functional update of loop state\n    }\n  } else { // exit of for loop\n    if i < len && arr[i] == value {\n      Ok(i)\n    } else {\n      Err(i)\n    }\n  } where {\n    invariant : 0 <= i && i <= j && j <= len,\n    invariant : i == 0 || arr[i - 1] < value,\n    invariant : j == len || arr[j] >= value,\n    reasoning :\n      #|For a sorted array, the boundary invariants are witnesses:\n      #|  - `arr[i-1] < value` implies all arr[0..i) < value (by sortedness)\n      #|  - `arr[j] >= value` implies all arr[j..len) >= value (by sortedness)\n      #|\n      #|Preservation proof:\n      #|  - When arr[h] < value: new_i = h+1, and arr[new_i - 1] = arr[h] < value ✓\n      #|  - When arr[h] >= value: new_j = h, and arr[new_j] = arr[h] >= value ✓\n      #|\n      #|Termination: j - i decreases each iteration (h is strictly between i and j)\n      #|\n      #|Correctness at exit (i == j):\n      #|  - By invariants: arr[0..i) < value and arr[i..len) >= value\n      #|  - So if value exists, it can only be at index i\n      #|  - If arr[i] != value, then value is absent and i is the insertion point\n      #|\n  }\n}\n\n///|\ntest \"functional for loop control flow\" {\n  let arr : Array[Int] = [1, 3, 5, 7, 9]\n  inspect(binary_search(arr,5), content=\"Ok(2)\") // Array to ArrayView implicit conversion when passing as arguments\n  inspect(binary_search(arr,6), content=\"Err(3)\")\n  // for iteration is supported too\n  for i, v in arr {\n    println(\"\\{i}: \\{v}\") // `i` is index, `v` is value\n  }\n}\n```\nYou are *STRONGLY ENCOURAGED* to use functional `for` loops instead of imperative loops\n*WHENEVER POSSIBLE*, as they are easier to reason about.\n\n### Loop Invariants with `where` Clause\n\nThe `where` clause attaches **machine-checkable invariants** and **human-readable reasoning** to functional `for` loops. This enables formal verification thinking while keeping the code executable. Note for trivial loops, you are encouraged to convert it into `for .. in` so no reasoning is needed.\n\n**Syntax:**\n```mbt nocheck\nfor ... {\n  ...\n} where {\n  invariant : <boolean_expr>,   // checked at runtime in debug builds\n  invariant : <boolean_expr>,   // multiple invariants allowed\n  reasoning : <string>         // documentation for proof sketch\n}\n```\n\n**Writing Good Invariants:**\n\n1. **Make them checkable**: Invariants must be valid MoonBit boolean expressions using loop variables and captured values.\n\n2. **Use boundary witnesses**: For properties over ranges (e.g., \"all elements in arr[0..i) satisfy P\"), check only boundary elements. For sorted arrays, `arr[i-1] < value` implies all `arr[0..i) < value`.\n\n3. **Handle edge cases with `||`**: Use patterns like `i == 0 || arr[i-1] < value` to handle boundary conditions where the check would be out of bounds.\n\n4. **Cover three aspects in reasoning**:\n   - **Preservation**: Why each `continue` maintains the invariants\n   - **Termination**: Why the loop eventually exits (e.g., a decreasing measure)\n   - **Correctness**: Why the invariants at exit imply the desired postcondition\n\n## Label and Optional Parameters\n\nGood example: use labeled and optional parameters\n\n```mbt check\n///|\nfn g(\n  positional : Int,\n  required~ : Int,\n  optional? : Int, // no default => Option\n  optional_with_default? : Int = 42, // default => plain Int\n) -> String {\n  // These are the inferred types inside the function body.\n  let _ : Int = positional\n  let _ : Int = required\n  let _ : Int? = optional\n  let _ : Int = optional_with_default\n  \"\\{positional},\\{required},\\{optional},\\{optional_with_default}\"\n}\n\n///|\ntest {\n  inspect(g(1, required=2), content=\"1,2,None,42\")\n  inspect(g(1, required=2, optional=3), content=\"1,2,Some(3),42\")\n  inspect(g(1, required=4, optional_with_default=100), content=\"1,4,None,100\")\n}\n```\n\nMisuse: `arg : Type?` is not an optional parameter.\nCallers still must pass it (as `None`/`Some(...)`).\n\n```mbt check\n///|\nfn with_config(a : Int?, b : Int?, c : Int) -> String {\n  \"\\{a},\\{b},\\{c}\"\n}\n\n///|\ntest {\n  inspect(with_config(None, None, 1), content=\"None,None,1\")\n  inspect(with_config(Some(5), Some(5), 1), content=\"Some(5),Some(5),1\")\n}\n```\n\nAnti-pattern: `arg? : Type?` (no default => double Option).\nIf you want a defaulted optional parameter, write `b? : Int = 1`, not `b? : Int? = Some(1)`.\n\n```mbt check\n///|\nfn f_misuse(a? : Int?, b? : Int = 1) -> Unit {\n  let _ : Int?? = a // rarely intended\n  let _ : Int = b\n\n}\n// How to fix: declare `(a? : Int, b? : Int = 1)` directly.\n\n///|\nfn f_correct(a? : Int, b? : Int = 1) -> Unit {\n  let _ : Int? = a\n  let _ : Int = b\n\n}\n\n///|\ntest {\n  f_misuse(b=3)\n  f_misuse(a=Some(5), b=2) // works but confusing\n  f_correct(b=2)\n  f_correct(a=5)\n}\n```\n\nBad example: `arg : APIOptions` (use labeled optional parameters instead)\n\n```mbt check\n///|\n/// Do not use struct to group options.\nstruct APIOptions {\n  width : Int?\n  height : Int?\n}\n\n///|\nfn not_idiomatic(opts : APIOptions, arg : Int) -> Unit {\n\n}\n\n///|\ntest {\n  // Hard to use in call site\n  not_idiomatic({ width : Some(5), height : None }, 10)\n  not_idiomatic({ width : None, height : None }, 10)\n}\n```\n\n## More details\n\nFor deeper syntax, types, and examples, read `references/moonbit-language-fundamentals.mbt.md`.\n\n<!-- File: packages/fractional-index/README.md (Tokens: ~2101 | Category: plugin-manifest) -->\n# @loro-dev/fractional-index\n\nTypeScript implementation of Loro's Rust `loro_fractional_index` crate.\n\nThis package creates compact string positions that sort lexicographically. The\npublic API always accepts and returns canonical uppercase hex strings, so indexes\nare easy to store, compare, serialize, and use as object or map keys.\n\n- No runtime dependencies.\n- ESM output with TypeScript declarations.\n- Public indexes are plain strings.\n- Generated strings are byte-for-byte compatible with the Rust crate's\n  `Display` output.\n- Golden tests are generated from the Rust implementation in this repository.\n\n## Install\n\n```sh\npnpm add @loro-dev/fractional-index\n```\n\n```sh\nnpm install @loro-dev/fractional-index\n```\n\n```sh\nyarn add @loro-dev/fractional-index\n```\n\n## Quick Start\n\n```ts\nimport { FractionalIndex, compare } from \"@loro-dev/fractional-index\";\n\nconst first = FractionalIndex.default();\nconst before = FractionalIndex.newBefore(first);\nconst after = FractionalIndex.newAfter(first);\nconst middle = FractionalIndex.newBetween(first, after);\n\nconsole.log(first); // \"80\"\nconsole.log(before); // \"7F80\"\nconsole.log(after); // \"8180\"\nconsole.log(middle); // \"817F80\"\n\nconst ordered = [after, first, before].sort(compare);\nconsole.log(ordered); // [\"7F80\", \"80\", \"8180\"]\n\nJSON.stringify({ position: first }); // \"{\\\"position\\\":\\\"80\\\"}\"\n```\n\nGenerated indexes are canonical uppercase hex strings. For generated values,\nordinary string comparison also follows byte order:\n\n```ts\nbefore < first; // true\nfirst < after; // true\n```\n\nUse `compare(a, b)` when sorting values that may have been parsed from external\ninput, because it compares by bytes after parsing.\n\n## Data Model\n\nAn index string is the uppercase hex encoding of the same bytes used by Rust.\nGenerated indexes include the `0x80` terminator byte.\n\n```ts\nconst index = FractionalIndex.default(); // \"80\"\n```\n\nThe public API does not expose byte arrays. Internally, the implementation still\nuses bytes to stay aligned with the Rust algorithm.\n\n## Creating Indexes\n\n### Default\n\n```ts\nconst index = FractionalIndex.default(); // \"80\"\n```\n\nThis matches `FractionalIndex::default()` in Rust.\n\n### Before And After\n\n```ts\nconst base = FractionalIndex.default();\n\nconst before = FractionalIndex.newBefore(base); // \"7F80\"\nconst after = FractionalIndex.newAfter(base); // \"8180\"\n```\n\n### Between Two Indexes\n\n```ts\nconst left = FractionalIndex.default();\nconst right = FractionalIndex.newAfter(left);\nconst between = FractionalIndex.newBetween(left, right);\n\nif (between) {\n  console.log(left < between); // true for canonical generated strings\n  console.log(between < right); // true\n}\n```\n\n`newBetween()` returns `undefined` when the Rust crate would return `None`.\nFor byte sequences that trigger a Rust panic, this package throws an `Error`\ninstead of returning a misleading value.\n\n### General Constructor\n\n`FractionalIndex.new(lower, upper)` mirrors Rust's `FractionalIndex::new`:\n\n```ts\nFractionalIndex.new(undefined, undefined); // default \"80\"\nFractionalIndex.new(existing, undefined); // after existing\nFractionalIndex.new(undefined, existing); // before existing\nFractionalIndex.new(left, right); // between left and right\n```\n\n`null` and `undefined` are both treated as an absent bound.\n\n## Generating Many Indexes\n\nUse `generateNEvenly()` when you know how many positions you need. It produces\nstrictly sorted indexes inside the open interval `(lower, upper)`.\n\n```ts\nconst values = FractionalIndex.generateNEvenly(undefined, undefined, 5);\n\nconsole.log(values);\n// [\"7E80\", \"7F80\", \"80\", \"817F80\", \"8180\"]\n```\n\nBounded generation:\n\n```ts\nconst lower = FractionalIndex.newBefore(FractionalIndex.default());\nconst upper = FractionalIndex.newAfter(FractionalIndex.default());\n\nconst values = FractionalIndex.generateNEvenly(lower, upper, 100);\n```\n\nThe method returns `undefined` if both bounds are provided and `lower >= upper`.\n\n## Jitter\n\nThe Rust crate can append random bytes after the terminator. This package exposes\nthe same behavior through `JitterOptions`.\n\n```ts\nconst index = FractionalIndex.jitterDefault({ jitter: 3 });\nconsole.log(index.length); // 8 hex chars: 0x80 plus 3 random bytes\n```\n\nFor deterministic tests or replicated fixtures, provide `randomByte`:\n\n```ts\nconst bytes = [1, 2, 3];\nlet offset = 0;\n\nconst index = FractionalIndex.jitterDefault({\n  jitter: 3,\n  randomByte: () => bytes[offset++],\n});\n\nconsole.log(index); // \"80010203\"\n```\n\nJitter variants:\n\n```ts\nFractionalIndex.jitterDefault({ jitter: 2 });\nFractionalIndex.newJitter(lower, upper, { jitter: 2 });\nFractionalIndex.newBeforeJitter(index, { jitter: 2 });\nFractionalIndex.newAfterJitter(index, { jitter: 2 });\nFractionalIndex.newBetweenJitter(left, right, { jitter: 2 });\nFractionalIndex.generateNEvenlyJitter(lower, upper, 10, { jitter: 2 });\n```\n\n`jitter` and `randomByte` must both be integers in `[0, 255]`, matching Rust's\n`u8` boundary.\n\n## Parsing And Serialization\n\n```ts\nconst fromHex = FractionalIndex.fromHexString(\"80ff\");\nconsole.log(fromHex); // \"80FF\"\n```\n\nCompatibility notes:\n\n- `fromHexString()` accepts uppercase or lowercase hex and returns canonical\n  uppercase hex.\n- Like Rust, `fromHexString()` ignores a trailing odd nibble. `\"80A\"` parses as\n  `\"80\"`.\n- Invalid hex pairs throw `SyntaxError`.\n\n## API Reference\n\n```ts\ntype FractionalIndex = string;\n\ninterface JitterOptions {\n  jitter?: number;\n  randomByte?: () => number;\n}\n```\n\n### Namespace API\n\n```ts\nFractionalIndex.TERMINATOR; // 128\n\nFractionalIndex.default(): FractionalIndex;\nFractionalIndex.fromHexString(hex): FractionalIndex;\n\nFractionalIndex.new(lower?, upper?): FractionalIndex | undefined;\nFractionalIndex.newBefore(index): FractionalIndex;\nFractionalIndex.newAfter(index): FractionalIndex;\nFractionalIndex.newBetween(left, right): FractionalIndex | undefined;\nFractionalIndex.generateNEvenly(lower, upper, n): FractionalIndex[] | undefined;\n\nFractionalIndex.jitterDefault(options?): FractionalIndex;\nFractionalIndex.newJitter(lower, upper, options?): FractionalIndex | undefined;\nFractionalIndex.newBeforeJitter(index, options?): FractionalIndex;\nFractionalIndex.newAfterJitter(index, options?): FractionalIndex;\nFractionalIndex.newBetweenJitter(left, right, options?): FractionalIndex | undefined;\nFractionalIndex.generateNEvenlyJitter(\n  lower,\n  upper,\n  n,\n  options?,\n): FractionalIndex[] | undefined;\n\nFractionalIndex.compare(left, right): number;\nFractionalIndex.equals(left, right): boolean;\nFractionalIndex.isFractionalIndex(value): value is FractionalIndex;\n```\n\n### Top-Level Helpers\n\nNamespace methods are also available as named exports. Since `new` is a\nJavaScript keyword, `FractionalIndex.new()` is exported as `newIndex()`:\n\n```ts\ndefaultIndex();\nfromHexString(hex);\ncompare(left, right);\nequals(left, right);\nnewIndex(lower, upper);\nnewBefore(index);\nnewAfter(index);\nnewBetween(left, right);\ngenerateNEvenly(lower, upper, n);\njitterDefault(options);\nnewJitter(lower, upper, options);\nnewBeforeJitter(index, options);\nnewAfterJitter(index, options);\nnewBetweenJitter(left, right, options);\ngenerateNEvenlyJitter(lower, upper, n, options);\nisFractionalIndex(value);\n```\n\n## Testing Against Rust\n\nThe golden fixture used by the TypeScript tests is generated from the Rust crate:\n\n```sh\npnpm --filter @loro-dev/fractional-index fixtures:generate\npnpm --filter @loro-dev/fractional-index check\n```\n\nThe fixture covers:\n\n- Default, before, after, and between generation.\n- Long before/after chains.\n- `generate_n_evenly` for bounded and unbounded ranges.\n- `None` cases.\n- Rust panic edge cases.\n- Jitter byte placement.\n- Hex serialization.\n\n## Development Commands\n\nThis package uses Vite+ (`vp`) for build, test, lint, and format orchestration.\n\n```sh\npnpm --filter @loro-dev/fractional-index format\npnpm --filter @loro-dev/fractional-index lint\npnpm --filter @loro-dev/fractional-index typecheck\npnpm --filter @loro-dev/fractional-index test\npnpm --filter @loro-dev/fractional-index build\npnpm --filter @loro-dev/fractional-index check\n```\n\n`lint` runs oxlint in type-aware mode with warnings denied. `format` and\n`format:check` use oxfmt. `typecheck` uses `tsgo`. `build` runs `vp pack` and\nemits the ESM bundle, declarations, and sourcemap to `dist/`.\n\n## Performance Notes\n\nString indexes are optimized for JavaScript ergonomics: comparison, JSON,\nstorage, and use as keys are all straightforward. The implementation parses\nstrings to byte arrays internally for generation so it can stay aligned with the\nRust byte algorithm. For the expected workload of normal list/tree positioning,\nthis keeps the API simple without a meaningful practical performance cost.\n</yakaai_skills>"}