miniio

Small, portable WASIp1 I/O SDK for building MoonBit CLI tools and agent skills.

wasi
wasip1
io
cli
agent
moon add moonbit-community/miniio@0.2.1
Download zip
Version
0.2.1
License
Apache-2.0
Last updated
2 months ago
Downloads
27K
README

#miniio

MiniIO is a small, portable WASIp1 I/O SDK for MoonBit command-line tools and agent skills. It gives MoonBit programs a simple way to work with stdin, stdout, stderr, files, directories, arguments, and environment variables while keeping raw preview1 calls internal.

Use it when you want a MoonBit executable that runs cleanly under moon run, wasmtime, or another WASIp1 host without tying your code to host-specific file and terminal APIs.

#ABI compatibility

0.1.0 is compatible with MoonBit < 0.9.3 0.2.0 is compatible with MoonBit >= 0.9.3

#Public API

  • args_get()
  • environ_get()
  • get_env_var(), get_env_vars()
  • moonbit-community/miniio/io::{Data, Reader, Writer}
  • stdin, stdout, stderr
  • open, create
  • File::close
  • File::write_all
  • File::write_text
  • File::seek
  • File::tell
  • Reader::{read, read_exactly, read_some, read_all, read_until}
  • Writer::{write, write_reader}
  • mkdir, remove_file, remove, rmdir
  • readdir
  • exists, kind, is_dir, is_file
  • read_file, write_file, copy_file
  • read_text_file, write_text_file
  • read_json_file, write_json_file
  • Errno, CreateMode, FileKind, Mode, SeekFrom

After importing moonbit-community/miniio/io, File also implements Reader and Writer, so partial reads and streamed writes are available without exposing raw preview1 calls.

#Scope

Internal only:

  • args_sizes_get, args_get
  • environ_sizes_get, environ_get
  • fd_read, fd_write, fd_close, fd_readdir, fd_prestat_*, fd_seek, fd_tell
  • path_open, path_create_directory, path_unlink_file, path_remove_directory
  • preopen discovery and path resolution
  • rights, flags, cookies, raw fd types

Still deliberately omitted:

  • async runtime and async I/O
  • detailed metadata/stat helpers such as mtime, sizes, permissions, and file descriptor rights
  • symlink, rename, link, walk
  • raw preview1-shaped public calls

Use remove_file(path) when the path must be a file, rmdir(path) when it must be a directory, and remove(path) only when accepting either is intentional.

#Common File Patterns

///|
test "copy text between files" {
let dir = "readme_copy_text"
@miniio.remove(dir) catch {
Noent => ()
Notempty => @miniio.rmdir(dir, recursive=true)
e => raise e
}
@miniio.mkdir(dir)
defer (@miniio.rmdir(dir, recursive=true) catch { _ => () })

@miniio.write_text_file(dir + "/input.txt", "hello\n")
@miniio.copy_file(dir + "/input.txt", dir + "/output.txt")
inspect(@miniio.read_text_file(dir + "/output.txt"), content="hello\n")
}

///|
test "append log file" {
let dir = "readme_append_log"
@miniio.remove(dir) catch {
Noent => ()
Notempty => @miniio.rmdir(dir, recursive=true)
e => raise e
}
@miniio.mkdir(dir)
defer (@miniio.rmdir(dir, recursive=true) catch { _ => () })

let path = dir + "/tool.log"
@miniio.write_text_file(path, "start\n")
@miniio.write_text_file(path, "done\n", append=true)
inspect(@miniio.read_text_file(path), content="start\ndone\n")
}

///|
test "read and write json" {
let dir = "readme_json"
@miniio.remove(dir) catch {
Noent => ()
Notempty => @miniio.rmdir(dir, recursive=true)
e => raise e
}
@miniio.mkdir(dir)
defer (@miniio.rmdir(dir, recursive=true) catch { _ => () })

let path = dir + "/manifest.json"
@miniio.write_json_file(path, { "name": "miniio", "portable": true })
inspect(
@miniio.read_json_file(path).stringify(),
content="{\"name\":\"miniio\",\"portable\":true}",
)
}

///|
test "list and remove directories" {
let dir = "readme_list_remove"
@miniio.remove(dir) catch {
Noent => ()
Notempty => @miniio.rmdir(dir, recursive=true)
e => raise e
}
@miniio.mkdir(dir)

@miniio.write_text_file(dir + "/b.txt", "b")
@miniio.write_text_file(dir + "/a.txt", "a")
debug_inspect(
@miniio.readdir(dir, sort=true),
content="[\"a.txt\", \"b.txt\"]",
)

@miniio.rmdir(dir, recursive=true)
inspect(@miniio.exists(dir), content="false")
}

#WASIp1 Guest Paths

WASIp1 paths are guest paths backed by explicit preopened directories. A program that reads data/input.txt needs that guest path to be backed by a host directory.

When using moon run or moon test, Moon's WASI runner is convenient but sandboxed: file access is limited to the working/project directory it runs from. Put development fixtures and temporary test directories under that tree. For host directories outside the current working directory, build the executable and run it with explicit preopens:

wasmtime run --dir ./data::data _build/wasm/debug/build/<module>/<package>.wasm data/input.txt

#Quick Eval

For quick experiments, moon run -c accepts MoonBit's single-file import header, so you can try the API without creating a package:

printf '{"name":"miniio","ok":true}' | moon run -c 'import { "moonbit-community/miniio" @miniio, "moonbit-community/miniio/io", "moonbitlang/core/json" @json, } fn main { try { let input = @miniio.stdin.read_all().text() let value = @json.parse(input) @miniio.stdout.write_text(value.stringify(indent=2) + "\n") } catch { e => { @miniio.stderr.write_text("jq failed: \{e}\n") catch { _ => () } @miniio.exit(1) } } }'

#Examples

The repository root is a Moon workspace. It includes the module itself and separate example projects that use versioned dependencies, not local path dependencies:

  • example/cli_tools: small cat, cp, ls, and tree commands.
  • example/lottie_manifest: reads Lottie JSON with cg-zhou/moon_lottie@0.3.0 and writes a text manifest. The renderer package is not used because it is wasm-gc-oriented.
  • example/morm_query: writes SQL text using the synchronous query-builder surface of oboard/morm@0.3.12. It does not use Morm's async database engine APIs.

Check:

moon check moon test deno task test

The external package examples were validated with a recent Moon toolchain. The Deno tasks prepend $HOME/.moon/bin to PATH so they use that toolchain when it is installed.

Portable executable skill:

  • skills/miniio-portable-wasm: agent guidance and a small template for building WASIp1 executables with moonbit-community/miniio installed through moon add.

Run the demo package:

moon run demo

#
Errno

pub(all) suberror Errno {
Success
TooBig
Acces
Addrinuse
Addrnotavail
Afnosupport
Again
Already
Badf
Badmsg
Busy
Canceled
Child
Connaborted
Connrefused
Connreset
Deadlock
Destaddrreq
Dom
Dquot
Exist
Fault
Fbig
Hostunreach
Idrm
Ilseq
Inprogress
Intr
Inval
IO
Isconn
Isdir
Loop
Mfile
Mlink
Msgsize
Multihop
Nametoolong
Netdown
Netreset
Netunreach
Nfile
Nobufs
Nodev
Noent
Noexec
Nolck
Nolink
Nomem
Nomsg
Noprotoopt
Nospc
Nosys
Notconn
Notdir
Notempty
Notrecoverable
Notsock
Notsup
Notty
Nxio
Overflow
Ownerdead
Perm
Pipe
Proto
Protonosupport
Prototype
Range
Rofs
Spipe
Srch
Stale
Timedout
Txtbsy
Xdev
Notcapable
} derive(Eq,
Debug
)

impl Show for Errno

#
CreateMode

pub(all) enum CreateMode {
OpenExisting
TruncateExisting
OpenOrCreate
CreateOrTruncate
CreateNew
} derive(Eq,
Debug
)

#
File

type File

impl Reader for File
impl Writer for File

#
File::close

fn File::close(self : File) -> Unit raise Errno

#
File::seek

fn File::seek(self : File, offset : Int64, from? : SeekFrom) -> UInt64 raise Errno

#
File::tell

fn File::tell(self : File) -> UInt64 raise Errno

#
File::write_all

fn File::write_all(self : File, data : BytesView) -> Unit raise Errno

#
File::write_text

fn File::write_text(self : File, text : StringView) -> Unit raise Errno

#
FileKind

pub(all) enum FileKind {
Unknown
Regular
Directory
SymLink
Socket
BlockDevice
CharDevice
} derive(Eq,
Debug
)

#
Mode

pub(all) enum Mode {
ReadOnly
WriteOnly
ReadWrite
} derive(Eq,
Debug
)

#
SeekFrom

pub(all) enum SeekFrom {
Start
Current
End
} derive(Eq,
Debug
)

#
args_get

fn args_get() -> Array[String] raise Errno

#
copy_file

fn copy_file(src : StringView, dst : StringView, append? : Bool, create_mode? : CreateMode) -> Unit raise Errno

#
create

fn create(path : StringView) -> File raise Errno

#
environ_get

fn environ_get() -> Array[(String, String)] raise Errno

#
exists

fn exists(path : StringView) -> Bool raise Errno

#
exit

fn exit(code : Int) -> Unit

#
get_env_var

fn get_env_var(key : StringView) -> String? raise Errno

#
get_env_vars

fn get_env_vars() -> Map[String, String] raise Errno

#
is_dir

fn is_dir(path : StringView) -> Bool raise Errno

#
is_file

fn is_file(path : StringView) -> Bool raise Errno

#
kind

fn kind(path : StringView) -> FileKind raise Errno

#
mkdir

fn mkdir(path : StringView) -> Unit raise Errno

#
open

fn open(path : StringView, mode? : Mode, append? : Bool, create_mode? : CreateMode, follow_symlink? : Bool) -> File raise Errno

#
read_file

fn read_file(path : StringView) -> &
Data
raise Errno

#
read_json_file

fn read_json_file(path : StringView) -> Json raise Errno

#
read_text_file

fn read_text_file(path : StringView) -> String raise Errno

#
readdir

fn readdir(path : StringView, include_hidden? : Bool, sort? : Bool, follow_symlink? : Bool) -> Array[String] raise Errno

#
remove

fn remove(path : StringView) -> Unit raise Errno

#
remove_file

fn remove_file(path : StringView) -> Unit raise Errno

#
rmdir

fn rmdir(path : StringView, recursive? : Bool) -> Unit raise Errno

#
stderr

let stderr : File

#
stdin

let stdin : File

#
stdout

let stdout : File

#
write_file

fn write_file(path : StringView, data : &
Data
, append? : Bool, create_mode? : CreateMode) -> Unit raise Errno

#
write_json_file

fn write_json_file(path : StringView, json : Json, append? : Bool, create_mode? : CreateMode) -> Unit raise Errno

#
write_text_file

fn write_text_file(path : StringView, text : StringView, append? : Bool, create_mode? : CreateMode) -> Unit raise Errno

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io