Guides

How to Debug GitHub Actions with Breakpoint

When a GitHub Actions workflow fails, your options are limited: read the logs, add more logging, push a new commit, and wait for the job to run again. For failures that are hard to reproduce or depend on the runner environment, this loop can be time consuming.

Breakpoint is a GitHub Action that gives you a faster path. It pauses a running workflow and opens an SSH connection to the runner, so you can inspect the environment directly while the job is still active. The action is compatible with any runner and also available outside of Namespace.

This guide covers how it works and how to use it.

How Breakpoint Works

When a breakpoint step runs, it starts an SSH server on the runner and prints a connection string to the workflow log. You connect from your local machine, get a shell inside the runner, and can look around, check files, run commands, inspect environment variables, whatever you need. When you're done, you either resume the workflow from within the session or wait for the timeout to expire.

The SSH connection is authenticated using the public keys already associated with your GitHub account, so there's nothing extra to configure on your end.

A Note on CI Minutes

Every minute a breakpoint session is active is a minute your workflow is running. If you set a 30-minute duration and step away, that's 30 minutes of CI time consumed even if you weren't actively debugging. Keep sessions short, and resume the workflow as soon as you're done.

Basic Setup

Add the action as a step in any workflow:

- name: Breakpoint if tests failed
  if: failure()
  uses: namespacelabs/breakpoint-action@v0
  with:
    duration: 30m
    authorized-users: your-github-username

When this step runs, the workflow log will show something like:

┌───────────────────────────────────────────────────────────────────────────┐

 Breakpoint running until 2024-06-01T16:06:48+02:00 (29 minutes from now). │

 Connect with: ssh -p 40812 runner@rendezvous.namespace.so

└───────────────────────────────────────────────────────────────────────────┘

Run the ssh command from your terminal to connect. The workflow resumes automatically once the session ends or the duration expires.

Usage Patterns

Pause only when something fails

The most common pattern is to add a breakpoint that only activates on failure, so it doesn't interrupt successful runs:

steps:
  - name: Checkout
    uses: actions/checkout@v4
 
  - name: Run tests
    run: go test ./...
 
  - name: Breakpoint if tests failed
    if: failure()
    uses: namespacelabs/breakpoint-action@v0
    with:
      duration: 30m
      authorized-users: alice, bob

The if: failure() condition means this step is skipped unless a previous step has failed.

Pause at a specific point

If you know where in the workflow you want to investigate, place the breakpoint step there:

steps:
  - uses: actions/checkout@v4
 
  - name: Build Docker image
    run: docker build -t myapp .
 
  - name: Pause to inspect the build
    uses: namespacelabs/breakpoint-action@v0
    with:
      duration: 20m
      authorized-users: alice
 
  - name: Run integration tests
    run: ./run-tests.sh

The workflow pauses after the build and waits for you to connect before moving on to the tests.

Run in the background

In background mode, the workflow continues running while the SSH server stays available in the background. This is useful when you want the option to connect during a long-running step without blocking progress.

steps:
  - uses: actions/checkout@v4
 
  - name: Start Breakpoint in background
    uses: namespacelabs/breakpoint-action@v0
    with:
      mode: background
      authorized-users: alice
 
  - name: Run build
    run: make build

If you're connected when the workflow finishes, the session stays open until you disconnect.

One thing to keep in mind: the background breakpoint captures the environment at the point it's started. Environment variable changes made in later steps won't show up in your SSH session.

Configuration Options

InputDefaultDescription
modepausepause halts the workflow until you resume or the duration expires. background runs the SSH server without blocking.
duration30mHow long the breakpoint stays open. Only applies to pause mode. Accepts values like 30m, 1h, 2h30m.
authorized-users(none)A comma-separated list of GitHub usernames. The action fetches their public keys from GitHub automatically.
authorized-keys(none)A comma-separated list of raw SSH public keys. Use this instead of (or in addition to) authorized-users.
slack-announce-channel(none)A Slack channel to notify when a breakpoint starts. Requires a SLACK_BOT_TOKEN environment variable.
shell/bin/bashThe login shell for the SSH session.
endpointrendezvous.namespace.so:5000The rendezvous server used to broker the SSH connection. You can host your own if needed.

You must provide at least one of authorized-users or authorized-keys. The action will fail without them.

More Debugging Options on Namespace Runners

If you're running workflows on Namespace runners, several more debugging tools are available beyond breakpoint.

Pause a job from the dashboard

You can pause a running job and open a terminal session directly from the Namespace dashboard. Navigate to the job in the dashboard, click the Troubleshoot button on any currently running step, and a browser-based terminal opens inside that step's environment. The current step continues executing, but the workflow won't advance to the next step until you end the session and click Resume.

If a session is open but idle, the workflow resumes automatically after 10 minutes.

This is available for Linux-based jobs.

SSH directly into the runner

If you need access to the runner outside of a paused step (to inspect something mid-job without stopping it, for example), you can SSH in directly. First, find the instance ID from the Set up job step in your workflow logs, where it appears in the runner name as nsc-runner-<instance-id>. Then connect using the Namespace CLI or native SSH:

nsc ssh <instance-id>
 
# or with native SSH:
ssh <instance-id>@ssh.<region>.namespace.so

SSH access works on Linux and macOS runners. Native SSH access is not enabled by default — contact support@namespace.so to enable it for your workspace.

Remote display (VNC and RDP)

For macOS runners, Namespace supports VNC access so you can see and interact with the graphical environment of the runner. For Windows runners, RDP is available. Both can be started from the dashboard or via the CLI:

nsc vnc <instance-id>   # macOS
nsc rdp <instance-id>   # Windows

Performance metrics and logs

The Namespace observability dashboard surfaces per-job resource metrics (CPU, memory, disk I/O, and network) correlated with workflow steps, making it easier to identify which step is responsible for a spike. It also retains container logs (including logs from containers running inside your workflow) and links any Docker builds to their full build logs and traces.

Namespace also includes automatic out-of-memory (OOM) detection, which flags jobs that hit memory limits clearly rather than leaving you to infer it from metrics.

Crash dump collection

Namespace can automatically detect job crashes, collect crash dumps, and store them as artifacts for later inspection. This is not enabled by default. Contact support@namespace.so to enable it.

Further Reading

Accelerate your developer team

Join hundreds of teams using Namespace to build faster, test more efficiently, and ship with confidence.