Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
229acd2
feat(agent): replace the shell tool with the myshell process EDSL
tonyfettes Aug 19, 2026
41535d5
fix(run_moonbit): correctness fixes from review, and restore two upst…
tonyfettes Aug 19, 2026
2a1f783
fix(run_moonbit): stop telling the model native is required for IO
tonyfettes Aug 19, 2026
9ed492b
feat(run_moonbit): confine snippets with a moonrun policy and a works…
tonyfettes Aug 20, 2026
c8bb688
fix(run_moonbit): close three refusals a real turn ran into
tonyfettes Aug 20, 2026
7a65bcd
refactor(run_moonbit): drop the workspace boundary, keep the policy
tonyfettes Aug 20, 2026
4d1e0b7
ci: move to nightly, and tell the model what a snippet may start
tonyfettes Aug 20, 2026
9ed3862
fix(run_moonbit): grant the DEFAULT registry path, not only MOON_HOME's
tonyfettes Aug 20, 2026
03b023b
fix(run_moonbit): describe the spawn allowlist on the tool, not in on…
tonyfettes Aug 20, 2026
f935a23
refactor(run_moonbit): open the snippet's reads, keep its writes bounded
tonyfettes Aug 20, 2026
2b9d1b0
docs(run_moonbit): give the tool description sections, and a test tha…
tonyfettes Aug 20, 2026
33543f4
fix(review): give the standalone review CLI the sandbox its docs claim
tonyfettes Aug 21, 2026
be4f524
refactor: bind scratch-dir cleanup to the scope that owns it
tonyfettes Aug 21, 2026
9ab9856
refactor(prompt): teach the command surface in the prompts, not the tool
tonyfettes Aug 21, 2026
5fe1d71
feat(run_moonbit): admit `git rebase`, not only its control forms
tonyfettes Aug 21, 2026
925947a
docs: trim the sandbox-guidance comments to their point
tonyfettes Aug 21, 2026
ffb35f3
feat(run_moonbit): admit the read-only git queries
tonyfettes Aug 21, 2026
e96d918
feat(run_moonbit): admit git ls-tree
tonyfettes Aug 21, 2026
896cf31
refactor(run_moonbit): hold the command surface on the tool, not in f…
tonyfettes Aug 21, 2026
2b12c2e
ci: follow main onto the pre-release channel
tonyfettes Aug 21, 2026
88dd36f
fix(sandbox): give the worker profile its own denial guidance
tonyfettes Aug 21, 2026
abba289
feat(run_moonbit): admit just, drop git config, and fix two false claims
tonyfettes Aug 21, 2026
acb5f24
fix(run_moonbit): bound the wait that binary output starts, and corre…
tonyfettes Aug 21, 2026
c2e8714
refactor(run_moonbit): wait for the exit, not for the early wake it d…
tonyfettes Aug 21, 2026
616dde8
fix: stop advertising refused worktree cleanup, and repair the bgjobs…
tonyfettes Aug 21, 2026
170bade
feat(run_moonbit): admit git worktree prune
tonyfettes Aug 21, 2026
1ae9d95
feat(run_moonbit): a snippet writes only its own temp directory
tonyfettes Aug 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ jobs:
- name: Checkout code
uses: actions/checkout@v5

# Pre-release, to match CI: `run_moonbit`'s policy states its spawn
# allowlist with `process.allow`, which stable's moonrun rejects outright,
# so an agent working here on stable would find every snippet refused.
- name: Set up MoonBit
run: |
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash -s pre-release
echo "$HOME/.moon/bin" >> $GITHUB_PATH

- name: Update MoonBit dependencies
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/desktop-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,14 @@ jobs:
expected="version = \"$RELEASE_VERSION\""
grep -Fx "$expected" desktop/moon.mod

# Pre-release, matching CI. This is the toolchain that BUILDS the app, not
# the seed it ships (that one is pinned by `desktop/.moonbit-version`), but
# if the two channels differed then a change compiling on the channel CI
# runs could still break the release build, and nothing would catch it
# until a release ran.
- name: Set up MoonBit
run: |
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash -s pre-release
echo "$HOME/.moon/bin" >> "$GITHUB_PATH"

- name: Show MoonBit version
Expand Down
9 changes: 6 additions & 3 deletions README.mbt.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,12 @@ The `cmd/openseek` package is the single-binary entry point — a subcommand tre
(default: the terminal UI; `run`/`serve`/`review`/`sessions` for the headless
engine; `mcp` to validate MCP configuration). `openseek run` parses arguments
and runs the agent package. The agent sends DeepSeek native function tools and
supports twelve local tools: `shell` (with `shell_output` and `shell_stop` for
background jobs — on Windows the plain foreground shell only), `read`, `edit`,
`multi_edit`, `write`, `remove`, `plan`, `goal`, `run_moonbit`, and `finish`.
supports eleven local tools: `run_moonbit` — both the scripting surface and the
command runner, spawning processes through the shell-free
[`bobzhang/myshell`](https://mooncakes.io/docs/bobzhang/myshell) EDSL, with
`job_output` and `job_stop` watching anything it detaches as a background job —
plus `read`, `edit`, `multi_edit`, `write`, `remove`, `plan`, `goal`, and
`finish`. There is no shell tool, so no command ever goes through a shell.

```bash
export DEEPSEEK=sk-...
Expand Down
43 changes: 22 additions & 21 deletions agent/README.mbt.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ calls `@agent.run`, but that decision lives outside the `agent` package.

`build_tools(runtime, scope)` returns the standard local tool registry:

- `shell`: run a command under the workspace root or an explicit cwd (including
`moon check` for compiler feedback), with `run_in_background` support;
- `shell_output` / `shell_stop`: read or stop a background shell job (omitted on
Windows, where background jobs are not wired);
- `run_moonbit`: compile and run a self-contained MoonBit program — both the
scripting surface (transform files, parse JSON, compute, probe the language)
and the command runner, since processes are spawned from the program through
the shell-free `bobzhang/myshell` EDSL. Supports `run_in_background`;
- `job_output` / `job_stop`: read or stop a background job;
- `read`: read a text file;
- `edit`: replace exact text in a file;
- `multi_edit`: apply several explicit line-anchored replacements to one file;
Expand All @@ -115,16 +116,16 @@ calls `@agent.run`, but that decision lives outside the `agent` package.
- `plan`: record or replace the step-by-step plan for a multi-step task;
- `goal`: report standing-goal status (`met`, `continuing`, or `blocked`;
`met` clears the goal — setting one is the serve `goal` command's job);
- `run_moonbit`: compile and run a self-contained MoonBit program in an
isolated package (automation and language probes; standard batteries only,
no local packages);
- `finish`: end the task with a final answer.

There is no shell tool: every command the agent runs is an argument vector
handed to `@myshell.Cmd`, so no command text is ever parsed by a shell.

File-oriented tools capture `runtime.workspace_root()` when the registry is
built. The registry also receives the runtime and task scope for stateful
tools: the shell tools use both — background-job completion notices are pushed
through `runtime.queue_steer`, and the background-job runtime plus its spill-dir
cleanup are owned by the task scope's group.
tools: the background-job path uses both — completion notices are pushed
through `runtime.queue_steer`, and the job runtime plus its spill-dir cleanup
are owned by the task scope's group.

```mbt check
///|
Expand All @@ -139,9 +140,6 @@ async test "standard tools are registered in dispatch order" {
],
content=(
#|[
#| "shell",
#| "shell_output",
#| "shell_stop",
#| "read",
#| "edit",
#| "multi_edit",
Expand All @@ -150,6 +148,8 @@ async test "standard tools are registered in dispatch order" {
#| "plan",
#| "goal",
#| "run_moonbit",
#| "job_output",
#| "job_stop",
#| "finish",
#|]
),
Expand Down Expand Up @@ -283,9 +283,9 @@ answer, `finish`, `abort`, cancellation, unexpected failure, or exhausted

## Operational Notes

This package is intended for trusted local automation. The standard `shell`
tool can run arbitrary commands, while `edit` and `write` can modify files
visible to the process. Use the CLI package for application-level policy,
This package is intended for trusted local automation. `run_moonbit` can run
arbitrary commands (its snippets spawn processes), while `edit` and `write` can
modify files visible to the process. Use the CLI package for application-level policy,
session storage, logging configuration, and serve-mode wire handling.

Run the package tests with:
Expand All @@ -312,11 +312,12 @@ improving:
logs through async logging so piped runs such as `2>&1 | tee run.log` receive
step output promptly.
- Current MoonBit projects use `moon.mod`; `moon.mod.json` is legacy. Manifest
or package-import edits should be followed quickly by a shell `moon check` or
another explicit shell validation command.
- Use `shell` for exact end-to-end MoonBit command validation beyond compiler
feedback, especially `moon test`, `moon run`, `moon info`, `moon fmt`, and
README command checks.
or package-import edits should be followed quickly by a `moon check` or
another explicit validation command.
- Use `run_moonbit` for exact end-to-end MoonBit command validation beyond
compiler feedback, especially `moon test`, `moon run`, and README command
checks. Source-writing commands (`moon fmt`, `moon info`) are denied by the
snippet sandbox and belong to the caller, not the agent.
- For snapshot updates, run plain `moon test` first and only run
`moon test --update` after deciding the failure is a stale snapshot or
intentional output change, not a behavior bug.
5 changes: 2 additions & 3 deletions agent/moon.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
"bobzhang/openseek/agent_runtime",
"bobzhang/openseek/agent_tool",
"bobzhang/openseek/agent_tool/bgjobs",
"bobzhang/openseek/agent_tool/shell_output",
"bobzhang/openseek/agent_tool/shell_stop",
"bobzhang/openseek/agent_tool/job_output",
"bobzhang/openseek/agent_tool/job_stop",
"bobzhang/openseek/agent_tool/edit",
"bobzhang/openseek/agent_tool/finish",
"bobzhang/openseek/agent_tool/goal",
Expand All @@ -15,7 +15,6 @@ import {
"bobzhang/openseek/agent_tool/run_moonbit",
"bobzhang/openseek/agent_tool/read",
"bobzhang/openseek/agent_tool/remove",
"bobzhang/openseek/agent_tool/shell",
"bobzhang/openseek/agent_tool/write",
"bobzhang/openseek/deepseek",
"bobzhang/openseek/deepseek/client",
Expand Down
2 changes: 1 addition & 1 deletion agent/steer_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async fn steer_test_server(group : @async.TaskGroup[Unit]) -> String? {
assert_true(request_body.contains("also rename the file"))
// The prebuilt registry reached the request: the standard tools ride
// along even though the caller, not the turn, constructed them.
assert_true(request_body.contains("\"name\":\"shell\""))
assert_true(request_body.contains("\"name\":\"run_moonbit\""))
conn.send_response(200, "OK", extra_headers={
"Content-Type": "text/event-stream",
})
Expand Down
Loading
Loading