Docs & CLI

From repository to running task.

Everything the microdev CLI does, from the first login to scripted task creation. Each task is its own isolated Linux microVM; these pages cover how to start one, what it keeps, and when it stops.

Quickstart

The CLI runs on macOS and Linux, on Intel/AMD 64-bit and ARM64. It needs OpenSSH to connect, and finds an existing key or creates a dedicated one in ~/.config/microdev. On Windows, install the Linux CLI inside WSL2.

  1. Install

    Your terminal
    curl -fsSL https://microdev.dev/install.sh -o install-microdev.shsh install-microdev.shexport PATH="$HOME/.local/bin:$PATH"

    The installer verifies a SHA-256 checksum fetched over HTTPS, then installs to ~/.local/bin. It needs no administrator privileges and does not change your shell startup files. Pass --bin-dir /absolute/path to install elsewhere or --version VERSION to pin a release. You can read the installer before running it.

  2. Sign in

    Your terminal
    microdev login

    login prints GitHub's device authorization URL and the code to enter, and opens the page in your browser. Add --no-browser to skip opening the browser; the URL is printed either way. Your personal organization is selected automatically. The trial needs no card.

  3. Start the demo

    Your terminal
    microdev demo

    demo starts a private, isolated task from the public microdev-dev/microdev-demo sample and connects you to it. The sample is public, so it needs no Git credentials, and the CLI never offers yours to it.

  4. Run the tests inside the task

    Inside the task
    cd ~/workspacecargo test

    Edit the sample freely. You can't push to the sample; push your changes to your own repository. The sample's README walks through a first change.

Your repository

A public repository needs nothing more. A private one clones with your computer's Git credentials: sign in to GitHub with gh auth login or your configured Git credential helper, including the macOS Keychain.

Your terminal
microdev start OWNER/REPO

HTTPS and SSH GitHub clone URLs work in place of OWNER/REPO. microdev repos lists your GitHub repositories; it reads them through the GitHub CLI, so it needs gh auth login.

microdev start
Uses the current checkout's GitHub origin. With no origin, or outside a Git checkout, it starts the demo; an origin that is not on GitHub is refused with a request for a GitHub repository.
--ref BRANCH
Starts on a branch or tag.
--no-connect
Creates the task and prints the next command without opening SSH.
--key PATH.pub
Uses an existing public key for the new task.
--forward-agent
Forwards your SSH agent. Off unless you ask for it.

Git credentials

If your computer is signed in to GitHub, the first time you use a project the CLI asks you to confirm the GitHub account and repository. It then hands your computer's credentials to the task over verified SSH, before the first clone. For a public repository the answer is optional: decline, or start without a terminal, and the task clones anonymously; the agent starts as usual, resume still retries a failed setup, and agents can push once you run microdev git connect ID. Your dotfiles repository is a project of its own: private dotfiles need consent even when the repository is public. For a task started from the browser, run microdev git connect ID in a terminal on your computer, approve the intended GitHub account and projects, then run microdev resume ID to complete private setup. Git credentials stay with the task, so an agent can keep working after your laptop disconnects. If a start stops because it needs Git consent, run microdev git connect ID in a terminal, answer y to each question, then rerun your start command. It asks about every project of the task that isn't connected to your local GitHub account: the repository and its dotfiles repository. On a paused task, git connect saves consent without resuming it; on a running task it hands the credentials over right away. Once you've connected Git, your task can push branches with your credential. Nothing pushes on its own: your agent does, or Create PR in the Mac app's Review. microdev git connect ENV_ID connects the task's projects, or changes their account after you sign in locally as another GitHub account; microdev git disconnect ENV_ID removes the connection of the task's repository and dotfiles. To invalidate every copy at once, revoke the token at GitHub.

Coding agents

Every task image includes the Codex, Claude Code and Pi CLIs, pinned, alongside Ubuntu 24.04, Git, SSH, Python, Node, compilers, tmux and ripgrep. Start one on a prompt when you create the task:

Your terminal
microdev start OWNER/REPO --agent codex --prompt "Fix the flaky retry test"microdev start OWNER/REPO --agent claude --prompt-file task.md --jsonmicrodev attach ID
--agent codex|claude|pi|custom
Starts that agent in a tmux session in the task's ~/workspace. custom is your own harness (below). Without --json the CLI attaches your terminal; detach with Ctrl-b d and the agent keeps working.
--prompt TEXT
The agent's first instruction. --prompt-file PATH reads it from a file (at most 32 KiB). Without either, the agent waits for input.
microdev attach ID
Reopens the agent this computer started in the task: it resumes a paused task and continues that agent's most recent conversation, with no picker. If Claude has no conversation yet, it opens fresh. For any other task, --agent codex|claude|pi|custom opens that agent fresh.

Connect each agent account once and every task starts signed in (in the Mac app: Settings → Agents). Codex uses your ChatGPT plan through microdev codex connect (the first --agent codex start asks for it), so Codex tasks work without you. Claude Code uses your Claude Pro or Max plan: run claude setup-token once, then paste what it prints into microdev agent connect claude -; an Anthropic API key works too. Pi reuses a login you make once with /login in any task: microdev agent reuse pi-anthropic|pi-codex|pi-copilot|pi-keys ID. Without a connection, run microdev attach ID and follow the agent's login in that task. You can also run codex, claude or pi yourself from microdev ssh ID.

Your own agent

--agent custom (Custom in the Mac app) runs any harness: the executable your task registers at ~/.config/microdev/custom-agent. MicroDev runs it in ~/workspace as custom-agent start PROMPT for a new task with a prompt, custom-agent open without one and custom-agent resume after a pause, with MICRODEV_MODEL set when the task chose a model. Register it, and install the harness, from your dotfiles init.sh:

init.sh
mkdir -p ~/.config/microdevcat > ~/.config/microdev/custom-agent <<'EOF'#!/bin/shcase "$1" in  start) exec opencode --prompt "$2" ;;  resume) exec opencode --continue ;;  *) exec opencode ;;esacEOFchmod +x ~/.config/microdev/custom-agent

Keep its sessions inside ~/workspace so they survive a pause, and list them in ~/.config/microdev/transcript-paths.json so its work keeps the task awake.

Claude Code runs with permission prompts off, like Codex. Pi never asks for tool approval. The task's VM is the boundary.

Model inference runs with the model provider. The agent, your builds and your tools run in the task. Model usage comes from your agent account and is not part of MicroDev compute.

Agent sign-ins, session history and settings survive pause and resume. Keyring credentials and environment variables do not. After a resume, microdev attach ID continues the most recent conversation of the agent this computer started.

Task lifecycle

Every task has an ID. These commands take it where it says ID.

microdev list
Lists your tasks with their IDs and states.
microdev status ID
Shows the state of one task. If setup failed, it names the step (the repository clone, the dotfiles clone, the dotfiles init.sh or the task configuration) and whether it failed or timed out.
microdev pause ID
Waits until the workspace is saved, then releases the compute.
microdev resume ID
Resumes a paused task or retries failed setup without opening a shell.
microdev ssh ID
Resumes the task first if it is paused, then opens a shell as soon as SSH is reachable, even if setup failed. It does not connect Git or retry failed setup. OpenSSH verifies the host key.
microdev attach ID
Resumes the task if paused, completes setup, then opens the agent's terminal.
microdev trial
Shows your remaining trial allowance.
microdev delete ID
Permanently deletes the task and its saved work.

Leaving SSH does not pause the task. exit disconnects your terminal and the task keeps running, so run microdev pause ID when you are done, or let auto-stop do it.

What persists

Every resume boots a fresh root filesystem around your saved work. The workspace and the agent state needed to continue come back; everything else is rebuilt from configuration.

Preserved

  • The whole workspace in ~/workspace, byte for byte: every branch, stash and commit, and staged, uncommitted, untracked and ignored files
  • Repository-local Git settings
  • Codex, Claude Code and Pi sign-in, session history and settings files
  • The task's Git credentials

Rebuilt on resume

  • The root filesystem: a fresh copy of the pinned system image, checked against its published SHA-256 digests
  • Installed packages, other home-directory files, shell history and global Git settings
  • Your dotfiles, cloned fresh, and environment variables
  • Agent logs, general caches and other agent files outside the kept list, running processes, tmux sessions, open connections and unsaved editor buffers

Keep task notes and any custom durable state inside ~/workspace, and save editor buffers before pausing. Resume never fetches, resets, cleans or checks out your workspace. Agent logs, general caches and other agent files outside the kept list are cleared on every resume; sign-in, session history and settings files are kept.

Dotfiles

Point MicroDev at a dotfiles repository that contains init.sh. It is cloned fresh and init.sh runs as dev in ~/.dotfiles, with HOME=/home/dev, when a task is created and on every resume. Failures and timeouts appear in microdev status.

Your terminal
microdev dotfiles your-org/dotfiles

After fixing your dotfiles, microdev resume ID retries setup, even on a running task and even when the repository clones without Git credentials. If a private project still needs Git consent, resume stops first and names microdev git connect ID. Write init.sh so it is safe to run again: a retry after failed setup can repeat work that partly finished. Teams can share a reviewed setup commit for each project; that takes precedence over personal dotfiles.

init.sh
#!/bin/shset -eu# Link rather than append, so a second run changes nothing.ln -sf "$HOME/.dotfiles/gitconfig" "$HOME/.gitconfig"

Auto-stop

A task pauses itself after 15 idle minutes, even with your agent open and your terminal or the Mac app attached. Idle means that in every minute of the window its processes used less than 2% of one vCPU, it moved data at 32 bytes a second or more for less than half of the minute (packet headers and your SSH sessions into the task excluded), nobody typed in its terminal, and no agent transcript changed. An agent waiting at its prompt, its own background refreshes (Codex checks its rate limits once a minute) and an attached terminal or Mac app nobody types into are quiet, so a finished agent's task pauses; the pause keeps the workspace and agent sessions.

Work counts even when it writes nothing: a build or test run spends CPU, and a download or a streamed model response keeps moving bytes, so an agent waiting on a long test suite is not mistaken for an idle one. What a rate cannot see is a tool that only sleeps or polls now and then, with no CPU and less than half of each minute on the network: it is paused like a finished agent. The Mac app's idle setting, below, raises the delay or turns auto-stop off. Missing activity data resets the idle window rather than pausing the task.

Agents that keep sessions somewhere else can report them. Write absolute paths to this file from your dotfiles hook:

~/.config/microdev/transcript-paths.json
["/home/dev/workspace/.agent-sessions"]

The delay is a Mac app setting: Settings, Task behavior, Pause when the task is idle for: never, 1, 5, 15 or 30 minutes, or 1, 2, 4 or 24 hours. It applies to every task the Mac app configures, from the next time the app applies that task's configuration. The CLI has no setting for it, and a task the Mac app has never configured uses 15 minutes. The setting arrives with the Mac app, which is not released yet; until then every task uses 15 minutes.

On the trial, a task also pauses when the trial's running time is used up. Activity does not extend it.

The free trial

New accounts get 5 agent-hours (300 minutes) of running time, for 14 days from your first launch, with up to 2 tasks running at once and up to 10 new tasks an hour. Resuming a paused task doesn't count against that (resumes have their own limit of 30 an hour). No card is collected and the trial never turns into a paid plan on its own.

The minutes are shared by all your trial tasks, and there is no limit per run. A task uses them only while it runs, including time spent waiting on tools and models; paused time is free. An attempt that fails before it starts uses no time. When the time or the window runs out, running tasks pause with their work preserved. Trial work is kept for 30 days after the trial ends.

Your terminal
microdev trial

Out of time? Choose a plan for your organization, or ask for manual pilot access.

Scripts and automation

--json works with list, status, create, start, demo, pause, resume and trial. With --json, start and demo never open a shell. create OWNER/REPO is the same as start OWNER/REPO --no-connect.

start --agent … --json returns as soon as the agent is running and adds an agent field, {"name": "codex", "terminal": "UUID"}. In status --json, a failed setup carries guest.setup_failure: a stage of repository, dotfiles, dotfiles_init or task_configuration, and an outcome of failed or timed_out.

Pass --request-id UUID to make creation idempotent: retrying with the same ID returns the same task instead of starting another, and never sends its prompt twice. Rerunning the same start command (same --request-id) is always safe: it resumes a paused task, finishes setup, and starts the agent once. If the agent already got the prompt, it reopens the agent instead. The CLI prints the request ID and task ID before it waits, then reports setup progress every 30 seconds. If setup is interrupted, inspect the task with microdev status ID.

Your terminal
request=$(uuidgen)microdev create OWNER/REPO --json --request-id "$request"# After a timeout, the same command finds the same task.microdev create OWNER/REPO --json --request-id "$request"
MICRODEV_CONFIG_DIR
Uses a different configuration directory, given as an absolute path. Useful for a separate CI identity.
--org UUID
Runs one command in another organization without changing the saved choice.

README badge

Add an Open in MicroDev badge to a repository's README. It carries the repository through GitHub sign-in into the new-task form. The person still chooses repository access and supplies an SSH public key before launching, so the link itself starts no compute.

Open in MicroDev
README.md
[![Open in MicroDev](https://microdev.dev/open-in-microdev.svg)](https://microdev.dev/start?repository=OWNER/REPO)

Replace OWNER/REPO with your repository. The hint stays in that browser tab for up to an hour. Try it with the sample repository.

Teams

Tasks and paid plans belong to an organization. For a team, create or select a shared organization before creating tasks. To synchronize its members from GitHub, install the MicroDev Identity GitHub App on your GitHub organization (GitHub shows it requesting read access to members, email, metadata and contents; MicroDev only reads the member list), then connect it.

Your terminal
microdev org create "Your team"microdev org use ORGANIZATION_UUIDmicrodev github connect YOUR_GITHUB_ORGmicrodev sync CONNECTION_UUID

org use saves your choice for later commands. microdev help advanced lists the organization, membership, corporate sign-in and GitHub connection commands.

Paid seats are pooled across the organization: each seat adds its tasks at once and its included agent-hours to one shared pool. Add seats any time on monthly and annual plans: you pay the prorated fee for the rest of the period and get a prorated share of that period's included hours right away. Usage prices and per-seat hours stay the same until renewal. Switching between monthly and annual takes effect at renewal. Team starts at 2 seats and includes usage by member and priority email support. Business starts at 5 seats and includes usage by member, corporate OIDC single sign-on and SCIM provisioning and A named support contact. Compare plans.

Shared project setup

Give everyone working on a project the same starting tools and configuration. An organization owner or admin chooses a GitHub setup repository and a reviewed commit. MicroDev runs its init.sh when a new task starts and whenever that task resumes. Members start tasks normally; the organization selects the setup for them.

Use a CLI that lists setup show and setup publish in microdev help advanced. Setup also needs to be enabled for your organization. If these commands are unavailable, contact support before configuring a project.

1. Prepare a setup repository

Create a GitHub repository such as acme/development-setup and put init.sh at its root. Start with this example for a Node project. It writes a non-secret configuration file and installs a helper; the helper runs the project's locked dependencies and tests only when someone calls it.

acme/development-setup · init.sh
#!/usr/bin/env bashset -euo pipefailinstall -d "$HOME/.config/acme" "$HOME/.local/bin"printf '%s\n' '{"color": true}' > "$HOME/.config/acme/tooling.json"cat > "$HOME/.local/bin/project-test" <<'SH'#!/usr/bin/env bashset -euo pipefailcd "$HOME/workspace"npm cinpm testSHchmod 0755 "$HOME/.local/bin/project-test"

Adapt the script to your project. It runs with Bash as dev, from ~/.dotfiles, with HOME=/home/dev and sudo available inside the task. The image already includes Git, Node, Python and compilers. Install additional tools here, pin their versions and verify downloaded releases. The whole script must finish within 10 minutes and be safe to rerun after partial failure. Prefer replacing files or creating directories to repeatedly appending to files.

Commit and push the script through your normal review process. From the setup repository, copy the full commit ID:

Inside your setup repository
git rev-parse HEAD

Use the reviewed, pushed commit's full 40-character lowercase ID. Branch names, tags and abbreviated IDs are not accepted. Keep that commit reachable in the setup repository: existing tasks will need it again on resume.

2. Select the team and publish

List your organizations and choose the shared team before publishing. org use saves the choice for later commands; --org ORGANIZATION_UUID selects it for just one command.

Your terminal
microdev orgsmicrodev org use ORGANIZATION_UUIDmicrodev org showmicrodev setup show > setup.json

Edit setup.json. Keep the returned revision unchanged and add your project to projects. A new organization starts at revision 0. Replace the names and example commit below with your own.

setup.json · example for a new configuration
{  "revision": 0,  "projects": [    {      "repository": "acme/service",      "dotfiles_repository": "acme/development-setup",      "dotfiles_commit": "0123456789abcdef0123456789abcdef01234567"    }  ]}

repository is the project members work on. dotfiles_repository is the setup repository containing init.sh; it may be shared by several projects. dotfiles_commit pins that setup repository, independently of the project's branch. GitHub repository names are matched without regard to letter case.

Your terminal
microdev setup publish setup.jsonmicrodev setup show

A successful publish prints the saved configuration with its new revision. Publishing replaces the entire project list. Preserve entries you still need. By default owners and admins can publish; owners, admins and members can read. Your organization's access policy can change these permissions.

3. Start a task as a team member

Your terminal
microdev --org ORGANIZATION_UUID start acme/servicemicrodev --org ORGANIZATION_UUID status TASK_ID --json

No --dotfiles flag is needed. The task uses the published setup instead of your personal dotfiles for that project. Supplying a different --dotfiles repository is refused. Projects with no organization entry keep their usual personal setup. In the task, the sample helper is ~/.local/bin/project-test.

In the Mac app, a personal or project dotfiles setting can conflict with the organization's setup. Clear it in Settings → Setup → Dotfiles and remove any project dotfiles override before launching. If a pending launch already failed with that conflict, dismiss it and start a new task after changing the setting; Retry retains the original launch inputs.

Status JSON includes project_setup, with the selected configuration revision and setup commit. This selection belongs to the task: pausing and resuming keeps the original commit, even after an admin publishes an update or removes the project entry. A new task uses the current configuration. Create a new task to adopt a new setup commit; resume does not silently update it.

Each member needs GitHub access to both the project and the setup repository. Private repositories use the usual local Git credential connection and consent. A public project with private setup still needs consent for that setup repository. Publishing a setup entry does not grant GitHub access or narrow the permissions of your Git token.

Update, remove and retry a publication

For an update, review and push another setup commit, then run microdev setup show > setup.json again. Change the affected dotfiles_commit, keeping the returned revision and the other project entries, and publish. To remove a project's shared setup, delete its entry from that freshly read list and publish. To remove all entries, keep the current revision and set projects to []. Removal changes future tasks; existing tasks retain their recorded setup.

If another admin publishes first, your older revision is rejected. Read the current configuration, reapply your intended change, and publish again. Do not guess a newer revision: that could overwrite another admin's work.

The CLI prints a request UUID when it publishes. If the response is lost, retry with the unchanged file and that UUID:

Your terminal
microdev setup publish setup.json --request-id REQUEST_UUID

The retry returns the original publication, even if a newer revision now exists. It does not replace that newer revision. Run setup show to see what is current. Use a new request UUID for a different change.

When setup does not complete

Access denied
Confirm the organization with microdev org show and ask an owner to check your role and setup permissions. Existing organizations may need an administrator to enable setup in their access policy.
Git consent required
Run microdev git connect TASK_ID in a terminal, approve the intended GitHub account and repositories, then rerun your original start with the same request ID or run microdev resume TASK_ID.
Setup commit unavailable
Verify that the recorded commit still exists and is accessible in the setup repository. MicroDev fails setup rather than using the latest branch. Restore access to that commit to resume this task; publishing a replacement commit only affects new tasks.
init.sh failed or timed out
Inspect microdev status TASK_ID and ~/.microdev-init.log inside the task using microdev ssh TASK_ID. Retry transient failures with microdev resume TASK_ID. For a script fix, publish the corrected commit and start a new task; an existing task stays pinned.
Configuration rejected
Use valid JSON, GitHub repository names, a full lowercase 40-character commit and the revision from setup show. Each project may appear once; at most 100 projects and 128 KiB of JSON are accepted.

What you can customize

Use the script for tool installation, non-secret settings, shell helpers and project prerequisites. The saved workspace and supported agent state survive pause; packages and other root/home files are rebuilt by setup. Avoid resetting the workspace or overwriting agent state from init.sh. Pinning the script pins its source: dependencies downloaded from mutable URLs still need their own version pins.

Setup does not lock down what an agent can run or install afterward. It does not add a secrets store, private networking, Internet restrictions or custom VM images. Keep shared credentials out of both setup.json and the setup repository. Agent sign-in and the Mac app's local settings keep their existing behavior. There is no setup editor in the dashboard; administrators publish through the CLI.

An organization supports 100 project entries and 10,000 publications. Each accepted publication advances its revision; contact support if the publication limit is reached.

Billing from the CLI

Owners, admins and billing members manage an organization's plan. Payment details stay on Stripe's hosted pages. See pricing for what the plans include. Usage is counted in agent-hours: one 2-vCPU task running for one hour. A boosted task counts max(vcpus / 2, memory_mib / 2048) agent-hours for each hour it runs boosted.

Your terminal
microdev org use ORGANIZATION_UUIDmicrodev billing plansmicrodev billing subscribe PLAN SEATSmicrodev billing setupmicrodev billing status

setup prints the payment setup link. Finishing that page does not turn the plan on by itself: the plan starts once the opening invoice is paid and verified. status shows where it stands.

microdev-pro-v2
Pro: $29 per seat per month, 1 to 500 seats. Annual: microdev-pro-annual-v1, $290 per seat per year.
microdev-team-v1
Team: $59 per seat per month, 2 to 250 seats. Annual: microdev-team-annual-v1, $590 per seat per year.
microdev-business-v1
Business: $119 per seat per month, 5 to 125 seats. Annual: microdev-business-annual-v1, $1,190 per seat per year.
microdev-payg-v1
Pay as you go: no monthly fee, card required, $1.25 per agent-hour. For one person: one seat, 2 tasks at once.

If a completed pause loses committed, uncommitted or untracked work in your workspace, that billing period’s subscription fee is credited against your next renewal (a month’s fee on monthly plans, the year’s on annual plans). It covers files saved to the workspace when a pause completes. Running processes stop, and files outside the workspace start fresh on resume, as the persistence contract says. Tell support. The credit covers the plan fee only, not usage above the allowance or seats added mid-period, applies once per billing period, and needs a subscription that renews. Pay as you go has no subscription fee, so it isn’t covered.

billing quote PLAN SEATS
Prints the exact additional charge for more seats now.
billing upgrade PLAN SEATS CENTS
Adds that capacity once the quoted payment is verified. Current capacity stays if it fails.
billing seats COUNT
Changes the seat count from the next billing period.
billing plan PLAN
Changes the plan from the next billing period.
billing cancel
Cancels at the end of the paid period. billing renew undoes it.
billing invoices
Lists invoices. billing invoice ID shows one.
billing usage
Team and Business owners, admins and billing members: each member's agent-hours this period. Add a period start to see a past one. Members add up to the organization total the invoice is rated on.
billing portal
Prints a link to your payment methods on Stripe.
billing unassign USER_ID
Frees a seat. Only possible once that person has no running tasks.

microdev billing --help lists every billing command.

Mac app

The Mac app is coming soon; until it is released, use the CLI. The native app supports Apple Silicon and macOS 14 or later, and bundles its helpers so you do not need a separate CLI installation.

The Mac app is the same product in a native window. It uses the same Rust client library and service APIs as the CLI, so it sees the same account, organizations and tasks, and it shares local Git connections with the CLI. Creating, resuming or opening a task in the app synchronizes its Git credentials, as CLI start, resume and attach do. Explicit CLI ssh remains available without Git consent so you can inspect a failed setup. Nothing on the server is specific to the desktop.