Why does Grain say the remote workspace changed?
Another client changed the remote state after your folder last synchronized. Pull, review the local result and push again.
Grain / Docs / Troubleshooting
Docs
Start Grain troubleshooting with the doctor output, then match the failure to authentication, workspace selection, file synchronization, runtime type or desktop handoff. The recovery commands below preserve local work unless a force or discard option explicitly says otherwise.
grain doctor [path]
grain statusThe doctor command accepts one optional path and no flags. It prints cli, auth, api, session, token expiry, link and remoteRoot lines. Status has no flags and reports login, resolved workspace, local root and sandbox state. Doctor rejects flags with Unknown doctor option: <option> and multiple paths with Usage: grain doctor [path]. Status rejects arguments with Unknown status option: <option>.
grain loginLogin has no flags. It hands authentication to the Mac app and prints the path where the revocable CLI token was saved. If any option is supplied, it reports Unknown login option: <option>. Start the Mac app, complete sign-in and rerun the original command.
grain pull [--force]
grain push [--force] [--no-reload] [--dry-run]The remote workspace changed since this folder was last synchronized., do not force immediately. Pull first, review the resulting local files and preserve the edits you want.--force. Normal output reports remote changes pulled, local paths deleted and local changes preserved. When another client holds the workspace lease, pull identifies the active sync client.--force, --no-reload and --dry-run. A successful retry prints pushed <n> path(s). Use --dry-run to see proposed paths; use --no-reload when an open workspace should not refresh.--force only when you intentionally overwrite remote drift. The failure action explicitly recommends pull, review and retry first.grain upgrade [--target react-vite|nextjs]Upgrade accepts only --target, with react-vite or nextjs; React with Vite is the default. It promotes a clean, pushed HTML workspace to an app runtime and does not update the CLI. Invalid targets return Usage: grain upgrade [--target react-vite|nextjs]. Local edits return This checkout has local changes that are not in the active managed-content revision. Push them first. Remote drift requires a pull and review. A workspace that already has a runtime reports This workspace already has an app runtime.
grain open
grain refresh [path]Open has no flags and reports that the desktop app was asked to open the selected workspace id. Refresh accepts one optional path and no flags, then reports that the app was asked to refresh previews for that workspace. When the desktop handoff is unavailable, both direct you to start the app and retry. Extra arguments return Usage: grain open or Usage: grain refresh [path].
grain start [path] [--foreground] [--restart] [--no-pull] [--continue|--abort] [--no-open] [--debounce-ms <n>] [--push-interval-ms <n>]
grain stop [path]Start accepts --foreground, --restart, --no-pull, --continue, --abort, --no-open, --debounce-ms and --push-interval-ms. Healthy output reports the path watched by continuous sync. Use --restart when a stale daemon must be replaced. --continue and --abort are mutually exclusive; negative debounce and nonpositive interval values are rejected. Checkout-mode folders report Continuous sync cannot run from a checkout folder. Use explicit push and pull there. Stop accepts one optional path and no flags; checkout mode reports A checkout folder does not run the continuous sync daemon.
grain release [--dry-run]
grain checkouts list
grain checkouts remove <workspace-id> [--discard] [--dry-run]Release accepts --dry-run and removes only a clean, validated checkout. Expected output is Removed checkout <id> at <path> or its Would remove preview. The checkouts list subcommand has no flags. Checkouts remove accepts --discard and --dry-run. If it reports Checkout <id> has unpushed changes., push the checkout or rerun with --discard only when those changes are intentionally abandoned. Repeating a dry-run flag reports Use --dry-run only once.
--json and --workspace <id> belong before it.Missing value for <flag>, provide a value that does not begin with another option marker.Another client changed the remote state after your folder last synchronized. Pull, review the local result and push again.
Static HTML workspaces have no compute runtime. Push a clean checkout and promote it only when the artifact needs an app runtime.
The desktop handoff is unavailable. Start the Mac app and retry open or refresh.
The safe commands refuse by default. Push wanted work first; use discard only when you deliberately want to abandon the local changes.
Run the diagnostic commands, preserve local edits and apply the recovery for the exact error code or message.
Free forever. No card. Bring your own agent.