Skip to content

Run & observe

When you need this: you (or your agent) need the system actually running to see a change work — not just unit tests passing.

Bring the stack up

mship run

run starts the task's services in dependency order, waiting on each repo's healthcheck before starting its dependents — tcp, http, sleep, or a custom task, declared per repo in mothership.yaml (Configuration). Long-running services (start_mode: background) stay alive so you can interact with them.

Ports and URLs are task-scoped: two tasks running in parallel don't fight over localhost:3000. Filter to part of the stack with --repos:

mship run --repos api,svc-users

Build artifacts

mship build

Same dependency ordering, running each repo's build target — schemas generate before the services that import them compile.

See what's real

The observation commands answer questions agents otherwise guess at:

mship status      # active task, phase, branch, per-repo test results, drift
mship context     # full JSON snapshot of workspace state (built for agents)
mship journal     # the task's log: what was done, when, why
mship graph       # the repo dependency graph
mship worktrees   # every active worktree, grouped by task

All of these emit JSON when stdout isn't a TTY (or with mship --json …), so an agent gets structured answers — which log belongs to which service, which URL to hit, which test command runs where — without find/ps/lsof archaeology.

Capturing what's on screen

For UI repos, mship capture drives the repo's capture target (simulator screenshots, layout dumps) and files artifacts under .mothership/captures/<task>/.

Promoting a capture to evidence

Most captures are part of the develop–verify–iterate loop: screenshot, look, adjust, capture again. Those stay ephemeral — mship capture writes them under .mothership/captures/, which is gitignored, and nothing else happens.

Passing --evidence <spec-id>:<criterion-id> promotes a capture into durable evidence for that acceptance criterion:

mship capture --evidence my-spec:ac3

The artifact is copied into .mothership/evidence/<spec-id>/ under a content-hashed name, attached to the criterion as kind=artifact, and recorded with the revision it was taken from — marked when that revision is an uncommitted working tree, and separately marked when the revision itself is not a commit on any branch (a detached HEAD, or a throwaway ref materialized for a remote capture), so a reviewer can tell work-in-progress or throwaway evidence from a screenshot taken at a real, committed revision. Both markers can appear together.

The store is machine-local and gitignored, so it behaves identically whether your workspace is a metarepo, a monorepo, or a single repo — nothing is ever committed into your product's history by capturing evidence.

Artifacts are capped at 8 MiB each — a phone fetches these over the relay, and a screenshot or layout dump larger than that is a capture bug, not evidence. An over-cap artifact is refused when it is stored (the capture itself still succeeds) and refused again if one ever reaches the store another way.

What travels: the phone fetches evidence from mship serve over the relay. The PR body embeds it when the bytes are fetchable on GitHub, which means evidence_storage: published and the bytes actually on a ref GitHub serves. You do not have to arrange that second half: under published storage mship finish publishes the referenced artifacts to an mship-evidence orphan branch in the repo the pull request targets, and embeds a raw URL pinned to that branch's commit.

An orphan branch shares no history with your default branch, so the binaries never enter main's tree and a clone of the product is unaffected. finish pushes that branch and nothing else — never main, never your workspace repo — and when a task spans several repos, each repo that gets a PR publishes to its own branch, so every PR is self-contained. Published artifacts accumulate on the branch; nothing prunes them for you.

The publication is built with git plumbing, not a checkout, so your working tree, index, HEAD and branches are untouched: work you have in flight — untracked, edited, or already staged — cannot be swept into it. Nothing is forced: a rejected push, an unreachable origin, or a repo with no GitHub origin all stop the publish rather than push past it.

Every failure there degrades and none of them block the PR: finish warns, names the artifact instead of embedding it, and carries on opening the PR. It also warns under local or encrypted storage, where the bytes are not on GitHub in readable form at all and nothing is published.

What does not travel: secrets, platform state, and anything else git cannot carry.

Running on another machine

A run target that needs hardware you don't have (an iOS simulator on a Mac, an Android box, a beefier builder) can execute on a run host:

mship run --remote=ios-sim-host

Same commands, same env contract, output streamed back live. Setup and troubleshooting: Remote run.