Skip to main content

msdev

msdev exposes three capabilities: node (SSH + connection reuse), env (shared execution context, shell, files), and exec (commands).

A Node owns SSH reachability and optional ControlMaster multiplexing. An Env owns the full execution context: host or Docker runtime, conda/venv/uv layers, optional setup script (root switch, proxy, etc.), command wrap, and static env vars. Commands run over direct SSH (no remote msdevd).

The CLI is intentionally stateless: execution always names the env as the first exec argument. MCP is not part of the architecture.

Install

git clone https://gitcode.com/rookie_hongchuan/msdev.git
cd msdev
python3 -m pip install -e .
msdev --help
msdev --version

The package installs the msdev CLI.

Install the agent skill for Cursor and Claude Code, and sync SSH config:

msdev init
msdev init --scope project
msdev init -f

init registers Host aliases from ~/.ssh/config, prints added/removed changes, and writes skills/msdev-cli/SKILL.md into ~/.cursor/skills/ and ~/.claude/skills/ (or into .cursor/ / .claude/ under the current directory with --scope project). Outdated skill files prompt before overwrite; use -f to force.

Windows client

The typical setup is a Windows laptop talking to Linux Nodes. Native C:\Windows\System32\OpenSSH\ssh.exe does not support ControlMaster. msdev therefore prefers Git for Windows OpenSSH when installed (C:\Program Files\Git\usr\bin\ssh.exe), which does:

  • auto-selects Git Bash ssh/sftp/ssh-keygen over PATH / System32 OpenSSH; override with MSDEV_SSH / MSDEV_SFTP / MSDEV_SSH_KEYGEN;
  • enables ControlMaster when the resolved client is Git/MSYS OpenSSH (disable with MSDEV_SSH_CONTROL_MASTER=0, force with =1);
  • falls back to System32 OpenSSH without mux if Git is not installed;
  • hides SSH console windows (CREATE_NO_WINDOW) and kills local process trees with taskkill /T on timeout or cancel;
  • SSH is non-interactive: BatchMode unless a password is supplied, host keys use accept-new, and there is no password/passphrase/yes-no prompt. When a password is known, injects OpenSSH SSH_ASKPASS so node connect (and later ssh/sftp) can authenticate without a TTY; the local public key is then installed on the Node so later logins are passwordless. The password is never written to the node registry.

Install with python -m pip install -e .. install-user.py writes msdev.cmd under %USERPROFILE%\.local\bin.

Remote paths inside a Linux Env remain POSIX (/srv/...). Local env put/get on Windows accept Windows absolute paths (C:\...).

Local exec on Windows wraps Conda with conda run and venvs with Scripts\activate.bat (remote Linux Nodes still use POSIX sh/bash wrappers).

Nodes and execution environments

Use node connect as the single entry point: it writes ~/.ssh/config when needed, registers the node, saves passwords, installs the local public key, and opens an SSH ControlMaster when multiplexing is supported:

msdev node connect dev-122 --hostname 80.48.33.133 --user root --password PASSWORD
msdev node connect dev-122
msdev node bootstrap dev-122
msdev node sync-ssh
msdev node list --ssh
msdev node list

Connect writes or updates a dedicated Host <name> block in OpenSSH config. The msdev registry stores the Host alias. User, port, keys, and proxy remain in SSH config. node sync-ssh registers Host aliases that were added manually.

Connect atomically creates a same-named host Env on first use. There is no remote agent binary to deploy. Use msdev node bootstrap NODE only to re-check SSH readiness after connect problems.

Inspect connectivity for one node or for every registered node (probes run in parallel; partial failures exit non-zero):

msdev node status
msdev node status dev-122

Rename a node together with its same-named host Env, guide files, and SSH Host alias:

msdev node rename dev-122 lab-122

Persistent OpenSSH masters are optional. All SSH from msdev is non-interactive: host keys use accept-new, and password/passphrase prompts are disabled. Supply --password on connect; it is saved to ~/.ssh/config as # msdev Password ... and used to install the local public key (~/.ssh/id_ed25519, generated if missing) so later connections can be passwordless:

msdev node connect dev-122 --hostname 80.48.33.133 --user root --password PASSWORD
msdev node connect dev-122
msdev node connect dev-122 --identity FILE     # choose which key to install
msdev node connect dev-122 --no-install-key    # password only, do not copy key
msdev node disconnect dev-122

Nodes and Envs have separate private Markdown guides:

msdev node guide dev-122
msdev node guide dev-122 --write ./dev-122-guide.md
msdev env guide dev-122
msdev env guide dev-122 --write ./host-env-guide.md

Guides are stored under ~/.config/msdev/guides/nodes/ and ~/.config/msdev/guides/environments/. Node guides document how to connect; Env guides document how to initialize shared context (setup).

Share a full local configuration (registry + guides) with:

msdev config export ./msdev-config.tar.gz
msdev config import ./msdev-config.tar.gz
msdev config import ./msdev-config.tar.gz --force   # overwrite name conflicts

Bundles contain resources.json, both guide trees, and a manifest.json. SSH keys and passwords are never exported.

msdev env add dev-122-root \
  --node dev-122 \
  --setup-file ./setup-root.sh \
  --wrap sudo --wrap -n --wrap --

msdev env open dev-122-root

Open an interactive shell in an env. Docker envs enter the container:

msdev env shell dev-122
msdev env shell dev-122-docker --cwd /srv/project

Agent automation should use msdev exec, not env shell.

File put, get, read, and write

Bulk transfer copies a local file into an Env filesystem, or fetches one back:

msdev env put dev-122 ./config.yaml /srv/project/config.yaml
msdev env get dev-122 /srv/project/config.yaml --output ./config.yaml
msdev env get dev-122 /srv/project/config.yaml > ./config.yaml

Editing uses content-oriented read/write. Paths inside the Env must be absolute. Host Envs use direct filesystem copy locally and sftp/ssh streams remotely. Docker Envs stage through the node with docker cp. File bytes never pass through JSON RPC.

msdev env read dev-122 /srv/project/config.yaml
msdev env read dev-122 /srv/project/config.yaml --json
msdev env write dev-122 /srv/project/note.md --file /tmp/note.md
msdev env write dev-122 /srv/project/note.md < /tmp/note.md
msdev env write dev-122 /srv/project/note.md --file /tmp/note.md \
  --expected-sha256 <digest>

Read before replacing an existing file. --expected-sha256 is compare-and-swap replacement that refuses to overwrite a changed remote file.

Command execution

Commands execute synchronously and stream stdout and stderr to the terminal as they are produced. Cursor or Claude Code should use their native background terminal support for long jobs.

Pick one form:

Scenario Form
Simple one-liner -c '…'
Quotes, pipes, multi-line --file - + heredoc (see below)
Script on disk --file ./script.sh

Heredoc (<<'EOF') is a local-shell mechanism: it writes a multi-line string to msdev's stdin when you pass --file -. Quote the delimiter (<<'EOF') so $ and backticks are not expanded locally. msdev then runs the body through a remote shell (sh -c), or via shebang if the body starts with #!.

msdev exec dev-122 --file - <<'EOF'
python3 -c 'print("no local quoting")'
grep 'pattern' /var/log/app.log | tail -20
EOF

msdev exec dev-122 -c 'python3 train.py --config "path with spaces" | tee log.txt'

msdev exec dev-122 --file ./scripts/run.sh

Positional commands after -- are not supported. The env name is the first argument after exec; use -c for inline strings or --file for script content (path or - for stdin/heredoc). -c - is accepted but identical to --file -; prefer --file - only.

Quoted pipelines and | tokens are executed through a remote POSIX shell (sh -c), so they run on the Node instead of being treated as a single executable name. On a Windows local Env they use cmd.exe /s /c. Prefer sh -c '…' for complex scripts. Default streaming writes POSIX newlines as CRLF on a Windows console so remote line output does not staircase; piped CLI output keeps LF.

--timeout-seconds defaults to -1 (no deadline). Any positive finite duration is also accepted. A positive timeout kills the local SSH/command process tree and returns a timed-out result. Cancelling the local CLI closes the SSH session (best-effort remote cancel).

--result-json selects captured, non-streaming execution and prints one structured JSON result containing stdout and stderr.

Architecture

msdev CLI
  -> typed core service
  -> UnixRpcTransport (local subprocess) or SshRpcTransport
  -> SSH ControlMaster (when supported) + direct remote command / SFTP

Remote command output is bounded. Node/Env registries use locked atomic updates.

Testing

python3 -m unittest discover -s tests -v

Feature work must include at least one actual scenario test on the real control path (msdev CLI → service → SSH/SFTP → effect). Unit tests alone are not sufficient.

Metadata

Release files for msdev 0.15.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for msdev 0.15.2
File Size Uploaded Provenance
msdev-0.15.2.tar.gz 138.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for msdev 0.15.2
File Interpreter ABI Platform
msdev-0.15.2-py3-none-any.whl Python 3 none any Details

Total release size: 232.3 kB

Release files / msdev-0.15.2.tar.gz

Download URL msdev-0.15.2.tar.gz
Size 138.9 kB
Tags Source
SHA-256 checksum
How to use checksums
7bc10049a316b4740ae5308f63ed5f80d96d345d8b8ff34819c8e8dccd236f6a
BLAKE2b-256 checksum
How to use checksums
c174168cbbd32f69963e44fe4d27da6fea5449ac111fc7a9d04b66204b180fb4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / msdev-0.15.2-py3-none-any.whl

Download URL msdev-0.15.2-py3-none-any.whl
Size 93.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
08e6576e742aa0d2849d4eb54377701f041f8e62fdf7af5cf4a6b39325f1b68e
BLAKE2b-256 checksum
How to use checksums
6b9dd771d71e7456451ade6d26b2b808010468fe8768a13cd6d91498d3ef6341
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Security for msdev 0.15.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page