> ## Documentation Index
> Fetch the complete documentation index at: https://ngquct-feat-721-compare-sync.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Development Setup

> Clone, configure signing, and build TablePro in Xcode

## Prerequisites

| Software | Version           | Notes                                                                    |
| -------- | ----------------- | ------------------------------------------------------------------------ |
| Xcode    | 26.0+             | Ships the macOS 26 SDK the app builds against. Every CI job pins 26.4.1. |
| Swift    | 5.9 language mode | Comes with Xcode, set by `SWIFT_VERSION` in the project                  |

The app references macOS 26 SDK symbols (`NSGlassEffectView` in the quick switcher), so an older Xcode cannot compile it. The deployment target stays at macOS 14.0 Sonoma, which is what the built app runs on, not what you build on.

Optional but recommended:

| Tool        | Install                    | Purpose                    |
| ----------- | -------------------------- | -------------------------- |
| SwiftLint   | `brew install swiftlint`   | Linting                    |
| SwiftFormat | `brew install swiftformat` | Code formatting            |
| GitHub CLI  | `brew install gh`          | Used by `download-libs.sh` |

## Quick Start

<Steps>
  <Step title="Clone the repository">
    ```bash theme={null}
    git clone https://github.com/TableProApp/TablePro.git && cd TablePro
    ```
  </Step>

  <Step title="Download native libraries">
    ```bash theme={null}
    scripts/download-libs.sh
    ```

    This pulls two archives from the `libs-v1` GitHub Release into `Libs/`: the macOS `.a` files (libmariadb, libpq, libduckdb, libmongoc, and others) and the iOS xcframeworks. About 257 MB downloaded, 620 MB on disk once expanded. Expect a minute or two.

    <Warning>
      Skipping this step causes linker errors. The static libraries are not checked into git.
    </Warning>
  </Step>

  <Step title="Create build config">
    ```bash theme={null}
    touch Secrets.xcconfig
    ```

    Empty file is fine for development. Production builds use this for API keys.
  </Step>

  <Step title="Install tools">
    ```bash theme={null}
    brew install swiftlint swiftformat
    ```
  </Step>

  <Step title="Open in Xcode">
    ```bash theme={null}
    open TablePro.xcodeproj
    ```
  </Step>

  <Step title="Configure signing">
    1. Select the **TablePro** target
    2. Go to **Signing & Capabilities**, **Debug** sub-tab
    3. Change **Team** to your Apple Developer account (a free personal team works)
    4. Change the **Bundle Identifier** from `com.TablePro` to something unique, for example `com.yourhandle.TablePro`

    The Debug configuration signs with `TablePro.Debug.entitlements`, which drops
    the iCloud capability, so a free personal team can sign it without a paid
    Apple Developer Program membership. If another target still shows a team
    error (a driver plugin or the MCP server), set its **Team** the same way.

    Do not commit the resulting `project.pbxproj` changes; they break official
    Release signing. Hide them locally:

    ```bash theme={null}
    git update-index --skip-worktree TablePro.xcodeproj/project.pbxproj
    ```
  </Step>

  <Step title="Build and run">
    Select the **TablePro** scheme, set destination to **My Mac**, press `Cmd+R`.

    Or from the command line:

    ```bash theme={null}
    xcodebuild -project TablePro.xcodeproj -scheme TablePro -configuration Debug build -skipPackagePluginValidation
    ```

    `Cmd+R` writes the app to DerivedData
    (`~/Library/Developer/Xcode/DerivedData/TablePro-*/Build/Products/Debug`). The
    `xcodebuild` command above writes to `build/Debug/TablePro.app` inside the repo instead.
  </Step>
</Steps>

Writing a driver plugin? See [Plugin Development](/development/plugin-development) to build one and [Testing a Custom Plugin](/development/testing-plugins) to run it in your local build.

<Frame caption="Xcode project setup">
  <img className="block dark:hidden" src="https://mintcdn.com/ngquct-feat-721-compare-sync/Px1jOVnHwSdgRuFN/images/xcode-setup.png?fit=max&auto=format&n=Px1jOVnHwSdgRuFN&q=85&s=d474746ac98bc5ec1b7e633a50845002" alt="Xcode setup" width="3024" height="1722" data-path="images/xcode-setup.png" />

  <img className="hidden dark:block" src="https://mintcdn.com/ngquct-feat-721-compare-sync/Px1jOVnHwSdgRuFN/images/xcode-setup-dark.png?fit=max&auto=format&n=Px1jOVnHwSdgRuFN&q=85&s=bffdc45ddaa08755f574b3812ccc69f1" alt="Xcode setup" width="3024" height="1722" data-path="images/xcode-setup-dark.png" />
</Frame>

## Project Structure

<Tree>
  <Tree.Folder name="TablePro" defaultOpen>
    <Tree.Folder name="Core">
      <Tree.File name="Database/, Plugins/, Services/, Utilities/, SSH/, Autocomplete/" />
    </Tree.Folder>

    <Tree.Folder name="Views">
      <Tree.File name="Connection/, Editor/, Main/, Results/, Settings/, Sidebar/" />
    </Tree.Folder>

    <Tree.Folder name="Models" />

    <Tree.Folder name="ViewModels" />

    <Tree.Folder name="Extensions" />

    <Tree.Folder name="Theme" />

    <Tree.Folder name="Resources" />
  </Tree.Folder>

  <Tree.Folder name="Plugins">
    <Tree.File name=".tableplugin bundles + TableProPluginKit framework" />
  </Tree.Folder>

  <Tree.Folder name="Packages">
    <Tree.File name="TableProCore: shared SwiftPM modules used by the macOS and iOS apps" />
  </Tree.Folder>

  <Tree.Folder name="LocalPackages">
    <Tree.File name="Vendored CodeEditSourceEditor, CodeEditTextView, CodeEditLanguages" />
  </Tree.Folder>

  <Tree.Folder name="Libs">
    <Tree.File name="Pre-built static libraries (downloaded, not in git)" />
  </Tree.Folder>

  <Tree.Folder name="TableProMobile">
    <Tree.File name="iOS app" />
  </Tree.Folder>

  <Tree.Folder name="TableProTests" />

  <Tree.Folder name="TableProUITests" />

  <Tree.Folder name="docs">
    <Tree.File name="Mintlify docs site" />
  </Tree.Folder>

  <Tree.Folder name="scripts">
    <Tree.File name="build-release.sh, create-dmg.sh, download-libs.sh" />
  </Tree.Folder>
</Tree>

`Packages/TableProCore/Sources/TableProPluginKit` is a symlink to `Plugins/TableProPluginKit`. Edit the files under `Plugins/` only.

## Running Tests

```bash theme={null}
xcodebuild -project TablePro.xcodeproj -scheme TablePro test -skipPackagePluginValidation
```

Or in Xcode: `Cmd+U`. To run a single class or method, pass `-only-testing:TableProTests/TestClassName` or `-only-testing:TableProTests/TestClassName/testMethodName`.

## Linting and Formatting

Before committing:

```bash theme={null}
swiftlint lint --strict
swiftformat .
```

CI rejects warnings, so plain `swiftlint lint` is not enough. Full tooling reference: [Code Style](/development/code-style).

## Troubleshooting

| Problem                             | Fix                                                                 |
| ----------------------------------- | ------------------------------------------------------------------- |
| Linker errors about missing symbols | Run `scripts/download-libs.sh`                                      |
| SPM resolution fails                | Clean build folder (`Cmd+Shift+K`), reopen Xcode                    |
| Build fails after pulling           | Delete derived data: `rm -rf ~/Library/Developer/Xcode/DerivedData` |
| Missing `Secrets.xcconfig` error    | Run `touch Secrets.xcconfig` in project root                        |
| Code signing errors                 | Change Team in Signing & Capabilities                               |

<Note>
  Pass `-skipPackagePluginValidation` on every `xcodebuild` invocation so the build does not stop on package plugin validation. `scripts/build-release.sh`, `scripts/build-plugin.sh`, `scripts/check-pluginkit-abi.sh`, and CI all pass it.
</Note>
