# polyscope.json

The `polyscope.json` file lives in your repository root and controls how Polyscope workspaces behave. It defines setup and teardown scripts, preview URLs, and reusable tasks — all in one place.

**Commit this file to your repository.** When `polyscope.json` is checked into version control, every team member gets the same workspace configuration — setup scripts, preview URLs, and tasks — automatically when they create a new workspace.

You can create or edit this file from the command palette (**&#8984;K**) by searching for "polyscope.json".

## Full Example

```json
{
  "scripts": {
    "setup": ["herd link", "herd secure"],
    "archive": ["herd unsecure", "herd unlink"],
    "run": [
      { "label": "Dev Server", "command": "npm run dev", "autostart": true },
      { "label": "Tests", "command": "npm run test:watch" }
    ]
  },
  "runMode": "replace",
  "preview": {
    "url": "https://{{folder}}.test"
  },
  "tasks": [
    {
      "label": "Security review",
      "prompt": "Review the codebase for security vulnerabilities..."
    }
  ]
}
```

## Template Placeholders & Environment

Polyscope substitutes a small set of placeholders in script commands and the preview URL before running them, and exposes one environment variable to scripts.

### Placeholders

| Placeholder | Resolves to |
|---|---|
| `{{folder}}` | The workspace folder name. For a workspace created from the branch `add-billing`, this resolves to `add-billing`. |
| `{{worktree}}` | Alias for `{{folder}}`. |

All three syntaxes are accepted and equivalent: `{{folder}}`, `{folder}`, and `${folder}`.

Placeholders are supported in:

- `preview.url`
- `scripts.setup`, `scripts.archive`, and `scripts.run` commands

```json
{
  "scripts": {
    "setup": "herd link {{folder}}",
    "archive": "herd unlink {{folder}}"
  },
  "preview": {
    "url": "https://{{folder}}.test"
  }
}
```

### Environment Variables

| Variable | Description |
|---|---|
| `POLYSCOPE_ROOT_PATH` | Absolute path to the original repository (the source the workspace was cloned from). Available in `setup`, `archive`, and `run` scripts. Useful when a script needs to reference the source repo, e.g. to copy `.env` or other untracked files. |

```json
{
  "scripts": {
    "setup": "cp \"$POLYSCOPE_ROOT_PATH/.env\" .env"
  }
}
```

## scripts

Scripts run automatically during the workspace lifecycle. Both `setup` and `archive` accept a string (single command) or an array of strings (sequential commands).

See [Template Placeholders & Environment](#template-placeholders-environment) for the `{{folder}}` placeholder and `POLYSCOPE_ROOT_PATH` environment variable available inside scripts.

### scripts.setup

Runs automatically after a workspace is created. Use this to install dependencies, build assets, run migrations, or link services.

```json
{
  "scripts": {
    "setup": "npm ci && npm run build"
  }
}
```

Or with multiple commands:

```json
{
  "scripts": {
    "setup": ["herd link", "herd isolate 8.4", "herd secure"]
  }
}
```

### scripts.archive

Runs before a workspace is deleted. Use this to unlink services, clean up external resources, or remove build artifacts.

```json
{
  "scripts": {
    "archive": ["herd unsecure", "herd unlink"]
  }
}
```

See [Workflows](/docs/core-concepts/workflows) for more examples of setup and archive scripts.

### scripts.run

Defines run scripts — commands that appear as launchable actions in the header bar and open in dedicated terminal tabs. Each entry can be a simple string (used as both the label and command) or an object with more options.

```json
{
  "scripts": {
    "run": [
      "npm run dev",
      { "label": "Tests", "command": "npm run test:watch" }
    ]
  }
}
```

Each run script object supports:

- **`label`** — Display name shown in the UI (defaults to the command itself)
- **`command`** — The shell command to execute
- **`runMode`** — Per-script override: `"preserve"` (default) keeps existing tabs, `"replace"` kills the previous run before starting a new one
- **`autostart`** — When `true`, the script runs automatically after the workspace is initialized

See [Run Scripts](/docs/digging-deeper/run-scripts) for a detailed guide.

## runMode

Controls how run script terminal tabs behave when re-launched. Accepts `"preserve"` (default) or `"replace"`.

- **`preserve`** — Each launch opens a new terminal tab, keeping previous runs visible.
- **`replace`** — Kills the existing terminal tab for that script before starting a new one.

```json
{
  "runMode": "replace"
}
```

Individual scripts can override this global setting with their own `runMode` property.

## preview

Configures the live preview URL for workspaces. The preview URL powers the built-in browser (**&#8984;P**) and is required for the [Visual Editor](/docs/digging-deeper/visual-editor).

### preview.url

A URL template that gives each workspace its own preview. The `{{folder}}` placeholder resolves to the workspace's folder name at runtime — see [Template Placeholders & Environment](#template-placeholders-environment) for the full list.

```json
{
  "preview": {
    "url": "https://{{folder}}.test"
  }
}
```

For a workspace named "brave-bunny", this becomes `https://brave-bunny.test`.

If your project uses a fixed port instead of dynamic hostnames, you can use a static URL:

```json
{
  "preview": {
    "url": "http://localhost:3000"
  }
}
```

See [Laravel Herd](/docs/integrations/laravel-herd) for details on how Polyscope auto-detects Herd and suggests a preview URL.

### preview.command

A shell command that Polyscope runs to detect the preview URL dynamically. Use this when your dev server binds to a random or project-specific port and the URL isn't known ahead of time.

The command runs in the workspace directory and should print the URL to stdout. Polyscope captures the output and uses it as the preview URL.

```json
{
  "preview": {
    "command": "npm run dev"
  }
}
```

If both `url` and `command` are set, `command` takes precedence.

## tasks

An array of reusable prompts that you can launch from the sidebar with a single click. Each task creates a new workspace and sends the prompt automatically.

```json
{
  "tasks": [
    {
      "label": "Security review",
      "prompt": "Review the codebase for security vulnerabilities. Check for SQL injection, XSS, CSRF, and other OWASP top 10 issues."
    },
    {
      "label": "Add test coverage",
      "prompt": "Identify areas with missing test coverage and add tests for critical business logic."
    }
  ]
}
```

- **`label`** — The name shown in the task menu
- **`prompt`** — The full prompt sent to the agent

See [Tasks](/docs/advanced/tasks) for more examples and use cases.

## copyGitignored

By default, Polyscope uses copy-on-write (CoW) cloning to create workspaces efficiently. On filesystems that don't support CoW (such as network-mounted volumes or certain Linux configurations), gitignored files like `node_modules` or `vendor` are not included in the clone.

Set `copyGitignored` to `true` to copy gitignored files into the workspace clone. This ensures dependencies and build artifacts are available without needing to reinstall them during setup.

```json
{
  "copyGitignored": true
}
```

> **Note:** This increases clone time and disk usage since files are copied rather than linked. Only enable this if your filesystem does not support copy-on-write.

## Common Configurations

### Laravel with Herd

```json
{
  "scripts": {
    "setup": ["herd link", "herd secure"],
    "archive": ["herd unsecure", "herd unlink"],
    "run": [
      { "label": "Queue Worker", "command": "php artisan queue:work", "autostart": true },
      { "label": "Vite", "command": "npm run dev", "autostart": true }
    ]
  },
  "preview": {
    "url": "https://{{folder}}.test"
  }
}
```

### Node.js

```json
{
  "scripts": {
    "setup": "npm install",
    "archive": "rm -rf dist",
    "run": [
      { "label": "Dev Server", "command": "npm run dev", "autostart": true, "runMode": "replace" },
      { "label": "Tests", "command": "npm run test:watch" }
    ]
  },
  "preview": {
    "url": "http://localhost:3000"
  }
}
```
