---
title: "Wire the Sandbox Workflow"
description: "Replace the \"would review\" placeholder with the real thing. Import `runSandboxLifecycle` from Chapter 1, call it after the URL passes validation, and print the structured result."
canonical_url: "https://vercel.com/academy/vercel-sandbox/wire-the-sandbox-workflow"
md_url: "https://vercel.com/academy/vercel-sandbox/wire-the-sandbox-workflow.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-05-17T07:21:09.299Z"
content_type: "lesson"
course: "vercel-sandbox"
course_title: "Vercel Sandbox"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# Wire the Sandbox Workflow

# Wire the Sandbox Workflow into the CLI

We have two pieces. A lifecycle function that does the work, and a CLI that knows when to do it. Time to connect them.

This is one of those lessons where the code change is small but the moment is big. The first time you run `pnpm review <url>` and watch it boot a Sandbox, clone the repo, and print back a structured result is when the project stops feeling like a tutorial and starts feeling like a tool.

## Outcome

Replace the `console.log` placeholder in the `action` callback with a real call to `runSandboxLifecycle`, and print the returned result.

## Fast Track

1. Import `runSandboxLifecycle` from `./sandbox-lifecycle`.
2. Call it inside the validated `action` callback.
3. Log the structured result.

## Hands-on exercise

Open `src/cli.ts` and add the import:

```ts
import { Command } from 'commander';
import { runSandboxLifecycle } from './sandbox-lifecycle';

function isValidGitHubRepoUrl(input: string): boolean {
  return /^https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/?$/.test(input);
}

const program = new Command();

program
  .name('repo-review')
  .description('Clone and review a GitHub repository in a Sandbox')
  .version('0.1.0');

program
  .command('review <repoUrl>')
  .description('Run a Sandbox review against a GitHub repository URL')
  .action(async (repoUrl: string) => {
    if (!isValidGitHubRepoUrl(repoUrl)) {
      console.error(`Invalid GitHub repository URL: ${repoUrl}`);
      console.error('Expected format: https://github.com/<owner>/<repo>');
      return;
    }

    console.log(`Reviewing ${repoUrl}...`);
    const result = await runSandboxLifecycle(repoUrl);

    console.log(`Sandbox: ${result.sandboxId}`);
    console.log(`Clone exit code: ${result.cloneExitCode}`);
    console.log(`Files:\n${result.files}`);
    console.log(`README preview:\n${result.readmePreview}`);
  });

program.parse();
```

Notice we're not catching the error from `runSandboxLifecycle` yet. If the clone fails, the function throws, and we'll see an unhandled rejection in the terminal. We'll fix that in the next lesson when we add real exit-code handling. For now, the happy path is the goal.

Also: since `runSandboxLifecycle` is no longer being called from the bottom of `src/sandbox-lifecycle.ts`, you can delete the temporary `main()` test caller we added in lesson 1.4. The CLI is the real caller now.

\*\*Warning: Troubleshooting: import path\*\*

TypeScript imports omit the `.ts` extension (`./sandbox-lifecycle`, not `./sandbox-lifecycle.ts`). If you see "cannot find module", drop the extension.

\*\*Note: Troubleshooting: output too noisy\*\*

Logging the full `ls -la` output is verbose. That's fine for now since we're confirming the wire is connected. We'll trim what gets printed when we add the proper reporter in Chapter 5.

## Try It

```bash
pnpm review https://github.com/vercel/examples
```

Expected output:

```txt
Reviewing https://github.com/vercel/examples...
Sandbox: sbx_7N2k4A...
Clone exit code: 0
Files:
total 32
drwxr-xr-x  ... README.md
drwxr-xr-x  ... examples
README preview:
# Vercel Examples

This repository contains...
```

That's the whole first half of the course in one CLI invocation. Validation, Sandbox boot, clone, file inspection, clean shutdown.

## Commit

```bash
git add src/cli.ts src/sandbox-lifecycle.ts
git commit -m "feat(cli): wire sandbox lifecycle into the review command"
```

## Done-When

- [ ] CLI imports `runSandboxLifecycle` from `./sandbox-lifecycle`
- [ ] Valid URL triggers a real Sandbox run
- [ ] Invalid URL still exits early without booting a Sandbox
- [ ] Result fields (`sandboxId`, `cloneExitCode`, `files`, `readmePreview`) all print

## Solution

```ts title="src/cli.ts"
import { Command } from 'commander';
import { runSandboxLifecycle } from './sandbox-lifecycle';

function isValidGitHubRepoUrl(input: string): boolean {
  return /^https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/?$/.test(input);
}

const program = new Command();

program
  .name('repo-review')
  .description('Clone and review a GitHub repository in a Sandbox')
  .version('0.1.0');

program
  .command('review <repoUrl>')
  .description('Run a Sandbox review against a GitHub repository URL')
  .action(async (repoUrl: string) => {
    if (!isValidGitHubRepoUrl(repoUrl)) {
      console.error(`Invalid GitHub repository URL: ${repoUrl}`);
      console.error('Expected format: https://github.com/<owner>/<repo>');
      return;
    }

    console.log(`Reviewing ${repoUrl}...`);
    const result = await runSandboxLifecycle(repoUrl);

    console.log(`Sandbox: ${result.sandboxId}`);
    console.log(`Clone exit code: ${result.cloneExitCode}`);
    console.log(`Files:\n${result.files}`);
    console.log(`README preview:\n${result.readmePreview}`);
  });

program.parse();
```


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
