| name | bitrise-ci-onboarding |
| description | Take a Bitrise prospect from "I have an account" to "my first build is green" by registering a project, connecting a repo, uploading signing credentials, and triggering the first build via the Bitrise MCP server. Use this when the user asks to "set up my project on Bitrise", "connect my repo to Bitrise", "run my first Bitrise build", "onboard my app to Bitrise CI", or "get my iOS/Android app building on Bitrise". The user must already have a Bitrise PAT wired into the MCP — if they don't, run bitrise-signup first. Use this skill regardless of whether it's iOS or Android; the skill branches internally.
|
Bitrise CI Onboarding
Drive a prospect through the full first-build flow: app registration →
repository connection → signing credentials → trigger build → watch it go
green. This is the second of three skills in the prospect onboarding
journey.
Why these instructions exist
The CI onboarding flow has more moving parts than signup, and the parts
have an order: you can't trigger a build before the app is finished, you
can't sign without the credential uploaded, and you can't push to a private
repo without the SSH key registered. This skill is the recipe.
It also branches by platform (iOS vs. Android) at two points: project
config selection and credential upload. Read the platform-specific section
for the user's platform; ignore the other.
Preconditions
- The user must have a working Bitrise PAT in the MCP. Sanity-check by
calling
me first — if it errors, route the user to bitrise-signup.
- The user must be on the
agentic-onboarding branch's MCP for the
signing-upload tools (upload_build_certificate,
upload_provisioning_profile, upload_android_keystore_file) to be
available. The hosted mcp.bitrise.io does not have these yet. If the
signing tools error with "tool not found", fall back to the manual web
upload — see "Fallback: web-based credential upload" below.
The flow
1. Confirm context: workspace, platform, repo
Before calling any tools, gather four things by asking the user:
- Workspace. Call
list_workspaces. If there's exactly one, use it. If
there are several, present the list and ask the user to pick. Capture the
workspace_slug.
- Platform. iOS or Android? This decides the project config and the
signing flow.
- Repository URL. Confirm the full URL (e.g.,
https://github.com/acme/cool-app.git). Confirm whether it's public or
private — private repos need SSH key registration.
- Git provider. GitHub, GitLab, Bitbucket, or self-hosted variants?
Defaults to
github if unsure but ask.
If the user hasn't connected the provider's account to Bitrise yet, call
get_provider_connect_url with the chosen provider. Open the returned URL
in their browser, ask them to complete the OAuth flow, then poll
list_connected_accounts until the provider shows as connected. Don't move
on until it is.
2. Register the app
Call register_app with:
repo_url: as confirmed above
is_public: boolean from the user's answer
organization_slug: the workspace slug
provider: e.g., github
default_branch_name: ask the user; default to main. (The MCP defaults
to master, which is wrong for most modern repos.)
Capture the returned app_slug. The MCP description says not to prompt for
finishing the app — chain straight into the next step.
3. Register the SSH key (private repos only)
For a private repo, build won't be able to clone without an SSH key. The
prospect probably doesn't have one ready. Two options:
- Have the MCP generate one for them. Generate an ed25519 keypair on
the user's machine via shell:
ssh-keygen -t ed25519 -f bitrise_deploy_key -N "" -C "bitrise-<app-slug>".
Read both files. Then call register_ssh_key with app_slug,
auth_ssh_private_key, auth_ssh_public_key, and
is_register_key_into_provider_service: true so Bitrise auto-registers
the public key as a deploy key on GitHub/GitLab/Bitbucket. Delete the
local keypair files after — they're only needed for the upload.
- Have the user paste an existing key. If they already have a deploy
key, ask for both halves. Same
register_ssh_key call, but set
is_register_key_into_provider_service: false.
For a public repo, skip this step.
4. Pick a stack and finish setup
Call list_available_stacks (pass workspace_slug to include workspace
custom stacks). Pick a sensible default for the platform — for iOS, the
latest macOS stack; for Android, the latest linux-docker-android-22.04 or
similar. Tell the user which stack you picked and why; let them override.
Then call finish_bitrise_app with:
app_slug: from step 2
project_type: ios or android (or flutter, react-native, etc. if
the user said so)
stack_id: from above
config: a starter config that matches the project type. Common values:
default-ios-config, default-android-config-kts,
default-flutter-config-android, default-react-native-config, etc.
Per the MCP tool description, don't prompt the user before this call —
just run it.
5. Register a webhook
Call register_webhook with app_slug. This makes git pushes auto-trigger
builds, which is what the user expects from CI. Skip if the user
explicitly asked for manual-only triggering.
6. Set up signing credentials
This is where the flow forks by platform. For the very first build,
consider whether signing is even needed yet. The default starter configs
build & test on every push but don't always require distribution signing.
If the user just wants to see a green build, you can skip this step on the
first run and circle back when they want to ship to TestFlight / Play
Console / Release Management.
If signing IS needed:
iOS
Two files must be uploaded: a .p12 build certificate and a
.mobileprovision provisioning profile. Ask the user where on disk both
files live. The MCP reads them from the local filesystem (the file_path
arg is read with os.ReadFile), so the files must be reachable to whatever
process the MCP runs as — practically, the user's machine.
upload_build_certificate with app_slug, file_path (absolute path to
.p12), and certificate_password if the cert is password-protected.
Returns the API response; capture data.slug if you want to chain
updates.
upload_provisioning_profile with app_slug, file_path (absolute path
to .mobileprovision).
If the user doesn't have a build certificate or provisioning profile yet,
walk them through generating them in Xcode → Apple Developer portal, or
suggest the workspace-level "Apple API key" automatic provisioning flow
(set up in the Bitrise web UI at workspace settings; the MCP doesn't expose
it). Don't fabricate certs.
Android
A keystore (.jks or .keystore) plus its alias and two passwords:
upload_android_keystore_file with app_slug, file_path (absolute
path to keystore), alias, keystore_password, private_key_password.
All five are required.
If the user doesn't have a keystore yet and just wants a green build, the
default Android config will use the auto-generated debug keystore, which
ships with the Android SDK. Skip the upload and only set up a release
keystore when the user is ready to publish.
Fallback: web-based credential upload
If the MCP signing tools aren't available (e.g., user's on the hosted
mcp.bitrise.io), point them at the Code Signing tab of the Workflow
Editor:
https://app.bitrise.io/app/<app_slug>/workflow_editor#code-signing. The
upload UI there is the same flow, just in a browser. Don't pretend the
tools work and then fail.
7. Trigger the first build
Call trigger_bitrise_build:
app_slug: from step 2
branch: the default branch the user confirmed (main, usually)
workflow_id: leave empty to use the config's default workflow
(typically primary or deploy), or pass one explicitly if the user has
a preference
Capture the returned build_slug and build_url. Share build_url with
the user immediately so they can watch in the browser if they want.
8. Wait for the build
Poll get_build with build_slug until the status field changes from 0
(not finished) to 1 (success), 2 (failed), or 3 (aborted). Status code 4
means in-progress. Reasonable polling cadence: every 10–15 seconds for the
first minute, then every 30 seconds. Tell the user roughly how long mobile
builds take (5–15 minutes is typical) so they don't think it's hung.
If the build succeeds: report the build URL, the duration, and offer to
move on to Release Management (bitrise-release-management) if they want
a public install page.
If the build fails: call get_build_log with build_slug and read the
log. Look for the failing step. Common first-build failures and how to
respond:
- Clone failure on a private repo: SSH key not registered or not
authorized at the provider. Re-run step 3 and confirm the deploy key
shows up at github.com//settings/keys.
- Code signing error on iOS: Provisioning profile mismatch or wrong
bundle ID. Surface the error message to the user and suggest the
automatic provisioning flow.
- Stack mismatch: Build expects an Xcode/Java version not on the
chosen stack. Re-run
finish_bitrise_app with a different stack_id,
or edit the bitrise.yml directly via get_bitrise_yml →
update_bitrise_yml.
Don't paper over a failed first build — the user wants to know what's
wrong, not be told everything's fine.
Hand-off to Release Management
When the build is green and the user wants a public install page, call
bitrise-release-management and pass:
workspace_slug
app_slug
platform
build_slug (latest successful build)
- The bundle ID (iOS) or package name (Android) — the user will know this
or you can extract it from the build artifact
Things to watch out for
- The MCP's
register_app defaults default_branch_name to master.
Almost always wrong now — ask the user.
finish_bitrise_app is mandatory. A register_app'd app without
finish_bitrise_app is in a half-configured state and won't build. The
MCP description tells the agent to chain immediately.
- Tool description for
register_app says "always prompt the user to
choose which workspace if they have multiple". Honor this — don't
silently pick the first one.
- Build status codes: 0=not finished (queued), 1=success, 2=failed,
3=aborted, 4=in-progress. Don't conflate "not finished" with "failed".
- Don't put PATs, keystores, or
.p12 contents into the chat. All of
these are secrets. Reference them by file path or by Bitrise slug.
- The signing-upload tools read files from local disk. They only work
in stdio mode (or against an MCP server with access to the same
filesystem as the file). HTTP-hosted MCPs can't read the user's local
disk; in that case use the web fallback.