Rust CLI tool for managing tmux sessions and workspace workflows on remote machines.
- tmux
- git + gh (for
mxr ship,mxr new, andmxr secret) - ssh + scp (for
mxr sync) - wrangler / npm / flyctl (only for the matching
mxr deploytarget)
curl -sSfL https://raw.githubusercontent.com/urbanisierung/mxr/main/install.sh | shThe install script auto-detects your architecture (x86_64 / aarch64) and
resolves the newest release. mxr's 0.x builds are published as prereleases,
so the releases/latest/download/... URL does not resolve yet — use the
script above (or grab a binary from the releases page).
# Add current directory as a session
mxr session add myproject
# Open the session (create + attach, or just attach if running)
mxr myproject
# List sessions (marks active ones)
mxr session ls
# Sync to a remote machine
mxr sync all user@host
# Scaffold a new repo: generate CLAUDE.md, init, push to GitHub
mxr new myproject --template rust
# Seed Claude skills + plugins into a repo (.claude/), ready to commit
mxr claude init
# Quick commit + push + PR
mxr ship "feat: add something"
# Create a deploy target and wire up CI secrets
mxr deploy pages myapp # Cloudflare Pages project (via wrangler)
mxr deploy fly myapp # Fly.io app (via flyctl)
mxr secret cloudflare # set CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID
# Self-update
mxr update~/.config/mxr/sessions.toml:
[[session]]
name = "myproject"
dirs = ["/home/user/projects/myproject"]
[[session]]
name = "infra"
dirs = ["/home/user/infra", "/home/user/infra/terraform"]The first directory always gets two windows. Each additional directory gets one window.
CLAUDE.md templates for mxr new live in ~/.config/mxr/templates.toml. Defaults are
written on first run; edit them to set up your own. Each body shares a portable base
(behavioral + quality guidelines) and adds a stack-specific section. Built-in templates:
| Template | Stack |
|---|---|
default |
Portable base only (language-agnostic) |
rust |
Rust — cargo, clippy, rustfmt |
kb |
Markdown knowledge base — markdownlint-cli2, Prettier, cspell |
ts-monorepo |
pnpm + Turborepo + Astro + Vite + Vitest + Biome + Preact + Zustand |
python |
Python — uv, Ruff, ty, pytest |
go-service |
Go backend service — net/http, golangci-lint, go test |
{{name}} and {{stack}} in the body are substituted when scaffolding:
[[template]]
name = "rust"
tech_stack = "Rust"
description = "Rust project (cargo, clippy, rustfmt)"
body = "# {{name}}\n\n## Part 1 — Behavioral Guidelines\n..."mxr deploy shells out to the providers' official CLIs to create a target to
deploy to — it does not deploy itself. A GitHub Actions workflow (such as
.github/workflows/deploy-web.yml) does the deploying, reading credentials from
repo secrets you set with mxr secret.
mxr deploy pages mxrlp # wrangler pages project create
mxr deploy worker my-worker # npm create cloudflare@latest (C3 scaffold)
mxr deploy fly # fly apps create --generate-name
# Wire up the CI secrets the deploy workflow reads (delegates entry to gh):
mxr secret cloudflare # CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID
mxr secret fly # FLY_API_TOKEN
mxr secret set MY_KEY # any secret; reads the value from stdin
mxr secret set MY_KEY value # or pass it inline
# Or fold target creation into scaffolding:
mxr new myapp --deploy cloudflare-pages
mxr new myapp --deploy flymxr secret requires gh and runs against the current repo. Secret values are
never handled by mxr — gh reads them from stdin so they stay out of your
shell history and argv when omitted.
mxr new needs a laptop. When you're on the run and want to spin up a project
from the Claude app, use the /new-project skill in this repo instead — it's the
web equivalent, driven entirely through the GitHub integration (no gh/mxr
binary required):
- From the Claude app, open a Claude Code session on this repo (
urbanisierung/mxr). - Prompt:
/new-project rust foo(or/new-project ts my-app).
Claude creates the GitHub repo, seeds it with the matching
templates/<stack>/CLAUDE.md, a README, and a .gitignore, then
pushes the initial commit and hands back the repo URL.
- Stacks:
rust,ts. Flags:--org <org>,--public(default private). - The stack templates are plain files under
templates/— the same CLAUDE.md bodiesmxr newwrites locally, kept as files so a web session can read and render them. - The skill lives at
.claude/skills/new-project/SKILL.md. Make it a one-tap trigger by wiring it to a Routine (scheduled/on-demand prompt) — see the Claude Code on the web docs.
mxr claude init seeds the current repo's .claude/ with configurable Claude
Code skills and plugins so they can be committed and shared with anyone who
clones it:
mxr claude init # write skills + plugins into ./.claude/
mxr claude init --force # overwrite existing skill files
mxr new myapp --claude # seed during scaffolding (before the initial commit)- Skills are written as
.claude/skills/<name>/SKILL.md. - Plugins are merged into
.claude/settings.json. Existing files are left alone (skills) or deep-merged idempotently (settings.json).
Presets live in ~/.config/mxr/claude.toml (defaults written on first run, same
as templates). Built-in defaults are token-savers:
| Preset | Kind | Saves | Needs |
|---|---|---|---|
caveman |
skill | output tokens (terse prose) | — |
lean-context |
skill | context tokens (search-before-read, narrow reads) | — |
rtk |
plugin (settings) | tool-output tokens (Bash hook) | rtk binary + rtk init -g |
ast-grep |
plugin (marketplace) | context tokens (structural search vs full reads) | ast-grep binary |
superpowers |
plugin (marketplace) | redo-loop tokens (TDD/planning/debugging workflows) | — |
A plugin is one of two kinds:
[[skill]]
name = "caveman"
description = "Talk like caveman to save output tokens."
body = "# Caveman Mode\n..."
# kind = "settings": a raw JSON fragment merged into settings.json (e.g. a hook)
[[plugin]]
name = "rtk"
kind = "settings"
settings_json = '{ "hooks": { "PreToolUse": [ ... ] } }'
# kind = "marketplace": register a marketplace and enable the plugin from it
[[plugin]]
name = "my-plugin"
kind = "marketplace"
marketplace = "my-mp"
source = "github" # or "git"/"url" with a `url` field
repo = "owner/repo"The rtk default needs the rtk binary
installed and a one-time rtk init -g (it installs the hook script the committed
settings reference).
| Command | Description |
|---|---|
mxr <name> |
Open session (shortcut) |
mxr session add <name> [--dir <path>] |
Add session |
mxr session open <name> |
Open session |
mxr session ls |
List sessions |
mxr session rm <name> |
Remove session |
mxr sync config <user@host> |
Copy sessions.toml to remote |
mxr sync binary <user@host> |
Copy binary to remote |
mxr sync all <user@host> |
Copy both |
mxr ship [message] |
Commit, push, create PR |
mxr new <name> [--org O] [--template T] [--public] [--deploy P] [--claude] |
Scaffold a repo + CLAUDE.md, push to GitHub, optionally create a deploy target and seed .claude/ |
mxr claude init [--dir D] [--force] |
Seed .claude/ skills + plugins into a repo |
mxr deploy pages <name> [--branch B] |
Create a Cloudflare Pages project (wrangler) |
mxr deploy worker <name> |
Scaffold a Cloudflare Worker (C3) |
mxr deploy fly [name] |
Create a Fly.io app (flyctl) |
mxr secret set <KEY> [VALUE] |
Set a GitHub Actions secret (gh) |
mxr secret cloudflare |
Set Cloudflare deploy secrets |
mxr secret fly |
Set Fly.io deploy secret |
mxr import [--file <path>] |
Import legacy format |
mxr update |
Self-update |
mxr update --check |
Check for updates only |