Tooling
CLI
One terminal tool for setting up SDK integrations, verifying configurations, shipping OTA releases (Flutter + React Native), managing flags + config + symbols, and seeding demos.
The Sankofa CLI is a Node-based command-line tool published as sankofa-cli on npm with binary name sankofa. It handles project-level operations: SDK setup, integration verification, OTA releases for both Flutter and React Native, feature flag and config management, error-tracking symbol uploads, signing-key management, and demo seeding.
Flutter ships Dart code patches; React Native ships JavaScript bundles — both App Store + Play Store compliant. Same release / patch / deploy syntax for both — the CLI detects the stack and runs the right pipeline.
Install
npm install -g sankofa-cliRequirements
- Node.js 18+
- For iOS builds: macOS + Xcode
- For Android builds: Android SDK + JDK 17
Quick start
# 1. Log in to your Sankofa account (one-time)
sankofa login
# 2. Set up the project — auto-detects platform, patches native files
sankofa init # interactive picker
sankofa init --deploy # install Sankofa Deploy
sankofa init --catch # install Sankofa Catch
sankofa init --all # install everything available for this stack
# 3. Verify everything is wired up
sankofa doctorFor Flutter (OTA patches):
sankofa init --deploy # scaffold the whole Deploy setup in a Flutter project
sankofa release android # ship the first base release
sankofa patch android # push a Dart-only patch
sankofa patch ios # push an iOS patch (App Store compliant)For React Native (analytics + OTA deploy):
sankofa release ios # ship the first base release
sankofa patch ios # push a JS-only patchTop-level commands
The CLI exposes these top-level commands:
| Command | Purpose |
|---|---|
init | Set up Sankofa in any project. Auto-detects platform; pass --deploy/--catch/--flag/--config/--all to skip the picker. |
check | Verify SDK integration is correct. |
doctor | Low-level toolchain diagnostics (Node, Xcode, Java, Flutter, Sankofa native wiring). |
login / logout | Browser-based or CI-token authentication. |
switch | Switch the active project / environment. |
release | Build + publish a base release (Flutter or React Native). |
patch | Ship a code-only OTA patch against an existing base release. |
deploy | Smart deploy — auto-picks release (first time) or patch (subsequent). |
preview | Download + install a published release locally. |
status | Show all releases for the current project. |
releases / patches | List + manage releases / patches (rollout, kill-switch, mandatory). |
rules | Manage deployment gating rules. |
schedule | Manage rollout schedules. |
defaults | Manage default configurations per project. |
dist | Build the signed store binary (no OTA). |
submit | Upload signed binary to App Store Connect / Play Console. |
keys | Manage Sankofa Deploy signing keys. |
engine | Manage the cached Sankofa Flutter runtime. |
flags | Manage feature flags (Switch). |
config | Manage remote config items. |
catch | Catch / error-tracking triage + symbol upload. |
demo | Seed demo flags + config items. |
update | Update everything Sankofa knows about — CLI, bundled Flutter, engine cache, project SDK. |
upgrade | Update the CLI binary to the latest npm release. |
Setup commands
sankofa init
Idempotent — safe to re-run. Creates .sankofa.json, updates .gitignore, and handles platform-specific native setup. Re-running on an already-configured project skips each step that's already in place (it does not duplicate or overwrite).
sankofa init # interactive product picker
sankofa init --deploy # install Sankofa Deploy (OTA)
sankofa init --catch # install Sankofa Catch (errors)
sankofa init --flag # install Sankofa Switch (flags)
sankofa init --config # install Sankofa Config
sankofa init --all # install everything available for this stack
sankofa init --endpoint https://api.sankofa.dev --project-id proj_...
sankofa init --force # overwrite existing .sankofa.jsonFor Flutter, sankofa init --deploy does the full setup automatically (see the Flutter SDK page): adds the Sankofa Flutter SDK, creates sankofa.yaml, wires lib/main.dart, and patches the Android + iOS native files. Then run sankofa login — it fills sankofa.yaml's app_id and api_key from the project you select, so there's nothing to paste. init and login are order-independent; whichever you run first, the other completes the setup.
sankofa check
Verifies SDK integration with detailed pass/fail output:
sankofa check # all modules
sankofa check analytics # analytics-specific
sankofa check deploy # deploy-specific
# • React Native: full SDK / native / credentials / server check
# • Flutter: defers to `sankofa doctor` (richer Flutter-specific checks)sankofa doctor
Toolchain + integration diagnostics. Reports Node, Xcode, Java/Gradle, Flutter SDK, Android SDK, server reachability, and the full Sankofa Deploy wiring for Flutter projects (sankofa.yaml, pubspec dependency, native meta-data, MainActivity / AppDelegate, bundled Sankofa Flutter SDK + runtime cache state).
sankofa doctor # full toolchain + integration check
sankofa doctor --deploy # focus on Sankofa Deploy wiring onlyAuthentication
sankofa login
Browser-based OAuth-style login. Creates a Deploy Token bound to the selected project.
sankofa login
sankofa login --deploy-token sk_deploy_... --project-id proj_... # CI/CD
sankofa login --region eu # pin EU residencysankofa logout / sankofa switch
sankofa logout # both project + global scopes
sankofa logout --project # project-scoped only
sankofa switch # change to a different project without re-authDeploy commands (Flutter + React Native)
The same release / patch / deploy / preview / status commands work for both Flutter and React Native projects — the CLI detects the stack from your pubspec.yaml / package.json and runs the right pipeline.
sankofa release
Build and publish a base release — signed native binary + OTA-ready payload in one step.
# Flutter
sankofa release android # produces an AAB by default
sankofa release android --apk # produce an APK (sideload-installable)
sankofa release ios # produces a signed .ipa for App Store
sankofa release android --publish --rollout 50 --description "v1.2.0"
sankofa release --dry-run android # build + run the safety check locally, no upload
# Flavored apps (gradle flavors + per-flavor entrypoint)
sankofa release android --flavor staging -t lib/main_staging.dart
sankofa release ios --flavor staging -t lib/main_staging.dart
# Also upload an installable preview build (see preview --from-server)
sankofa release android --preview-artifact
# React Native (identical syntax)
sankofa release ios
sankofa release android --publish --rollout 50 --description "v1.2.0"For Flutter, iOS builds a signed .ipa for App Store Connect / TestFlight (or just the .xcarchive with --no-codesign) and Android builds your .aab (or --apk); both register the release so sankofa patch can ship code updates on top.
Useful flags:
--flavor <name>/-t, --target <file>— Flutter product flavor + per-flavor entrypoint (e.g.--flavor staging -t lib/main_staging.dart). Required for flavored apps.--no-codesign— iOS: build the.xcarchivewithout signing (sign + export later in Xcode).--preview-artifact— also build + upload an installable preview build so teammates can run this release withsankofa preview --from-server. Android (APK) for Flutter + React Native; an iOS simulator app for React Native only. Flutter iOS isn't supported (a physical iPhone can't install a downloaded build) — usesankofa preview iosor TestFlight.--apk/--appbundle— Android format selector (Flutter + RN).--dry-run— build locally + capture the patch-safety-check baseline, but do not contact the server.--upload-mapping <path>/--upload-dsym <path>/--upload-dart-symbols <path>— attach Android mapping / iOS dSYMs / Flutter symbols for Catch symbolication.
sankofa patch
Ship a code-only update against an existing base release. No native build, no App Store / Play Store resubmission.
# Flutter — code-only patch
sankofa patch android
sankofa patch ios # iOS — App Store compliant
sankofa patch android --publish --rollout 25 --description "fix crash on Pixel 6"
sankofa patch ios --target-binary-version 1.2.0 --label hotfix-12
sankofa patch ios -t lib/patch_staging.dart # pick a specific patch entry-point
# React Native — JS bundle patch
sankofa patch ios --publish --mandatory
sankofa patch android --rollout 50Flutter options:
-t, --target <file>— the patch entry-point to compile (defaultlib/sankofa_patch.dart). Use it when you keep several patch entries and want to ship one;--entry-fileis an alias.--target-binary-version <semver>— match the host app's published version exactly (pubspec.yaml.version).--label <label>— patch label override.
sankofa deploy
Smart wrapper that picks release (no prior release exists) or patch (subsequent runs) automatically. Useful for one-shot CI scripts.
sankofa deploy android
sankofa deploy ios --rollout 50
sankofa deploy --dry-run androidsankofa preview / sankofa status
preview runs your app for QA. For React Native it downloads + installs a published release on a simulator/emulator. For Flutter there are two modes:
- Local run (default) — runs your current source on a device via the Sankofa Flutter runtime, passing
--flavor,-t/--target,-d/--device, and the build mode (--release/--profile/--debug). - From server (
--from-server, or implied by--label/--version) — Android only: downloads a published release and installs it on an Android device/emulator, so a tester can run a specific build without your source. Requires the release to have been published with--preview-artifact. iOS can't install a downloaded build on a device — use Local run for QA or TestFlight for on-device.
# React Native — install a published release on a simulator
sankofa preview ios
sankofa preview ios --label v1.2.0-patch.3
# Flutter — local run (your current source)
sankofa preview -d <device-id> --flavor staging -t lib/main_staging.dart
# Flutter — run a published Android release from the server (no source needed)
sankofa preview android --from-server --label v1.2.0 -d <adb-serial>
# (iOS has no server preview — run 'sankofa preview ios' locally, or use TestFlight)
# Dashboard of releases
sankofa status
sankofa status --env live --platform iossankofa releases / sankofa patches
Read-only listing of releases / patches. Useful for CI scripts that need to fetch the current release SHA without dashboard access.
sankofa rules / sankofa schedule / sankofa defaults
Manage deployment-time gating: rules to halt rollouts, schedules for time-based releases, default configurations per project.
sankofa dist / sankofa submit
# Build only the signed store binary, no OTA
sankofa dist ios
sankofa dist android --android-format aab
# Upload signed binary to App Store Connect or Play Console
sankofa submit ios --apple-api-key-id ABC --apple-api-issuer UUID
sankofa submit android --google-service-account ~/sa.json --google-track internalFlutter Deploy: signing keys + engine
These commands are Flutter-specific and become relevant once you've run sankofa init --deploy. The setup writes .sankofa/flutter-version (a pin file) and sankofa.yaml (project keys) that the commands below read automatically.
sankofa keys — signing keys
Every Flutter patch is signed with the project's private key, and the server + SDK both verify the signature before applying. Keys are project-scoped — generate one per project and back up the private key.
sankofa keys generate # generate a keypair for the current project
sankofa keys generate --force # overwrite (invalidates already-shipped patches)
sankofa keys show # print the base64 public key (embed in host app or server)
sankofa keys path # print the local private key path (for backup)
sankofa keys register # POST the public key to the server so it verifies patch signatures at upload timeKeys are stored at ~/.config/sankofa/keys/<project_id>.ed25519. Add the directory to your secrets manager — losing the key means you can't ship signed patches against existing releases without a coordinated rotation.
sankofa engine — Sankofa Flutter runtime
The CLI manages the Sankofa Flutter runtime + bundled SDK locally, verifying integrity against the registry on each download.
sankofa engine list # what's installed + what's available
sankofa engine download # download the runtime for the current project's pinned version
sankofa engine install [version] # install the bundled Sankofa Flutter SDK + runtime in one shot
sankofa engine verify # re-verify the cached runtime against the registry
sankofa engine path # print the cache root (useful in shell scripts)The cache lives at ~/.sankofa/engines/. sankofa init --deploy already runs engine install for you — the explicit commands are for upgrades and CI cache priming.
sankofa update — keep the whole stack fresh
The full Sankofa stack on a developer machine has four moving parts: the CLI itself, the bundled Sankofa Flutter SDK, the engine cache, and the per-project pub.dev SDK. update checks each one in a single sweep.
sankofa update # check + apply updates to all four surfaces
sankofa update --check # dry-run — report what would be updated, change nothing
sankofa update --only cli # bump the CLI only
sankofa update --only flutter # refresh the bundled Sankofa Flutter SDK only
sankofa update --only engine # refresh the engine cache only
sankofa update --only sdk # `flutter pub upgrade sankofa_flutter` in the current projectsankofa upgrade — bump the CLI binary itself
Just the CLI — update covers the broader stack; upgrade is the focused "newer version of sankofa-cli on npm" check.
sankofa upgrade # check + install if a newer version exists
sankofa upgrade --check # dry-run — report only
sankofa upgrade --sudo # use sudo for the install (CI scripts that already plan for it)macOS perms note. On a default macOS setup the global npm prefix is /usr/local/lib/node_modules (root-owned), so npm install -g … fails with EACCES. sankofa upgrade detects that case and auto-retries the install under sudo — you'll be prompted for your password on stdin once, then the upgrade proceeds. In non-interactive contexts (CI, piped output) the CLI prints the exact remedy instead of popping a hidden password prompt:
sudo npm install -g sankofa-cli@latest
(or: sankofa upgrade --sudo)A user-writable npm prefix (e.g. via nvm) avoids the sudo retry altogether.
Switch commands
Flag CRUD authenticates with your dashboard JWT (not the Deploy Token) — flag operations need full user + project-role RBAC.
Flag subcommands
sankofa flags list # list all flags
sankofa flags list --env test --include-archived # include archived
sankofa flags get new_checkout # show full details
sankofa flags create new_checkout --description "..." --default false
# Progressive rollout
sankofa flags toggle new_checkout 10 # 10%
sankofa flags toggle new_checkout 50 # 50%
sankofa flags toggle new_checkout 100 # full
# Kill switch
sankofa flags halt new_checkout --reason "spike in errors"
sankofa flags resume new_checkout
sankofa flags archive new_checkout # archive
# Stale-flag scanner
sankofa flags scan
sankofa flags scan --strict # fail CI on warningsThe stale-flag scanner walks your code for .getFlag(...) and .getVariant(...) calls across JS/TS/Dart/Swift/Kotlin and cross-references the keys against the server.
Config commands
sankofa config list
sankofa config list --env test
sankofa config get max_upload_mb
# Type is required on create; updates require matching type.
sankofa config set max_upload_mb int 25 --description "Max file upload"
sankofa config set support_url string "https://support.acme.com"
sankofa config set trial_discount_pct float 0.2
sankofa config set maintenance_banner_enabled bool true
sankofa config set pricing json '{"pro":9.99,"growth":49}'
sankofa config history max_upload_mb
sankofa config history max_upload_mb --limit 5
# Non-destructive — writes a new version whose snapshot matches the target.
sankofa config rollback max_upload_mb 3 --note "revert accidental bump"Catch commands
Error-tracking triage and symbol management:
# Issue triage
sankofa catch issues list
sankofa catch issues get isu_abc123
sankofa catch issues assign isu_abc123 --to [email protected]
# Event inspection
sankofa catch events list --issue isu_abc123
sankofa catch events get evt_xyz789
# Alerts
sankofa catch alerts list
sankofa catch alerts test alt_def456
# Symbol upload (sourcemaps, dSYM, ProGuard mapping, NDK, Flutter)
sankofa catch symbols upload --kind js_sourcemap --release "$RELEASE_SHA" --dir ./dist
sankofa catch symbols upload --kind dsym --release "$RELEASE_SHA" --dir ./build/dSYMs
sankofa catch symbols upload --kind proguard_mapping --release "$RELEASE_SHA" --file ./build/outputs/mapping/release/mapping.txt
sankofa catch symbols upload --kind ndk --release "$RELEASE_SHA" --dir ./obj
sankofa catch symbols upload --kind flutter --release "$RELEASE_SHA" --dir ./build/symbols
sankofa catch symbols list --release "$RELEASE_SHA"
sankofa catch symbols delete --kind js_sourcemap --id sym_abc
# Statistics
sankofa catch stats --since 7d
# Reverse-lookup obfuscated stacks
sankofa catch symbolicate --release "$RELEASE_SHA" --stack ./crash.txt
# Manifest helpers (used by CI integrations)
sankofa catch make-dsym-manifest --dir ./build/dSYMs
sankofa catch make-ndk-manifest --dir ./objThe symbols upload subcommand replaces what was historically a top-level sourcemaps upload — there's no separate sourcemaps command today.
Demo fixtures
sankofa demo seed
sankofa demo seed
sankofa demo seed --force # overwrite existing values
sankofa demo seed --skip-flags # only seed config items
sankofa demo seed --skip-config # only seed feature flagsCreates 6 flags + 6 config items used by every Sankofa example app — new_home_layout, checkout_cta_variant, onboarding_v2_rollout, ai_summary_kill_switch, ab_pricing_page, premium_badge_visible (flags) and support_url, max_uploads_per_day, trial_discount_pct, maintenance_banner_enabled, pricing_table, theme_colors (config).
Authentication resolution
Credentials are resolved in this order (highest wins):
Environment variables
SANKOFA_DEPLOY_TOKEN,SANKOFA_JWT,SANKOFA_PROJECT_ID,SANKOFA_ENDPOINT,SANKOFA_ENVIRONMENT.Project config
.sankofa.jsonin the project root (created bysankofa init).Global config
~/.sankofa/credentials.json(written bysankofa login).
Environment variables
| Variable | Purpose |
|---|---|
SANKOFA_DEPLOY_TOKEN | CI-friendly Deploy auth token. |
SANKOFA_JWT | CI-friendly dashboard JWT. |
SANKOFA_PROJECT_ID | Project ID. |
SANKOFA_ENDPOINT | Server base URL. |
SANKOFA_ENVIRONMENT | live or test. |
Build artifact identifiers
| Field | Value |
|---|---|
| npm package | sankofa-cli |
| Binary name | sankofa |
| Version | latest on npm |