Agent-friendly RMUX interface.
  • Rust 94.8%
  • Nix 5.2%
Find a file
2026-07-30 19:48:07 +08:00
assets docs: add installation guide and stable RMUX pin 2026-07-28 21:22:43 +08:00
docs chore: move metadata to Forgejo and add Apache license 2026-07-29 04:55:34 +08:00
src fix(muxrun): capture the current screen viewport 2026-07-30 19:48:07 +08:00
.envrc chore(devenv): add development environment 2026-07-28 13:00:35 +08:00
.gitignore feat(muxrun): add durable RMUX command runner 2026-07-28 12:59:45 +08:00
.muxrun.toml feat(muxrun): add durable RMUX command runner 2026-07-28 12:59:45 +08:00
AGENTS.md feat(muxrun): add durable RMUX command runner 2026-07-28 12:59:45 +08:00
Cargo.lock feat(muxrun): add durable RMUX command runner 2026-07-28 12:59:45 +08:00
Cargo.toml chore: move metadata to Forgejo and add Apache license 2026-07-29 04:55:34 +08:00
devenv.lock docs: add installation guide and stable RMUX pin 2026-07-28 21:22:43 +08:00
devenv.nix docs: add installation guide and stable RMUX pin 2026-07-28 21:22:43 +08:00
devenv.yaml docs: add installation guide and stable RMUX pin 2026-07-28 21:22:43 +08:00
flake.lock docs: add installation guide and stable RMUX pin 2026-07-28 21:22:43 +08:00
flake.nix docs: add installation guide and stable RMUX pin 2026-07-28 21:22:43 +08:00
LICENSE chore: move metadata to Forgejo and add Apache license 2026-07-29 04:55:34 +08:00
package.nix chore: move metadata to Forgejo and add Apache license 2026-07-29 04:55:34 +08:00
README.md chore: move metadata to Forgejo and add Apache license 2026-07-29 04:55:34 +08:00
SKILL.md feat(muxrun): add recovery and agent tooling 2026-07-28 18:00:50 +08:00

muxrun icon

muxrun

Durable, inspectable PTY commands for coding agents.

muxrun runs a command inside a project-scoped RMUX terminal. A coding agent can wait for a bounded interval, leave the command running, inspect it later, send input, or attach a real terminal without restarting the process.

Use it for builds, tests, dev servers, experiments, installers, and interactive programs that should survive an agent request or terminal ending.

Want your coding agent to install muxrun for you? Give it Install muxrun for an agent and ask it to follow the document in your project.

Why muxrun

  • Commands survive the muxrun client and agent request that started them.
  • Every command gets a durable task ID and a real PTY.
  • Agents can inspect rendered history, raw terminal output, or the current TUI.
  • Agents can send text and terminal keys without owning stdin continuously.
  • Text and JSON output support both humans and automation.
  • muxrun ls recovers task IDs after an agent or terminal exits unexpectedly.
  • The Nix package pins RMUX 0.8.0 at evaluation, build, and runtime.

Requirements

  • Linux on x86_64 for the current Nix flake
  • Nix with flakes, or devenv
  • A .muxrun.toml in each project that uses muxrun

The Nix package includes the matching RMUX runtime. Building directly with Cargo instead requires rmux 0.8.0 and rmux-daemon on PATH.

Install

Try It Without Installing

Run muxrun directly from the Forgejo repository:

nix run git+https://git.gjz010.com/gjz010/muxrun.git -- skill

Commands that manage tasks must run in a project containing .muxrun.toml.

Nix Flake

Add muxrun as an input and put its package in your dev shell or package list:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    muxrun.url = "git+https://git.gjz010.com/gjz010/muxrun.git";
  };

  outputs =
    { nixpkgs, muxrun, ... }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
    in
    {
      devShells.${system}.default = pkgs.mkShell {
        packages = [ muxrun.packages.${system}.default ];
      };
    };
}

Then update the lock file and enter the shell:

nix flake lock
nix develop
muxrun --version

muxrun has a separate, locked rmux-nixpkgs input that supplies only RMUX 0.8.0. Do not override it to follow the project's nixpkgs. Updating your project's nixpkgs, or muxrun's build-tool nixpkgs, therefore keeps the exact same RMUX derivation and continues to use its existing binary-cache entry.

devenv

Add muxrun to devenv.yaml without changing your existing inputs:

inputs:
  muxrun:
    url: git+https://git.gjz010.com/gjz010/muxrun.git

Then expose that input's package from devenv.nix:

{ inputs, pkgs, ... }:

{
  packages = [
    inputs.muxrun.packages.${pkgs.stdenv.system}.default
  ];
}

Merge these snippets into existing inputs and packages; do not replace other project settings. The muxrun input carries its independent rmux-nixpkgs pin transitively; do not override it with follows.

Resolve the input and verify the shell:

devenv update muxrun
devenv shell -- muxrun --version

Configure A Project

Create .muxrun.toml at the project root:

root = ".devenv/muxrun"
interval = "3m"
history_limit = 100000
completed_ttl = "24h"
cancel_grace = "5s"

# Omit for unlimited completed output. When set, muxrun retains the head and
# tail and marks the report as truncated.
# output_limit = 1048576

[terminal_size]
cols = 120
rows = 40

muxrun first uses the file named by MUXRUN_CONFIG. Otherwise it searches from the current directory toward the filesystem root for .muxrun.toml. Relative root paths are resolved from the configuration file's directory.

Ignore the runtime state directory if your project does not already ignore it:

.devenv/muxrun/

Install The Agent Skill

The executable embeds SKILL.md, which teaches OpenCode-compatible agents when and how to use muxrun:

mkdir -p .opencode/skills/muxrun
muxrun skill > .opencode/skills/muxrun/SKILL.md

Restart OpenCode after installing or updating the skill. For another agent that supports SKILL.md, redirect muxrun skill into that agent's project or global skill directory.

Quick Start

Wait up to the configured interval for a command:

muxrun run -- cargo test --workspace

If the command finishes, muxrun prints its rendered terminal history and returns its exit status. If it is still running, muxrun prints a task ID with reason=timeout and leaves the process running.

Start immediately in the background:

muxrun start -- cargo run --release

List and inspect retained tasks:

muxrun ls
muxrun status TASK_ID
muxrun tail -n 100 TASK_ID
muxrun screen TASK_ID
muxrun transcript TASK_ID

Continue waiting for a task:

muxrun resume TASK_ID

When resume observes completion, it prints the final output, returns the child's exit status, and consumes the task. A timeout preserves the task.

Interactive Input

send does not append a newline. Send Enter explicitly:

muxrun send TASK_ID 'yes'
muxrun send --key TASK_ID Enter
muxrun send --key TASK_ID C-c

Attach a human terminal when direct interaction is needed:

muxrun attach TASK_ID

Stop And Clean Up

muxrun cancel TASK_ID
muxrun clean TASK_ID
muxrun gc
  • cancel sends C-c, waits cancel_grace, then sends SIGTERM to the PTY process group if needed. The task remains inspectable.
  • clean immediately kills the session and deletes its metadata.
  • gc removes expired completed tasks and never kills running tasks.

JSON Output

Place global --json before the subcommand:

muxrun --json run -- cargo test
muxrun --json ls
muxrun --json status TASK_ID

Reports include the task ID, state, command, elapsed time, truncation and consumption flags, and relevant reason, wait_signal, exit_code, signal, or output fields.

Signals And Recovery

If a waiting run or resume receives SIGHUP, SIGINT, SIGQUIT, or SIGTERM, it prints the retained task ID with reason=signal, reports the signal, and exits with 128 + signal. It does not signal the child task.

SIGKILL cannot be caught. The RMUX task still survives; recover its ID with:

muxrun ls

Raw RMUX Escape Hatch

Forward an operation that muxrun does not expose directly to the pinned RMUX CLI and current project socket:

muxrun rmux -- list-sessions
muxrun rmux -- list-panes -a

stdin, stdout, stderr, and the RMUX exit status are passed through. Do not pass -S; muxrun owns project socket selection.

PTY Semantics

  • stdout and stderr are merged into one terminal stream.
  • The child sees a TTY and may enable colors, line buffering, progress redraws, or a full-screen interface.
  • stdin from start, run, and resume is not forwarded. Use send or attach.
  • tail and completed output are rendered terminal history. transcript retains raw PTY bytes including ANSI escapes and carriage returns.
  • RMUX owns the PTY, rendered screen, output retention, and scrollback. muxrun stores task metadata and uses a project-scoped Unix socket.

RMUX Version Binding

The flake uses two independent nixpkgs inputs. The main nixpkgs builds muxrun, while rmux-nixpkgs supplies one cache-stable RMUX 0.8.0 derivation. Updating the main input does not rebuild or move RMUX. The package also asserts RMUX 0.8.0 during evaluation, embeds its absolute store path for CLI operations, and wraps the binary with the matching daemon path. An unrelated rmux earlier on PATH is not used. Update rmux-sdk, the version assertion, and rmux-nixpkgs together when intentionally changing the RMUX protocol version.

Development

cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo test
nixfmt --check devenv.nix flake.nix package.nix
nix flake check
nix build .#muxrun
devenv build outputs.muxrun

License

Licensed under the Apache License 2.0.