Scripting & CI/CD
Use JSON output, jq, and environment variables to automate deployments in GitHub Actions, GitLab CI, and shell scripts.
What you'll be able to do after this module
Wire the Skytells CLI into automated pipelines — deploy on every push, verify the result, and fail the build if something goes wrong.
Prerequisites
- Modules 1–4 complete
- Familiarity with your CI platform (GitHub Actions examples used throughout; the pattern translates directly to GitLab CI, CircleCI, etc.)
The foundation: JSON output
Every CLI command supports --json. In interactive mode you get formatted tables. In scripts, you want structured data you can parse.
# Human-readable
skytells apps ls
# Machine-readable
skytells apps ls --jsonAdd jq to process it:
# Just the app names
skytells apps ls --json | jq '.[].name'
# App IDs where status is running
skytells apps ls --json | jq '[.[] | select(.status == "running") | .id]'
# Latest deployment status for a specific app
skytells deployments ls --app my-api --limit 1 --json | jq -r '.[0].status'Authenticating in CI
Never store credentials in code or config files. Use your CI platform's secrets manager.
The CLI picks up two environment variables automatically:
| Variable | What it is |
|---|---|
SKYTELLS_TOKEN | Your personal access token (from console.skytells.ai/settings/tokens) |
SKYTELLS_ACCESS_KEY | The project access key (from your project Settings in the Console) |
When both are set, no skytells login step is needed. The CLI uses them directly.
GitHub Actions
Basic deploy workflow
Create .github/workflows/deploy.yml:
name: Deploy to Skytells
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Install Skytells CLI
run: npm install -g @skytells/cli
- name: Deploy
env:
SKYTELLS_TOKEN: ${{ secrets.SKYTELLS_TOKEN }}
SKYTELLS_ACCESS_KEY: ${{ secrets.SKYTELLS_ACCESS_KEY }}
run: skytells deploy my-api
- name: Verify deployment
env:
SKYTELLS_TOKEN: ${{ secrets.SKYTELLS_TOKEN }}
SKYTELLS_ACCESS_KEY: ${{ secrets.SKYTELLS_ACCESS_KEY }}
run: |
STATUS=$(skytells deployments ls --app my-api --limit 1 --json | jq -r '.[0].status')
echo "Deployment status: $STATUS"
if [ "$STATUS" != "success" ]; then
echo "Deployment did not succeed"
exit 1
fiIn GitHub:
- Go to your repository → Settings → Secrets and variables → Actions.
- Add
SKYTELLS_TOKEN— your personal access token. - Add
SKYTELLS_ACCESS_KEY— the access key from your project.
Use a token with only the scopes you need for CI: projects.read, deployments.read, deployments.write. Don't use a token with keys.write or account.read in CI unless the pipeline specifically needs those.
Deploy multiple apps in sequence
- name: Deploy API
run: skytells deploy api-server
- name: Deploy Worker
run: skytells deploy worker
- name: Verify all apps are running
run: |
STATUS=$(skytells status --json | jq -r '.apps[] | select(.status != "running") | .name')
if [ -n "$STATUS" ]; then
echo "Apps not running: $STATUS"
exit 1
fi
echo "All apps running"Update environment variables before deploying
- name: Update environment
run: |
skytells env set --app my-api \
COMMIT_SHA=${{ github.sha }} \
BUILD_NUMBER=${{ github.run_number }}
- name: Deploy
run: skytells deploy my-apiGitLab CI
stages:
- deploy
deploy:
stage: deploy
image: node:18
before_script:
- npm install -g @skytells/cli
script:
- skytells deploy my-api
- |
STATUS=$(skytells deployments ls --app my-api --limit 1 --json | jq -r '.[0].status')
if [ "$STATUS" != "success" ]; then exit 1; fi
variables:
SKYTELLS_TOKEN: $SKYTELLS_TOKEN
SKYTELLS_ACCESS_KEY: $SKYTELLS_ACCESS_KEY
only:
- mainSet SKYTELLS_TOKEN and SKYTELLS_ACCESS_KEY in Settings → CI/CD → Variables in GitLab, marked as masked and protected.
Shell scripting patterns
Deploy and wait for confirmation
The CLI's deploy command is non-blocking — it starts the build and exits. To wait for a result, poll the deployment list:
#!/bin/bash
set -euo pipefail
APP="my-api"
echo "Triggering deployment..."
skytells deploy "$APP"
echo "Waiting for deployment to complete..."
MAX_ATTEMPTS=20 # ~5 minutes at 15s intervals
ATTEMPTS=0
while [ "$ATTEMPTS" -lt "$MAX_ATTEMPTS" ]; do
STATUS=$(skytells deployments ls --app "$APP" --limit 1 --json | jq -r '.[0].status')
if [ "$STATUS" = "success" ]; then
echo "Deployment succeeded"
exit 0
elif [ "$STATUS" = "failed" ]; then
echo "Deployment failed"
skytells logs "$APP" --type deployment --tail 50
exit 1
fi
echo "Status: $STATUS — waiting..."
sleep 15
ATTEMPTS=$((ATTEMPTS + 1))
done
echo "Timed out waiting for deployment"
exit 1Check whether a specific app is running before deploying
#!/bin/bash
APP_ID="abc123"
STATUS=$(skytells apps inspect "$APP_ID" --json | jq -r '.status')
if [ "$STATUS" = "stopped" ]; then
echo "App is stopped — starting before deploy"
skytells apps start "$APP_ID"
sleep 5
fi
skytells deploy "$APP_ID"Rotate a secret across all apps in a project
#!/bin/bash
NEW_SECRET=$(openssl rand -hex 32)
APP_IDS=$(skytells apps ls --json | jq -r '.[].id')
for ID in $APP_IDS; do
echo "Updating SECRET_KEY for app $ID"
skytells env set --app "$ID" SECRET_KEY="$NEW_SECRET"
done
echo "Redeploying all apps..."
for ID in $APP_IDS; do
skytells apps redeploy "$ID"
done
echo "Done. Monitor logs with: skytells logs <app> --type deployment --follow"Putting it all together: a production deploy checklist
#!/bin/bash
# Full production deploy with checks
set -euo pipefail
APP="my-api"
echo "=== Pre-deploy checks ==="
skytells status
echo "=== Updating build metadata ==="
skytells env set --app "$APP" DEPLOYED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "=== Deploying ==="
skytells deploy "$APP"
echo "=== Streaming deployment logs ==="
# Stream for up to 3 minutes, then exit regardless
timeout 180 skytells logs "$APP" --type deployment --follow || true
echo "=== Verifying status ==="
FINAL_STATUS=$(skytells deployments ls --app "$APP" --limit 1 --json | jq -r '.[0].status')
if [ "$FINAL_STATUS" = "success" ]; then
echo "✓ Deployment succeeded"
skytells status
else
echo "✗ Deployment status: $FINAL_STATUS"
exit 1
fiQuick reference
| What you want | Command or pattern |
|---|---|
| JSON output for any command | <command> --json |
| Parse with jq | <command> --json | jq '<expression>' |
| CI authentication | SKYTELLS_TOKEN + SKYTELLS_ACCESS_KEY env vars |
| Deploy in CI | skytells deploy <app> |
| Check latest deploy status | skytells deployments ls --app <id> --limit 1 --json | jq -r '.[0].status' |
| Stream logs (time-limited) | timeout <seconds> skytells logs <app> --follow || true |
You've completed the CLI path
You now know how to install and authenticate, manage projects and apps, deploy and debug, configure environment variables, and automate everything in CI pipelines.
Want to go deeper? Check out:
- Cognition Monitoring → — observe your apps: errors, security events, runtime health, and anomalies
- Orchestrator Mastery → — build automated multi-step workflows on top of your deployed apps