> ## Documentation Index
> Fetch the complete documentation index at: https://panopticon-cli.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Project Registry

> Managing multiple projects with Overdeck

export const ThemedImage = ({light, dark, alt = ""}) => {
  const [darkMode, setDarkMode] = useState(null);
  useEffect(() => {
    const root = document.documentElement;
    const syncTheme = () => setDarkMode(root.classList.contains("dark"));
    const observer = new MutationObserver(syncTheme);
    syncTheme();
    observer.observe(root, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  if (darkMode === null) return null;
  return <img src={darkMode ? dark ?? light : light} alt={alt} loading="lazy" />;
};

# Project Registry

Overdeck's project registry enables multi-project management with intelligent issue routing and label-based workspace creation.

## Overview

Projects are registered in `~/.overdeck/projects.yaml`. Each project can have:

* **Issue routing rules** - Route issues to different subdirectories based on labels
* **Custom workspace commands** - For complex polyrepo setups
* **Linear team mapping** - Connect projects to Linear teams

While `projects.yaml` is the source of truth, much of this configuration is also surfaced in the dashboard's **Settings** page, alongside model routing for the agents and conversations Overdeck runs and tracker API keys.

<ThemedImage light="/images/dashboard/settings-light.png" dark="/images/dashboard/settings-dark.png" alt="Overdeck Settings page showing model routing, tracker API keys, and project configuration" />

<Note>
  Overdeck manages both the workflow pipeline and the agents and conversations
  that move issues through it. The Settings page is where model routing for those
  agents lives, while per-project routing and workspace rules below are edited in
  `~/.overdeck/projects.yaml`.
</Note>

## Registering Projects

### Clone a repository

Clone a repository directly into Overdeck:

```bash theme={null}
pan project clone https://github.com/owner/repo
pan project clone owner/repo
pan project clone git@github.com:owner/private.git
pan project clone ssh://git@git.example.com:2222/team/repo.git
```

The URL you type is the URL git receives — protocol, username, port and path
unchanged — because all four decide how authentication happens. Only the bare
`owner/repo` shorthand is expanded, into a GitHub HTTPS URL.

Optional flags: `--parent <dir>` (default `~/Projects`), `--name <name>`,
`--issue-prefix <PREFIX>`, and `--dry-run`.

```bash theme={null}
pan project clone owner/repo --dry-run | jq '{key, path, repoSlug, defaultBranch}'
```

`--dry-run` prints the resolved intent as a single JSON document and writes
nothing — no directory, no registration, no context layer, no hooks. Credentials
embedded in a URL are redacted from that output.

**Credentials live on the server.** Clones run non-interactively
(`GIT_TERMINAL_PROMPT=0`, `ssh -o BatchMode=yes`), so nothing can hang waiting on
a prompt nobody can see. A private repository therefore needs credentials
already available on the machine running Overdeck — an SSH key loaded into that
machine's agent, or a configured credential helper. When they are missing you
get a typed message naming the problem, and it never suggests `ssh-add` for an
HTTPS failure.

**Cancelling.** Press Ctrl-C (or use Cancel in the dashboard) and the clone
child is stopped for real: SIGTERM first, SIGKILL if it has not exited five
seconds later. The command exits 130 once cleanup has settled. A directory the
clone created is removed; a directory that already existed is never touched.

**Unknown hosts** clone fine. You get a usable folder name and no guessed
tracker configuration, since there is no provider to infer one from.

### Add existing

Register a repository that already exists on your machine:

```bash theme={null}
pan project add /path/to/your/project [--name <name>] [--dry-run]
```

Registration detects:

* `github_repo` / `gitlab_repo` — the remote slug
* `tracker` — GitHub or GitLab, from the remote host
* `workspace.default_branch` — the repository's default branch, or nothing at
  all when the repository is detached or has no commits yet (a guessed `main`
  would point every later workspace at a branch that may not exist). The diff
  panel's "vs main" view compares against this branch, so a project on
  `master` or `trunk` still gets a correct "vs main" view.
* `issue_prefix` — proposed from the project key, up to ten characters
* The main workspace row

Adding a **subdirectory** of a repository adds the repository root instead,
and says so: `ℹ Using the repository root /home/you/code/app.` This keeps two
projects from fighting over one checkout. A name you pass with `--name` is kept;
otherwise the name comes from the root folder. A home directory that is itself a
repository (a dotfiles-managed `~`) is the one exception: folders under it stay
plain folders. A linked worktree is recognized as a repository. A plain folder
that is not a repository at all is fine — it registers as a project without one.

`workspaces/` is excluded through `<project>/.git/info/exclude`, which is local
and untracked. Overdeck never edits your tracked `.gitignore`, so a freshly
cloned repository does not come back dirty. If you want the exclusion shared
with your team, add it to `.gitignore` yourself.

Tests and quality gates are **not** detected. Configure those yourself — see
[Project Configuration](#project-configuration).

### Finish an interrupted setup

If creation stops after the project was registered — say the main workspace
could not be created — the repository is on disk and the project exists. Repair
it instead of cloning again:

```bash theme={null}
pan project finish-setup <key> [--path <expected-path>]
```

It is idempotent: it never clones and never registers a second project, so
running it on an already-complete project simply reports the result. `--path` is
a consistency check, not a relocation — a mismatch refuses rather than repairing
the wrong project.

### Dashboard

The sidebar `+`, the command palette, the workspace-page chips, and the
HomePage button open the **Add a project** dialog over the page you are on.
`/projects/new` still works and shows the same dialog as a full page;
`?mode=clone`, `?mode=existing` or `?mode=new` skips the first step.

The first step focuses **Open a folder**; the arrow keys move between the
choices and Enter picks one.

* **Open a folder** — type a path or browse the server's folders, starting in
  `~/Projects`. What happens next depends on what the folder is:
  * **A Git repository** — review it and add it. A folder *inside* a repository
    adds the repository root, with the note "Using the repository root
    \~/code/app."
  * **A folder with repositories in it** — the dialog lists the repositories it
    found, all checked. **Add N projects** adds each checked one as its own
    project; a failure on one row does not stop the rest. **Add this folder as
    one project** adds a single multi-repo project spanning the checked
    repositories: it registers `workspace.type: polyrepo` with one
    `workspace.repos` entry per repository and keeps `.pan/` in the first one
    (`pan_records.repo`). No tracker is set, since several remotes do not name
    one; add it yourself. See [Polyrepo Configuration](/configuration/polyrepo).
  * **A plain folder** — the dialog explains that agents and terminals work
    there but branches, isolated copies and pull requests won't, and offers
    **Add as folder** or **Back**.
* **Clone from URL** — download a Git repository. Press Enter to clone once the
  URL checks out.
* **Create new project** — start an empty Git repository. Press Enter to create
  once the name checks out.

Below the choices, **Repositories in \~/Projects** lists repositories already in
that folder that are not projects yet; **Add** registers one in a single click.

After a project is added, Overdeck opens it and puts the cursor in its
Launcher. If you started from the New Workspace page, you go back there with the
new project selected.

Defaults are real server-resolved values, not placeholders: the parent folder
comes from the server's home directory, and the exact destination is shown
before you commit to it. `~` and `~/sub` expand against the **server's** home,
since the browser has no idea what they mean on the machine holding the files.
Name and issue prefix live under Options, already filled in; anything you type
there survives a change to the URL or folder.

While a clone runs, the form is frozen and shows git's own phases. Cancel stops
the real process. If the connection drops, the page says so and keeps the
operation rather than pretending it finished — it never re-enables Create on a
result it has not seen. After a server restart an in-flight clone genuinely
cannot be resolved from memory, so you are offered *Check again* rather than an
automatic retry that might clone a second copy.

### Project or workspace?

**A project is a repository with its own issues and pipeline.** Use projects to register separate codebases. If you already have a project registered and want another checkout of it (e.g., for a feature branch, a long-lived testing branch, or a release branch), **create a workspace** instead. Workspaces share the same project registry entry and codebase but isolate development state per branch.

### Rename and list

```bash theme={null}
# List registered projects
pan project list

# Remove a project
pan project remove myproject

# Rename a project
pan project rename <key> <newName>

# Example: keep the stable `myn` key and change its display name
pan project rename myn "Mind Your Now"
```

### Rename a project

```bash theme={null}
pan project rename <key> <newName>

# Example: keep the stable `myn` key and change its display name
pan project rename myn "Mind Your Now"
```

The registration key is the stable identifier stored as the project's YAML map key. It is derived when the project is registered and cannot be renamed. The display name is the human-facing label shown throughout Overdeck; it can be renamed, but it cannot match another project's registration key or display name, ignoring letter case.

In the dashboard, use the pencil beside the name on the project page, or right-click the project tree row and choose **Rename project**. Both controls open an inline editor for the display name while preserving the registration key.

## Project Configuration

Projects are defined in `~/.overdeck/projects.yaml`:

```yaml theme={null}
projects:
  myn:
    name: "Mind Your Now"
    path: /home/user/projects/myn
    issue_prefix: MIN
    issue_routing:
      - labels: [splash, landing-pages, seo]
        path: /home/user/projects/myn/splash
      - labels: [docs, marketing]
        path: /home/user/projects/myn/docs
      - default: true
        path: /home/user/projects/myn

  overdeck:
    name: "Overdeck"
    path: /home/user/projects/overdeck
    issue_prefix: PAN
```

### Configuration Fields

| Field | Required | Description |
| - | - | - |
| `name` | Yes | Human-readable project name |
| `path` | Yes | Absolute path to project root |
| `issue_prefix` | Yes\* | Issue prefix for standard format IDs (e.g., "MIN", "PAN"). Automatically proposed during registration based on the repository name. |
| `tracker` | No | Issue tracker type: `linear`, `github`, `gitlab`, `rally`. Set it explicitly when the code host and issue tracker differ. |
| `issue_prefixes` | No | Array of prefixes for multi-prefix trackers (e.g., `[F, US, DE, TA]`) |
| `issue_pattern` | No | Custom regex for issue ID parsing: `^(PREFIX)-(\\d+)$` |
| `issue_routing` | No | Label-based routing rules |
| `workspace_command` | No | Custom workspace creation script |
| `workspace_remove_command` | No | Custom workspace cleanup script |
| `workspace` | No | Polyrepo/progressive workspace configuration |
| `release` | No | Coordinated post-merge release configuration |
| `verification.tests` | No | `ci` or `local`: where the verification gate's `test` gate runs. `ci` skips the local `quality_gates.test` run and treats the CI test job on the PR head as the test gate; `local` runs it on the host. Default: `ci` when the project has `github_repo` and a GitHub Actions workflow that runs a job named `test`/`tests`/`test-*`/`test (…)` on pull requests, else `local`. |

\*Not required if `issue_prefixes` or `issue_pattern` is specified.

### Separate the issue tracker from the code host

The `tracker` field selects where issues and workflow states live. Code-host fields such as `github_repo` and `gitlab_repo` independently select where Overdeck reads pull requests or merge requests.

Set `tracker` explicitly whenever those systems differ. For example, this project tracks `LEX-*` issues in Linear while hosting its source code and pull requests on GitHub:

```yaml theme={null}
projects:
  lexerra:
    name: "Lexerra"
    path: /home/user/projects/lexerra
    issue_prefix: LEX
    tracker: linear
    linear_project: Lexerra
    github_repo: eltmon/lexerra
```

Keep both credentials available: Overdeck uses the Linear API for issue state and authenticated GitHub access for pull-request evidence. Do not remove `github_repo` to force Linear routing, because that would also remove the project's GitHub pull-request lens.

See [Issue Tracker Integration](/configuration/issue-trackers#tracker-and-code-host-can-differ) for troubleshooting and additional examples.

### Repositories a conversation can link pull requests from

A conversation can be [linked to a pull request](/features/conversations#linking-a-pull-request-by-hand)
only when the PR's repository is configured for the conversation's project.
The conversation's project is its explicit project (set with `pan conv move`)
or else the registered project whose `path` contains its working directory.
These repositories count as configured:

* `github_repo` (on the host of the project's GitHub `origin` remote, or `github.com`)
* `gitlab_repo` (on the host of the project's GitLab `origin` remote, or `gitlab.com`)
* every `workspace.repos[].remote` written as a URL, for polyrepo projects (a
  bare forge name such as `remote: github` names no repository)
* the `origin` remote of the project checkout and of the conversation's working
  directory

`#42` refers to PR 42 in the first of these: `github_repo`, then `gitlab_repo`,
then the `origin` remotes. A link to any other repository is refused, and
nothing is stored.

## Release Configuration

The optional `release:` section tells Overdeck how to coordinate a project's post-merge rollout across multiple components. Overdeck resolves a release plan, waits for each component to become healthy, runs verification commands, halts the plan on failure, and runs a rollback hook when one is configured.

```yaml theme={null}
projects:
  myn:
    name: "Mind Your Now"
    path: /home/user/projects/myn
    issue_prefix: MIN
    release:
      components:
        api:
          provider: kubernetes
          trigger: auto
          health_url: https://api.myn.example.com/health
          version_check: scripts/check-version.sh api
          smoke_test: scripts/smoke.sh api
          rollback: scripts/rollback.sh api
        frontend:
          provider: vercel
          trigger: auto
          depends_on: [api]
          health_url: https://myn.example.com/health
          smoke_test: scripts/smoke.sh frontend
        docs:
          provider: vercel
          trigger: skip
```

### Component fields

| Field | Required | Description |
| - | - | - |
| `provider` | No | Informational label for the deployment target (e.g. `kubernetes`, `vercel`) |
| `trigger` | Yes | `auto` — wait for external deploy and verify; `manual` — pause for operator release; `skip` — exclude from the plan |
| `depends_on` | No | Array of other component keys that must release before this one |
| `health_url` | No | URL Overdeck polls until it returns a successful response |
| `version_check` | No | Shell command that must exit 0 after the component is healthy |
| `smoke_test` | No | Shell command that must exit 0 to consider the component released |
| `rollback` | No | Shell command to run when this component fails; success marks the issue `rolled_back` |

### Release semantics

* `trigger: auto` means Overdeck **waits and verifies** an external deploy; it does not invoke the provider deploy itself.
* Components are released in `depends_on` order using a topological sort. A component is only started after its dependencies pass.
* If any check fails, Overdeck stops all later components and records the final issue-level status.
* Projects without a `release:` section are **skipped cleanly** — no failure is recorded.

### Release status lifecycle

Issue-level `releaseStatus` moves through the following values:

`pending` → `releasing` → `passed`\
`pending` → `releasing` → `failed`\
`pending` → `releasing` → `partial`\
`pending` → `releasing` → `rolled_back`\
`pending` → `skipped`

The seven possible values are: `pending`, `releasing`, `passed`, `failed`, `partial`, `rolled_back`, and `skipped`.

Inspect or retry a release from the CLI with `pan rollout`:

```bash theme={null}
pan rollout status <issue-id>
pan rollout retry <issue-id>
```

`pan rollout` is distinct from `pan release`, which publishes npm stable/canary packages.

## Gauntlet Lane Configuration

The optional `gauntlet:` section sets per-project defaults for gauntlet lanes, the conversations that `pan lane start` launches for a gauntlet loop. Every field is optional.

```yaml theme={null}
projects:
  lexerra:
    gauntlet:
      lanes_root: /home/eltmon/Projects/lexerra-lanes
      sparse_checkout: ['/*', '!/client/assets-src/*', '/client/assets-src/KayKit_Medieval_Hexagon/']
      roles:
        builder: { model: stealth/space-bunny-alpha }
        critic: { model: claude-opus-5-5, effort: high }
```

| Field | Required | Description |
| - | - | - |
| `lanes_root` | No | Absolute directory that holds lane worktrees. It must be under your home directory, outside `/tmp`, and must not contain the project checkout. Default: a sibling of the project path named `<project dir>-lanes` (for `/home/u/Projects/lexerra`, `/home/u/Projects/lexerra-lanes`). |
| `base_ref` | No | Git ref new builder branches are cut from. Default: `origin/<workspace.default_branch>`, or `origin/main`. |
| `sparse_checkout` | No | Array of non-empty `git sparse-checkout --no-cone` patterns applied to new builder worktrees. |
| `roles` | No | Per-role `model`, `harness` and `effort` defaults. The keys are the lane roles `builder`, `critic`, `verifier`, `play` and `orchestrator`; any other key is rejected with an error naming it. A `--model`, `--harness` or `--effort` flag on `pan lane start` overrides these values. |

## Label-Based Routing

Issues are routed to different subdirectories based on their labels:

1. **Labeled issues** - Matched against `issue_routing` rules in order
2. **Default route** - Issues without matching labels use the `default: true` path
3. **Fallback** - If no default, uses the project root path

**Example:** An issue with label "splash" in the MIN team would create its workspace at `/home/user/projects/myn/splash/workspaces/feature-min-xxx/`.

## Linear Project Mapping

If you have multiple Linear projects, configure which local directory each maps to. Create/edit `~/.overdeck/project-mappings.json`:

```json theme={null}
[
  {
    "linearProjectId": "abc123",
    "linearProjectName": "Mind Your Now",
    "linearPrefix": "MIN",
    "localPath": "/home/user/projects/myn"
  },
  {
    "linearProjectId": "def456",
    "linearProjectName": "Househunt",
    "linearPrefix": "HH",
    "localPath": "/home/user/projects/househunt"
  }
]
```

The dashboard uses this mapping to determine where to create workspaces when you click "Create Workspace" or "Start Agent" for an issue.

## Custom Workspace Commands (Legacy)

> **Note:** For most polyrepo projects, use the built-in `workspace` configuration (see [Polyrepo Configuration](/configuration/polyrepo)) instead of custom scripts. Custom commands are only needed for highly specialized setups.

For projects that need logic beyond what the configuration supports, you can specify custom workspace scripts:

```yaml theme={null}
projects:
  myn:
    name: "Mind Your Now"
    path: /home/user/projects/myn
    issue_prefix: MIN
    # Custom scripts handle complex workspace setup
    workspace_command: /home/user/projects/myn/infra/new-feature
    workspace_remove_command: /home/user/projects/myn/infra/remove-feature
```

When `workspace_command` is specified, Overdeck calls your script instead of creating a standard git worktree. The script receives the normalized issue ID (e.g., `min-123`) as an argument.

When `workspace_remove_command` is specified, Overdeck calls your script when deleting workspaces (e.g., aborting planning with "delete workspace" enabled). This is important for complex setups that need to:

* Stop Docker containers and remove volumes
* Clean up root-owned files created by containers
* Remove git worktrees from multiple repositories
* Release port assignments
* Remove DNS entries

**What your custom script should handle:**

* Creating git worktrees for multiple repositories (polyrepo structure)
* Setting up Docker Compose files and dev containers
* Configuring environment variables and `.env` files
* Setting up DNS entries for workspace-specific URLs (e.g., Traefik routing)
* Creating a `./dev` script for container management
* Copying agent configuration templates (CLAUDE.md, .mcp.json, etc.)

**Example script flow:**

```bash theme={null}
#!/bin/bash
# new-feature script for a polyrepo project
ISSUE_ID=$1  # e.g., "min-123"

# Create worktrees for frontend and api repos
git -C /path/to/frontend worktree add ../workspaces/feature-$ISSUE_ID/fe feature/$ISSUE_ID
git -C /path/to/api worktree add ../workspaces/feature-$ISSUE_ID/api feature/$ISSUE_ID

# Generate docker-compose from templates
sed "s/{{FEATURE_FOLDER}}/feature-$ISSUE_ID/g" template.yml > workspace/docker-compose.yml

# Set up DNS and Traefik routing
# ... additional setup
```

The standard `pan workspace create` command will automatically detect and use your custom script.

## Project Initialization

When registering a new project with Overdeck (`pan project add`), the system will:

1. **Check for existing PRD** - Look for `docs/PRD.md`, `PRD.md`, `README.md`, or similar
2. **If found**: Use it to create/update the canonical PRD format, prompting for any missing crucial information
3. **If not found**: Generate one by:
   * Analyzing the codebase structure
   * Identifying key technologies and patterns
   * Asking discovery questions about the product

This ensures every Overdeck-managed project has a well-defined canonical PRD that agents can reference.

## Progressive Workspaces

For large projects with 10+ repositories, progressive workspaces provide on-demand repo checkout. Enable in `workspace` config:

```yaml theme={null}
projects:
  enterprise:
    name: "Enterprise Integration"
    path: /home/user/projects/enterprise
    tracker: rally
    issue_prefixes: [F, US, DE, TA]
    workspace:
      type: polyrepo
      progressive: true
      always_include: [meta]
      groups_file: team-meta/overdeck/repo-groups.yaml
      pr_target: qa
      repos:
        - name: meta
          path: team-meta
          link_type: symlink
          readonly: true
```

Key progressive fields:

| Field | Description |
| - | - |
| `progressive` | When `true`, only `always_include` repos created on workspace init |
| `always_include` | Repo names to always include (typically meta/docs repos) |
| `groups_file` | Path to `repo-groups.yaml` for named repo groups |
| `pr_target` | Default PR target branch (e.g., `'qa'`) |

See [Progressive Polyrepo](/configuration/progressive-polyrepo) for full documentation.

## Related Guides

* [Polyrepo Configuration](/configuration/polyrepo) - Multi-repository workspace setup
* [Progressive Polyrepo](/configuration/progressive-polyrepo) - Large-scale polyrepo with on-demand checkout
* [Setup Wizard](/configuration/setup-wizard) - Interactive project configuration
* [Meta Repos](/configuration/meta-repos) - Team conventions and onboarding kits
* [Issue Tracker Integration](/configuration/issue-trackers) - Connecting to Linear, GitHub, Rally, etc.
* [Workspaces](/features/workspaces) - Workspace management


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.