Connecting a repo
Tandem deploys from Git. Before you can deploy a service, the platform needs to know where its source lives. There are three ways to connect a repo — pick whichever matches where the code already lives (or should live):
- Tandem Git — Tandem hosts the repo itself: first-class git hosting, zero GitHub account needed. This is the portal’s default for new projects and the fastest zero-dependency path. Full guide: Tandem Git.
- GitHub App — Tandem authenticates as a GitHub App with scoped access to specific repos on GitHub.
- Clone URL — Tandem stores a URL it can
git clonefrom: a public repo, or a private one reached via a deploy key.
What each source enables
| Capability | Tandem Git | GitHub App | Clone URL |
|---|---|---|---|
| Manual deploys from the portal | yes | yes | yes |
Auto-deploy on push to the default branch (or deployBranch) |
yes | yes | no |
Import services from platform.yml on connect |
no — the “template” init mode seeds a starter platform.yml instead |
yes | no |
| Repository Mutation API (no-clone read/commit — powers the MCP git tools, and the future in-portal editor) | yes | no | no |
| Drive-style sharing / access grants on the repo itself | yes (share_git_repo, the Share dialog) |
no (GitHub’s own collaborator model governs the repo; Tandem only holds an installation token) | no |
| Migrate in from an existing GitHub repo, or any public URL | yes (import_repository / “Copy to Tandem Git” / “Import from URL”) |
n/a (it’s already there) | n/a |
| Export to GitHub / continuous Mirror to GitHub | n/a (it’s the source) | n/a | n/a |
| GitHub commit status / check runs (planned) | no | yes | no |
If you connect via clone URL, you can still define services manually from the portal’s Services tab and trigger deployments by hand. You just won’t get platform.yml import or push-driven deploys — for either of those, use Tandem Git or the GitHub App.
Connecting via Tandem Git
Tandem Git is a first-class, self-hosted git host inside the platform — a private repo with a standard HTTPS clone URL and an access token, no GitHub account required anywhere in the chain. See Tandem Git for the full guide (creating repos, PATs, credential-helper setup, the mutation API, sharing, migrate in/out, and continuous Mirror to GitHub). The short version:
- Creating a project: pick Host code on Tandem in the “New project” form (the default) — choose “Start from a template” (seeds a deployable
platform.yml) or “Empty repository”, name the project, and create. Both the project and its repo are created together, already wired up as the deploy source. - Adding to an existing project: from the project’s Code tab, either create a repo (auto-attached as the deploy source) or, if the project already has a linked Tandem repo that isn’t yet the source, use Make this the deploy source.
- Clone it: the URL is on the Code tab; mint a PAT from Settings → Git access tokens. Or skip cloning entirely — edit files directly through the Repository Mutation API or the
read_git_repository/commit_git_changesMCP tools. - MCP, zero portal clicks:
create_git_repowithasProjectSource: { newProject: "<name>" }(new project) or{ projectId: "<id>" }(existing project) creates the repo and wires up the deploy source in one call.
Already have code elsewhere? Migrate it in — see the “Migrating between GitHub and Tandem Git” section of Tandem Git (import_repository / “Copy to Tandem Git” / “Import from URL”).
Connecting via GitHub App
- From the portal, go to Settings → GitHub and click Install GitHub App.
- GitHub takes you through its install flow — pick whether to grant access to all repos or specific ones in your account/org. You can change this later from GitHub’s app settings.
- When the install completes, GitHub redirects you back to the portal with the installation linked to your user.
- Open a project, click Connect repository, and pick the repo from the list. Only repos covered by the install will appear.
- If the repo has a
platform.ymlat the root of the default branch, the portal offers to import its services in one click. Otherwise, define services manually.
After connection, every push to the repo’s default branch (or the deploy_branch override on the project, if set) automatically queues a deployment for each service in the project.
Already hosting on Tandem Git and want a GitHub-side copy instead of migrating away? Use Export to GitHub or continuous Mirror to GitHub from the Tandem repo’s Code tab — see Tandem Git — rather than starting a fresh GitHub App connection.
Connecting via clone URL
- Open a project and click Connect repository → Use a clone URL.
- Enter the HTTPS or SSH URL and the default branch name.
- For private repos you’ll need to give the host machine SSH access — talk to a platform admin for the deploy-key flow.
You’ll then need to add services from the Services tab. With no platform.yml import available, each service’s config (path, type, build/start commands) is whatever you enter there.
Note on where service config lives generally: for repo-backed projects platform.yml is the source of truth for a service’s type, build/start commands and output directory. The values stored on the service row are overrides used when the file doesn’t specify them — which is why clearing an override (send null, or blank the field in Edit service) is how you hand a setting back to the repo. A type recorded in Tandem that disagrees with platform.yml blocks every deploy of that service; see Changing a service’s type.
Changing a service’s type
Converting an app from one type to another — a static SPA that grows a Node server in front of it, most commonly — means the type in platform.yml no longer matches the type stored on the service, and the deploy guard refuses every deploy with:
service admin-web type mismatch: database=static, platform.yml=node
This is fully self-serve, on either surface:
- Portal: project → Services → Edit service → Type. Picking a different type reveals a confirmation you must tick; saving then shows what changed and what to check.
- MCP:
update_service_config { serviceId, type: "node", confirmTypeChange: "static->node" }. TheconfirmTypeChangetoken is the literal"<currentType>-><newType>"; it is required because a type change swaps how the service is built and run, and naming the current type also means a stale assumption fails loudly instead of flipping the wrong service.
Two things happen with the change, both deliberate:
- The stored
buildCommand,startCommandandoutputDirectoryoverrides are cleared, soplatform.ymlgoverns the new type. Left in place, a static service’soutput: distand pinned build command sail past the type guard and then fail the build further down for a much less obvious reason. (Pass any of those fields in the same call to set it deliberately instead.) - You get warnings back — chiefly about runtime env vars. Only
runtime/both-scoped vars reach the running container, so a service that just became a server with no runtime vars set will build fine and then fail its health check. Set them (set_env_varswithscope: "runtime", or the portal’s Env tab) before you deploy, and consider whether build-scopedVITE_*/NEXT_PUBLIC_*vars are still doing anything.
Nothing changes on the running container until you deploy (create_deployment, or Deploy in the portal). Rolling back afterwards is safe in the normal case: each deployment records the port its image was built to listen on, so a rollback re-runs that image the way it was built even though the service is a different type now. The exception is a deployment made before Tandem started recording that — rolling back to a very old pre-change deployment can time out on its health check, so change the type back first if you need one of those. Never delete and re-import a service to change its type — that destroys its env vars, deployment history and hostname binding.
Doing this over MCP
Tandem Git
create_git_repo (with or without asProjectSource), read_git_repository, commit_git_changes, share_git_repo, import_repository, export_repository_to_github, get_source_status, configure_git_mirror — see the Tandem Git guide and the MCP tool reference for full parameters.
GitHub App / clone URL
An agent connects a GitHub-backed repo entirely through MCP tools — no portal clicks:
list_github_installations— find the GitHub App installations visible to your org. (A human still performs the one-time GitHub App install; the agent picks it up from here.)list_installation_repositorieswith theinstallationId— see the repos that install grants.connect_repositorywithinstallationId+githubRepoNodeId— connect the repo into the org (needsmanage+ developer).list_repositoriesshows repos already connected and their ids.set_project_repositorywithprojectId+repositoryId(+ optionaldeployBranch) — attach the repo to an existing project.read_platform_ymlwith therepositoryId— fetch + parse the repo’splatform.ymlinto service definitions, thenimport_servicesto bulk-create them.
list_repositories reports hasInstallation per repo — true means platform.yml reads and push-driven auto-deploy are available; false (clone-URL only) means you define services manually and deploy by hand.
Switching between sources
- Clone URL → GitHub App: install the GitHub App if you haven’t already (Settings → GitHub), then from the project’s Settings choose Re-link repository via GitHub App and pick the matching repo. Existing services keep their config; only the connection mode changes. Auto-deploy and
platform.ymlimport become available immediately. - GitHub → Tandem Git (zero-migration): “Copy to Tandem Git” from the project’s Code tab (or
import_repositorywithsource: { githubRepositoryId }) clones the GitHub repo’s full history into a new Tandem repo; passrepointProject: trueto switch the project’s deploy source over once the copy finishes. Nothing about env vars or deploys changes — they’re stored outside git either way. - Tandem Git → GitHub: “Export to GitHub” (one-time copy into an empty repo you create) or continuous “Mirror to GitHub” (keeps a GitHub copy live) — both covered in the “Migrating between GitHub and Tandem Git” section of Tandem Git.
Common errors
no_installation_linked— you tried to import or refreshplatform.ymlon a repo connected via clone URL. Re-link via the GitHub App, or define services manually.service <name> type mismatch: database=..., platform.yml=...— the stored service type and the repo disagree; nothing was built. See Changing a service’s type.platform_yml_not_found— the App is installed but the file isn’t on the branch Tandem fetched. Check the file is at the repo root and committed to the default branch. See Writing platform.yml.- Push webhook received but no deployment — confirm the project’s
deploy_branch(or the repo’s default branch, if unset) matches the branch the push was on. Pushes to other branches are recorded but don’t auto-deploy. This applies identically to GitHub-connected and Tandem Git projects.