Home / Alt manpages / gh-codespace(1)

  • gh-codespace(1)
  • User command
  • linux

A Safe gh codespace Workflow from Create to Cleanup

You will create a GitHub Codespace, find its generated name, connect to it, copy a file, and stop or delete it when you are finished. The examples use GitHub CLI 2.87.3, installed on this machine, and the gh codespace command group. Allow about fifteen minutes, plus however long the Codespace provisioning step takes.

You need GitHub CLI, a GitHub account with Codespaces access, and a repository you are allowed to use. Authenticate once with gh auth login if this machine is not already signed in. That command changes your local GitHub CLI authentication state, so follow its prompts carefully and never paste a token into a shell history or a support request. None of the examples below needs sudo.

1. Check the local command and authentication

Confirm the installed version and ask the command group for its available operations:

$ gh --version
gh version 2.87.3 (2026-02-23)
$ gh codespace --help

The group also has the short alias gh cs. Use the longer form in scripts and notes because it is easier for someone else to recognise. Check authentication before creating anything:

$ gh auth status
$ gh codespace list

Checkpoint: you should see either an empty list or the Codespaces you already own. The list command defaults to at most 30 entries. If there is more than one result, record the exact name shown in the first column. Most later commands let you omit --codespace, but that starts an interactive selection and is an easy place to act on the wrong resource.

2. Create one Codespace deliberately

Creating a Codespace provisions a remote development environment and may consume an allowance or incur charges. Check the repository and branch before you run it. Replace both placeholders with real values:

$ gh codespace create --repo OWNER/REPOSITORY --branch BRANCH

The installed command also accepts --machine, --location, --idle-timeout, --retention-period and --devcontainer-path. Leave those defaults alone until you have a concrete reason to change them. A retention period controls how long a stopped Codespace remains before automatic deletion, with a maximum of 30 days in this version of the command. --web creates it from a browser and cannot be combined with display name, idle timeout or retention period.

Capture the name from the creation output, then verify it without changing state:

$ gh codespace list --repo OWNER/REPOSITORY
$ gh codespace view --codespace CODESPACE_NAME

Use the exact value shown for CODESPACE_NAME, not the display name. If you lose it, list the repository again rather than guessing.

3. Open a shell in the Codespace

SSH is useful for a repeatable terminal workflow. The Codespace must have an SSH server. GitHub's default image includes one; a custom image may need the SSHD dev container feature or an equivalent setup in its own configuration.

$ gh codespace ssh --codespace CODESPACE_NAME

On the first connection, gh can create a key pair under ~/.ssh if it cannot find a suitable existing key. That is a local file change, so check your SSH directory and key policy first. To run one remote command and return, put the command after --:

$ gh codespace ssh --codespace CODESPACE_NAME -- pwd
/workspaces/REPOSITORY

The path is an example: your repository name and working directory can differ. A non-zero status means the connection or remote command failed; it does not mean the Codespace was deleted.

4. Copy files without accidental shell expansion

gh codespace cp treats a path beginning with remote: as a path on the Codespace, relative to the remote user's home directory. Copy a local file to the remote workspace like this:

$ gh codespace cp ./README.md remote:/workspaces/REPOSITORY/

Copy in the other direction by putting the remote path first:

$ gh codespace cp remote:/workspaces/REPOSITORY/README.md ./README.remote.md

Directories require --recursive:

$ gh codespace cp --recursive ./local-config remote:/workspaces/REPOSITORY/

Remote names are literal by default. The --expand option evaluates a remote path like an scp shell expression, including globs, variables and backticks. Do not use it with paths supplied by another person or an untrusted script. Quoting protects your local shell, but it does not make an expanded remote expression safe.

5. Stop work, then remove only what you mean

Stopping releases the running compute but keeps the Codespace for later use:

$ gh codespace stop --codespace CODESPACE_NAME
$ gh codespace view --codespace CODESPACE_NAME

Stopping is the normal end-of-session action. It is reversible: start or open the Codespace again through the GitHub interface or an applicable gh codespace command.

Destructive action

Deletion removes the Codespace. Check its name and any uncommitted or unpushed work first:

$ gh codespace view --codespace CODESPACE_NAME
$ gh codespace delete --codespace CODESPACE_NAME

The delete command asks for confirmation when unsaved changes are present. Do not add --force merely to make a script non-interactive. There is no local undo command for a deleted Codespace. Preserve work in Git or copy required files out before deletion. Avoid --all and --days unless you have reviewed exactly which Codespaces match.

6. Diagnose the common traps

  • An interactive prompt usually means you omitted --codespace. Cancel with Ctrl-C if you cannot identify the selected resource.
  • A missing SSH server is a Codespace image or configuration problem. It is not fixed by changing the local SSH key.
  • A failed copy involving a directory usually means --recursive was omitted.
  • An unexpected file list can come from --expand. Remove that option and quote literal paths.
  • A stopped Codespace is not deleted. List it and inspect its state before creating a replacement.

Done means

  • gh auth status succeeds for the intended GitHub account.
  • You recorded the exact Codespace name and checked its repository and state.
  • You connected or copied files using explicit paths.
  • You stopped the resource when finished, or verified its data was preserved before deletion.
  • No command used elevated privileges, --all, --force or untrusted remote expansion casually.