Metadata-Version: 2.4
Name: msdev
Version: 0.9.0
Summary: Portable nodes and execution environments for msModelSlim development
Author: msModelSlim Agent Contributors
License: MulanPSL-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# msdev

`msdev` manages connection Nodes and execution Envs. A Node owns SSH and its
per-user `msdevd`; an Env references a Node and adds a host/Docker runtime plus
optional conda/venv/uv layers.

The CLI is intentionally stateless:

- Node-scoped NPU/model operations name `--node` or use `--all`;
- execution names `--env`;
- every workspace operation names the registered workspace;
- no harness conversation binding or implicit current Env exists;
- MCP is not part of the architecture.

## Install

```bash
python3 -m pip install -e tools/msdev
msdev --help
```

The package installs `msdev` and `msdevd`.

## Nodes and execution environments

Register a host from `~/.ssh/config`:

```bash
msdev node add dev-122 --ssh-host dev-122
msdev node list
msdev node status dev-122
```

Adding a Node atomically creates a same-named host Env. Bootstrap or refresh
the remote user daemon:

```bash
msdev node bootstrap dev-122
```

Configure persistent variables inherited by host-side child processes,
including `exec`, `env shell`, NPU queries, and workspace Git commands:

```bash
msdev node env dev-122 --set LD_LIBRARY_PATH=/opt/driver/lib
msdev node env dev-122
msdev node env dev-122 --unset LD_LIBRARY_PATH
```

Node variables apply only to the host runtime; Docker Envs do not inherit host
paths. Per-command `exec --env-var` values take precedence. Variable names and
values are stored in the private local resource registry, so use a dedicated
secret mechanism rather than this feature for credentials.

Persistent OpenSSH masters are optional:

```bash
msdev node connect dev-122
msdev node disconnect dev-122
```

For a server available only through a browser terminal, see
[Rootless web terminal access](docs/rootless-web-terminal-access.md). It covers
a rootless SSH daemon, a domestic reverse tunnel, WSL Fake-IP routing, host-key
verification, and the errors found during a real setup. Direct SSH in that
guide is a human connectivity bootstrap step; agent operations must still use
explicit `msdev` resources and must not bypass the CLI with SSH or SCP.

Nodes and Envs have separate private Markdown guides:

```bash
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/`, with private permissions and a 256 KiB
limit. Agents read the applicable guides once before first use in a session.

Open a human-operated interactive shell in an Env:

```bash
msdev env shell dev-122
msdev env shell dev-122 --cwd /srv/project
```

The command allocates an OpenSSH PTY and enters the Env's Docker runtime and
conda/venv/uv layers. Exiting returns
to the local shell. Only the shell session start and final status are visible
to msdev; commands typed inside it are not individually logged. Agent
automation should continue using `msdev exec`.

Create another Env on the same Node for Docker and Python layers:

```bash
msdev env add dev-122-vllm \
  --node dev-122 \
  --docker-container vllm-ascend \
  --layer conda:base \
  --layer venv:/srv/project/.venv
```

## NPU inventory

```bash
msdev npu list --node dev-122 --json
msdev npu list --all --json
```

## 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. Long jobs may also write a persistent progress
log when later inspection is required.

```bash
msdev exec \
  --env dev-122 \
  --cwd /srv/project \
  --timeout-seconds 1800 \
  --env-var MODE=test \
  -- python3 run.py
```

`--timeout-seconds` defaults to 300, accepts any positive finite duration, and
uses `-1` for no deadline. A positive timeout kills the complete command
process group and returns exit code 124. Cancelling the local CLI closes the RPC
connection, causing `msdevd` to kill and reap the remote process group. Finite
SSH/Unix RPC deadlines include a short completion grace for output drain and
serialization.

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

## Remote workspaces

A workspace gives a stable name to an Env and filesystem root:

```bash
msdev workspace add project \
  --env dev-122 \
  --root /srv/project

msdev workspace list
msdev workspace inspect project
```

Workspace operations are file- and Git-oriented. There is no
`msdev workspace exec`; use `msdev exec --env ... --cwd ...` for commands.

### Read and inspect

```bash
msdev workspace stat project README.md
msdev workspace read project README.md
msdev workspace read project weights.bin --output /tmp/weights.bin
msdev workspace list project src --json
msdev workspace glob project '**/*.py' --json
msdev workspace search project 'TODO' src tests --json
```

### Write safely

For non-trivial content, use stdin or `--file` rather than shell-escaped
`--content`:

```bash
msdev workspace write project docs/note.md < /tmp/note.md
msdev workspace write project docs/note.md --file /tmp/note.md
```

Compare-and-swap replacement prevents overwriting a changed remote file:

```bash
msdev workspace apply-patch project docs/note.md \
  --file /tmp/note.md \
  --expected-sha256 <digest>
```

Delete an explicit remote file:

```bash
msdev workspace delete project docs/obsolete.md
```

### Git

```bash
msdev workspace git-status project --result-json
msdev workspace git-diff --result-json project -- --stat
```

Git diff rejects options that can write files or invoke external diff helpers.

## Model inventory

Examples:

```bash
msdev model discover --node dev-122 --root /data/models
msdev model list --node dev-122 --json
msdev model list --all --json
msdev model inspect model://qwen/Qwen3-32B@main --node dev-122
msdev model validate model://qwen/Qwen3-32B@main --node dev-122
msdev model audit --node dev-122
```

Use `msdev model --help` and the individual subcommand help for register,
update, replicas, refresh, verify, export, import, and rebind.

## Explicit CLI sessions and runbooks

Create a session before a reproducible workflow:

```bash
msdev session begin --name qwen3-quant --json
```

Pass the returned ID explicitly or set it in a persistent terminal:

```bash
export MSDEV_SESSION_ID=<session-id>
```

Intent metadata is global and must appear before the subcommand:

```bash
msdev \
  --session-id <session-id> \
  --intent-kind execution \
  --intent-summary 'Run Qwen3 quantization' \
  --intent-phase quantization \
  --intent-step-id quant-1 \
  exec --env dev-122 --timeout-seconds 1800 -- python3 quant.py
```

Intent kinds:

- `execution`: core reproduction step;
- `verification`: optional confirmation;
- `diagnostic`: troubleshooting, excluded from core steps;
- `exploration`: discovery, excluded from core steps.

Each invocation receives a unique `operation_id`. `session_id` groups CLI
operations only; it never supplies a Node, Env, or workspace default.

Logs are private JSONL files under:

```text
${XDG_STATE_HOME:-~/.local/state}/msdev/sessions/
```

They retain sanitized logical arguments, preview, explicit resource, intent,
exit code, and elapsed time. Command stdout/stderr and environment values are
not duplicated into logs.

```bash
msdev session list
msdev session export --session-id <session-id> --output runbook.md
msdev session export --latest --detail normal --output runbook.md
msdev session export --input /path/to/session.jsonl --detail full
```

## Architecture

```text
msdev CLI
  -> typed core service
  -> UnixRpcTransport or SshRpcTransport
  -> per-user msdevd
  -> host/container command, workspace filesystem, NPU, or inventory
```

Remote RPC responses and command output are bounded. Workspace paths are
normalized under the registered root. Writes are atomic and support SHA-256
compare-and-swap. Node/Env and workspace registries use locked atomic updates.

## Testing

```bash
cd tools/msdev
python3 -m unittest discover -s tests -v
```
