# How a session works

A session is a Mac of your own in the cloud, for as long as the task takes. Your agent starts it, works on it and stops it, and then it is deleted.

## Start, work, stop

Terminal

```
nomac start
nomac exec --wait 600 -- xcodebuild -scheme App build
nomac stop
```

Start `start_mac`, `nomac start` or `POST /api/v1/mac/sessions`. The Mac is usually ready within a minute. Waiting is free; billing starts when it is ready.

Work Run commands (`exec_mac`, `nomac exec`), move files, open a shell with `nomac ssh`, and see the screen. Commands can run side by side.

Stop `stop_mac` or `nomac stop`. The Mac and its files are deleted, except the drive at `~/drive`. A Mac also stops at its time limit, its spend cap, its idle timeout or when the credit runs out.

## What is on the Mac

System macOS 26.6.2, Xcode 27.0, iOS 27.0 Simulator, on Apple silicon.

Tools Node 24.20.0, npm 11.19.0, Ruby 3.4.11, Bundler 4.0.23, CocoaPods 1.17.0, xcbeautify 3.2.1, XcodeGen 2.46.0, Git 2.54.0, Git LFS 3.8.0, GitHub CLI 2.100.0, jq 1.7.1, Python 3.14.7, uv 0.13.0, simulator-use 0.15.1, nvm 0.40.8, Swift 6.4, Homebrew 7.0.11, on every path.

Anything else Homebrew belongs to the agent, so `brew install` works.

`get_mac_session` returns the same list, and `~/NOMAC.md` on the Mac describes the machine.

## Fully enabled for your agent

Nothing on the Mac waits for a person. The agent is an administrator, `sudo` asks for no password, and the login password is in `$NOMAC_MAC_PASSWORD` for the keychain and anything else that asks. Privacy prompts and password dialogs are answered within seconds, and the screen never locks.

Safety comes from isolation instead: the Mac is yours alone, has no public address, cannot reach another customer's, and is deleted when it stops. To keep macOS's usual prompts, start with `access: { prompts: "ask" }` or `nomac start --prompts ask`.

## Drives

Every Mac gets a 20 GB drive at `~/drive`, kept between sessions and saved when the Mac stops. Keep projects in `~/drive/src/<repo>`: their build caches (DerivedData, Swift packages, CocoaPods, npm) are kept with them, so the next session rebuilds only what changed. Saving is automatic and free.

A drive is on one Mac at a time, so two Macs never write the same files. One Mac gets the account's default drive. A Mac started while another has the default gets a new drive of its own (`drive-2`, `drive-3`), and its answer names it. To keep agents' work apart, name a drive at the start: `access: { drive: "feature-x" }` or `nomac start --drive feature-x`. It is made empty the first time; add `drive_from: "default"` (`--drive-from default`) to start it as a copy of another drive's last save. If that drive is on a running Mac, the start says which, and `reuse: true` gives you that Mac.

An account keeps up to 10 drives. A new one past that replaces the least recently used drive: one NoMac made first, never the default or one in use. A drive is deleted after 90 days unused (30 for one NoMac made). `nomac drive` lists them.

Keep the drive under 10 GB: a Mac that does not hold it yet downloads all of it before it boots. `nomac-drive clean` removes build products unused for 14 days. Keep your source in git too: the drive is a cache, not a backup.

## Long commands and lost answers

- A command answers within its wait: up to 40 seconds over MCP (wait_seconds), 10 minutes with `nomac exec --wait 600`. One still running becomes a job. Follow it with `get_mac_job` or `nomac job ID`, and never run it again.
- Every start and command takes a `request_key`. After a lost answer, repeat the call with the same key and arguments: you get the same Mac or job back, never a second one.
- A command ends with everything it started. A server the Simulator should reach keeps running with `nomac-service start api -- npm run dev`.

## Time and cost

$0.90 an hour of ready time, billed per minute. A session runs 2 hours by default and up to 8. In its last 15 minutes, its answers carry `stop_notice`; `extend_mac` or `nomac extend 60` adds time. See [Pricing](/content/docs/pricing/index.html) and [Limits](/content/docs/limits/index.html).
