Skip to content
moonbitlangPublic

About

DeepSeek-backed MoonBit coding agent.

Resources

Stars

103 stars

Watchers

4 watching

Forks

Latest commit

 

History

3,286 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

moonbitlang/openseek

OpenSeek is a small MoonBit foundation for an OpenAI-compatible coding agent supporting DeepSeek, Kimi, and Z.AI GLM models. The module is split into pure data, HTTP transport, agent orchestration, and a CLI entry point so request encoding can be tested without network access.

For a picture of how the pieces fit together — module architecture, the core data model, and the life of one agent turn — see docs/architecture.md.

Running without a checkout

openseek-app-server serves the working-host API at ws://127.0.0.1:<port>/host, intended for SSH forwarding. Stdout announces the port, instance ID and protocol version as one JSON line; stdin EOF ends the service. The server uses the openseek executable beside it; OPENSEEK_ENGINE can select an engine for source builds. Clients initialize with that instance ID and protocol version before calling the host API. Browser-origin requests are rejected. Keep the listener and SSH forward bound to loopback.

The root CLI package builds on both native and wasm, and mooncakes.io hosts a prebuilt wasm binary for every published version. moonx fetches and caches it, so the engine runs with no clone and no build:

moonx moonbitlang/openseek --help
DEEPSEEK=sk-... moonx moonbitlang/openseek run --no-session 'summarize this repo'

The root package is the recommended executable entry point. After publishing a version containing this entry point, pin that version with moonbitlang/openseek@<version> or use moonbitlang/openseek@latest. The legacy moonbitlang/openseek/cmd/openseek coordinate remains runnable and prints a deprecation warning to stderr; its arguments, stdout, and exit status are unchanged. Subprocesses, the filesystem, and HTTPS all work under moonrun, so the wasm binary drives the same tools as the native one.

Monorepo development

The root moon.work develops OpenSeek, the desktop modules, and the moonbitlang/editor source together. The editor keeps its smaller editor/moon.work as a scoped entry point for editor-only builds and browser tests; root Moon commands are the integration gate across both projects. The Desktop window host (desktop/app) is the only module that depends on Proton, so it is left out of the root workspace and builds in its own desktop/app/moon.work; root commands therefore need no Proton runtime.

A fresh checkout needs the MoonBit toolchain and just. Recipes use Windows PowerShell on Windows and the default POSIX shell on macOS/Linux. The root integration gates are:

just check              # native + JS workspace checks and formatting
just test               # native + JS workspace tests and OpenSeek cram tests
just build              # native + JS MoonBit builds
just editor-build       # editor web distribution and server
just editor-test        # editor-only tests on every supported target
just editor-test-browser
just desktop-app-check  # Proton window host, in desktop/app/moon.work
just desktop-app-test

The desktop-app-* recipes need Proton's CEF runtime; install it once with just cef-setup.

The CLI lifecycle test (just test-turn-finish, also included in just test) runs as a standalone MoonBit script and needs no Python runtime. When passing editor paths containing spaces, quote the whole assignment: just --justfile editor/justfile "ROOT=C:/Users/me/My Project" dev.

The cram documentation tests (just test-cram, included in just test) use Bash. On Windows, just test selects Git for Windows' Bash at %ProgramFiles%/Git/bin/bash.exe, avoiding the WSL launcher on PATH. For a custom Git installation, set just "CRAM_SHELL=D:/Git/bin/bash.exe" test.

Windows installer packaging (just desktop-package) also needs NSIS with makensis.exe on PATH (usually under C:/Program Files (x86)/NSIS).

The editor browser suites additionally need Node.js 18 or newer, the locked npm dependencies, and a Playwright-managed Chromium installation:

cd editor
npm ci
npx playwright install chromium

Linux hosts that lack Playwright's system dependencies can use the CI form, npx playwright install --with-deps chromium.

Neither editor reference submodule is needed for the normal build, test, or browser smoke gates. Initialize CodeMirror only for source-reference research; initialize VS Code only for the opt-in editor performance suite:

git submodule update --init editor/codemirror # source-reference research
git submodule update --init editor/vscode     # opt-in performance suite

Packages

Package Purpose Docs
moonbitlang/openseek Root CLI entry point and module overview. README.md
moonbitlang/openseek/deepseek Pure chat data, provider-aware JSON encoding, and response decoding. deepseek/README.mbt.md
moonbitlang/openseek/deepseek/client HTTP transport (native or wasm) for supported chat-completions providers. deepseek/client/README.mbt.md
moonbitlang/openseek/agent_runtime Agent task-group (native or wasm) and extensible runtime event queue. agent_runtime/README.mbt.md
moonbitlang/openseek/agent_session Typed durable conversation state and DeepSeek message projection. agent_session/README.mbt.md
moonbitlang/openseek/agent_session/store Native filesystem-backed append-only session store. agent_session/store/README.mbt.md
moonbitlang/openseek/agent_session/log Lenient session-file reader: header plus events, with per-line error capture. —
moonbitlang/openseek/agent_session/compact Context-checkpoint (compaction) request building and summary handling. —
moonbitlang/openseek/agent_tool Tool registry, executor, output, and control-action types; one subpackage per built-in tool. agent_tool/README.mbt.md
moonbitlang/openseek/agent_skill Workspace skills: markdown playbooks discovered from skill libraries and listed in the system prompt. agent_skill/README.mbt.md
moonbitlang/openseek/jsonrpc Duplex JSON-RPC 2.0 client (concurrent requests, notifications, out-of-order replies). —
moonbitlang/openseek/mcp (+ config, stdio, streamhttp, tools) MCP client: mcp.json decoding, stdio and Streamable HTTP transports, and the bridge that namespaces server tools into the registry. —
moonbitlang/openseek/prompt Built-in system prompt text (generated from Markdown) and prompt-selection policy. prompt/README.mbt.md
moonbitlang/openseek_protocol Typed engine event stream (own module): the openseek serve stdout wire contract (openseek run renders it as minimal text), decodable on every backend. protocol/README.mbt.md
moonbitlang/openseek_protocol/emit Writer for that stream (native or wasm): owns each event's log level. protocol/emit/README.mbt.md
moonbitlang/openseek/agent OpenSeek agent loop (native or wasm) and local tool dispatch. agent/README.mbt.md
moonbitlang/openseek/agent_review Read-only, compiler-grounded code-review engine behind the review kind (openseek run --kind review). agent_review/README.mbt.md
moonbitlang/openseek/cmd/openseek Deprecated CLI compatibility entry point; use the root package. cmd/openseek/README.md
moonbitlang/openseek/internal/openseek The CLI's dispatcher and implementation: options (argparse tree), setup (workspace, prompt, session), execution (event sink, approvals, tools, review gate), run, serve, and commands. internal/openseek/README.md
moonbitlang/openseek/cli Shared command-main helpers: the agent options (--api-key, --model, …) and failure-text sanitizer used by openseek and openseek_tui. —
moonbitlang/openseek/viz Browser viewer for durable session logs (JS). viz/README.md
moonbitlang/inspect (in inspect/, own module) HTTP server (native or wasm) that serves the visualizer over recorded sessions. inspect/README.md
moonbitlang/openseek-viz-app (in cmd/viz_app/, own module) JS entry point compiled into the visualizer bundle. viz/README.md
moonbitlang/editor (in editor/, own module) Reusable readonly editor plus its reference browser shell and server. editor/README.md
moonbitlang/openseek/internal/workspace_path Workspace-path resolution shared by the agent tools and the command mains. internal/workspace_path/README.mbt.md
moonbitlang/openseek/testkit/filesystem JSON-backed virtual filesystem for tests and eval fixtures. testkit/filesystem/README.mbt.md
moonbitlang/openseek/eval/report Shared Markdown/JSON report primitive for deterministic and model evals. eval/report/README.mbt.md
moonbitlang/openseek/eval/tool_harness Deterministic host-side harness for file, command, and control tools. eval/tool_harness/README.mbt.md
moonbitlang/openseek/eval/file_edit/cases Deterministic file-editing eval case definitions. eval/file_edit/README.md
moonbitlang/openseek/eval/file_edit/harness Reusable file-editing eval runner, oracle, and reporter. eval/file_edit/README.md
moonbitlang/openseek/eval/file_edit/cmd/main Native-only CLI wrapper for the file-editing eval harness. eval/file_edit/README.md
moonbitlang/openseek/eval/prompt_task/harness Prompt-task eval: runs the real agent over isolated per-trial workspaces. eval/prompt_task/README.md
moonbitlang/openseek/eval/session_analyzer Post-hoc session-log analyzer producing Markdown/HTML/JSON reports. —
openseek_desktop (in desktop/, own module) Desktop app: CEF shell (Proton, a registry dependency) plus a JS frontend driving the engine over JSONL. desktop/README.md

The deepseek subpackage is pure and exposes chat data plus JSON helpers:

  • Model and Role
  • ChatMessage(role, content=[Text(...)]) with strongly typed Role values
  • ToolDefinition(name, description, parameters, strict?) for native tool calls
  • ChatResponse with FromJson response decoding

It has no HTTP dependency and is suitable for blackbox tests and portable request/response handling.

The deepseek/client subpackage exposes the HTTP client:

  • Client(api_key~, model?, api_url?)
  • Client::chat(messages, tools?)

It depends on moonbitlang/async/http and builds on both native and wasm.

The agent_tool package exposes the local tool registry and typed executor boundary. Tool executors return ToolAction: normal tools use Respond(ToolOutput(...)), while control tools such as finish use Control(Finish(...)).

The agent_runtime package owns loop-scoped task-group access and an extensible event queue available to stateful tools.

The agent_session package owns typed durable conversation state, append-only session events, JSON round-tripping, and projection from a session into DeepSeek chat messages. It is separate from TUI transcript rendering so resumable sessions can be type-safe and process-independent. The native agent_session/store package persists those sessions as a small header plus an append-only JSONL event log.

The agent subpackage contains the OpenSeek agent loop, native DeepSeek tool-call handling, and local tool dispatch. It depends on deepseek/client, filesystem, and process APIs.

Agent CLI

The root package is the headless automation entry point — a subcommand tree (run/serve/mcp/sessions). The interactive terminal UI is the separate openseek_tui binary, its own module in openseek_tui/. openseek run parses arguments and runs the agent package. The agent sends DeepSeek native function tools and supports eleven local tools: mbtx — both the scripting surface and the command runner, spawning processes through the shell-free moonbitlang/async/shell API, with job_output and job_stop watching anything it detaches as a background job — plus edit, multi_edit, write, remove, plan, goal, and finish. There is no shell tool, so no command ever goes through a shell.

To run it on your own project without installing anything, moonx fetches the published package and runs it in the current directory:

export DEEPSEEK=sk-...
cd path/to/your/project
moonx moonbitlang/openseek run "inspect this project and finish with a short summary"

run prints only the answer on stdout, so … run "…" > answer.md saves just the answer. Its progress goes to stderr: the session id, one line per tool call, and how the run ended. The full record (reasoning, every tool call and its output, token usage) is the session log. A run that stops early exits non-zero and names the session to continue with --session <id>.

To watch a run live in the browser, add --inspect. Before the agent starts, the run starts (or reuses) the session viewer for its session root (moonx moonbitlang/inspect --ensure --watch, see inspect/README.md) and prints a link on stderr:

session cli-20260930-065544-387-647458c4 (.openseek)
watch live: http://127.0.0.1:41474/?t=…#s=cli-20260930-065544-387-647458c4

It also opens the link in your default browser (open on macOS, xdg-open on Linux, rundll32 on Windows), except over SSH or on a Linux session without a display, and says on the next line what it did. The page opens on that run and follows it as it records. The viewer is shared by every run and TUI in the project, outlives the run, and exits after an hour without a request. If it cannot start, the run says so once and carries on. --inspect needs a recorded session, so it cannot be combined with --no-session.

From a checkout of this repository, moon run . -- runs the same CLI; pass --dir to point it at another project, since it works in the current directory:

export DEEPSEEK=sk-...
moon run . -- run "inspect this project and finish with a short summary"

For Kimi models, set KIMI instead:

export KIMI=sk-...
moon run . -- --model kimi-k2.7-code-highspeed run "inspect this project"

For Z.AI GLM models, set GLM:

export GLM=...
moon run . -- --model glm-5.3 run "inspect this project"

OPENSEEK_MODEL is optional and defaults to deepseek-flash. OPENSEEK_MAX_STEPS is optional; when omitted, turns are bounded by the model's context window (a checkpoint summary carries each turn into the next) rather than a step count. Pass --max-steps to cap steps for one run. --thinking no|high|max controls thinking mode and effort (default: high); GLM maps no to its lowest supported effort because GLM 5.3 always reasons. Pass --dir <workspace> to run one-shot commands against another workspace while still launching from the current shell. The default is .; if the final directory component is missing and its parent exists, OpenSeek creates it and logs workspace_created.

MCP Servers

OpenSeek can use tools from MCP servers. Point --mcp-config (or OPENSEEK_MCP_CONFIG) at a JSON file in the de-facto standard shape — an existing Claude/Cursor-style mcp.json works as-is:

{
  "mcpServers": {
    "codex": { "command": "codex", "args": ["mcp-server"] },
    "remote": { "url": "https://example.com/mcp", "headers": { "Authorization": "Bearer …" } }
  }
}

Repeat the option to load multiple files, for example --mcp-config host.json --mcp-config user.json. Files merge in argument order; a later server with the same name replaces the entire earlier entry before any connections are opened. Explicit options replace the single-file OPENSEEK_MCP_CONFIG fallback. Empty values are ignored; --mcp-config= alone disables MCP. During run and serve, an unreadable or invalid file is reported and skipped while other files still load. The mcp validation command exits nonzero if any file cannot be loaded.

A command entry is launched as a stdio subprocess (in the agent's workspace, inheriting the environment plus any env overrides); a url entry speaks the Streamable HTTP transport. The servers' tools form a catalog that the agent's mbtx scripts search and call through the tools SDK's mcp package (@mcp.search, @mcp.call(server, tool, arguments)), for run, serve, and the TUI (which forwards OPENSEEK_MCP_CONFIG to its engine). They are not in the model's function list, so the request stays the same size however many servers are configured. A server that fails to start, handshake, or list its tools is logged and reported as unavailable — MCP never breaks a session. Tool results are size-capped and calls are bounded by a timeout.

HTTP url and headers values support ${VAR} references to the engine's environment, for example "Authorization": "Bearer ${MCP_TOKEN}". Expansion is single-pass and missing variables are configuration errors. Stdio fields remain literal.

Validate a configuration without starting a session:

moon run . -- mcp --mcp-config mcp.json

A running serve engine reports what it holds of those servers without being asked. It emits an mcp_status event once it has finished connecting them, and again each time that state changes — a connected server exiting, say. Each event carries the whole state: every configuration file in the order given, loaded or failed with the error, and each server of the merged configuration with its transport, its target (the command, or the URL without credentials), and a state — connected with the tools it registered, lost when it connected and the connection has closed since, no_tools, failed with the error, or skipped when earlier servers used up the tool budget. A controller keeps the latest one; it is this engine's own connections, not what connecting again would yield.

Resources and prompts (the other MCP capabilities) are not consumed: openseek's agent is tool-driven, and a server that wants to feed it context can expose a tool. This keeps the surface small; revisit if a concrete need appears.

Skills

Reusable markdown playbooks the agent loads on demand. A skill is a <name>.md file or a <name>/SKILL.md directory layout with optional name:/description: frontmatter. Two libraries are merged: the global one (~/.openseek/skills, or --global-skills-dir) and the workspace one (.openseek/skills), with workspace skills shadowing same-named global ones. The system prompt lists each skill's name, description, and file path; the agent reads the file before applying it. See agent_skill/README.mbt.md.

Terminal UI

The interactive terminal UI is the openseek_tui binary, the moonbitlang/openseek_tui module in openseek_tui/. It is a member of this workspace, so it builds against this checkout's moonbitlang/openseek (agent, session, and provider packages) and moonbitlang/openseek_protocol, and drives the openseek engine in serve mode. Its sessions are interoperable with the CLI's: moon run . -- sessions list shows what is resumable from either.

See each package README for API boundaries, examples, and package-specific test notes.

Verified CLI Documentation (cram)

The CLI behaviour is documented as executable cram tests under tests/, built and run with moon cram test. The wrapper compiles the native cmd/* packages and exposes each on PATH as <name>.exe (e.g. openseek.exe).

  • tests/cram/cli.md — offline openseek subcommand examples (top-level and run help, and the run/serve/sessions behaviors). They make no network calls and run in CI via moon cram test tests/cram.
  • tests/cram/run-requests.md — run driven by a parent: a JSON request on stdin, presets (--kind), the result file, refusals, cancellation by closing stdin, and the one-general-child lease (docs/run-result.md is the contract). It uses the modelless echo preset and a closed local port, and needs no API key.
  • tests/cram/read-workflow.md — a tested guide to read.mbtx: numbered files, ranges, errors, and output limits. See Writing cram documentation to add a guide for another script.
  • tests/cram/validation-workflows.md — the bundled check, test, and formatting scripts, exercised on a temporary project.
  • tests/live/deepseek.md — a real, non-mock DeepSeek round trip. It is opt-in (DEEPSEEK=sk-... moon cram test tests/live) and parses the agent's JSONL log with MoonBit itself: a moon run -e script reads the stream through the published moonbitlang/jsonl package and asserts on typed Json values — no jq — without pinning nondeterministic content such as token counts or model phrasing.

For the evaluation-backed roadmap, see agent-improvement-guide.md. It explains why the next highest-ROI work is semantic CLI validation, native CLI/error-handling guidance, shaped IDE output, and manifest/debug/edit guardrails.

The file-editing eval harness is available under eval/file_edit. It runs the real agent against isolated fixtures and checks exact final file state, making it suitable for cheap Flash baselines such as 8 successful edits out of 10.

The deterministic tool harness under eval/tool_harness exercises file, command, and control tools through agent_tool.execute_tool_call with temporary fixtures. It is meant for ordinary moon test coverage of tool wiring and observable side effects, not for model quality scoring.

The testkit/filesystem package provides reusable JSON-backed text fixtures for mock tests and evals. It materializes flat path-to-content JSON objects under a temporary root and compares listed files against disk.

About

DeepSeek-backed MoonBit coding agent.

Resources

Stars

103 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages