Bitcoin-native smart contract stack with in-process steganography detection, proposals, funding, and verified work—all built on Bitcoin with smart contracts, escrow, and dispute resolution.
Helm chart for the Stargate single binary, with optional Postgres and IPFS. Stego detection (Trin/GGUF) runs in-process inside Stargate; there is no separate starlight-api pod.
# 1. Create secrets (required for authentication)
kubectl create secret generic stargate-stack-secrets \
--from-literal=stargate-api-key="stargate-api-$(date +%s)-$(openssl rand -hex 8)" \
--from-literal=stargate-ingest-token="stargate-ingest-$(date +%s)-$(openssl rand -hex 8)"
# 2. Deploy with secrets
helm install stargate-stack . \
--set secrets.createDefault=false \
--set secrets.name=stargate-stack-secrets \
--set secrets.stargateApiKey=true \
--set secrets.stargateIngestToken=true
# 3. Verify deployment
kubectl get pods
kubectl port-forward svc/stargate 3001:3001 &
curl http://localhost:3001/api/health- Docker/Helm/Kubectl access to a cluster (kind/minikube/Docker Desktop OK).
- Image available locally or in a registry:
stargate:latest(built fromstargate/Dockerfile) ormacroadster/stargate:v1
image.stargate.repository/tag: Stargate image (defaultmacroadster/stargate:v1)image.postgres.repository/tag: Postgres (defaultpostgres:15, only ifpostgres.enabled)postgres.enabled: deploy in-cluster Postgres (defaultfalse; use SQLite on the data PVC)postgres.*: credentials/PVC size when enabled- Storage: one PVC (
stargate-blocks-pvc) mounted atstargate.dataDir(default/data) for blocks, uploads, model cache, SQLite DBs under/data/sqlite/, and btcd chainstate under/data/btcd. Size controlled bystargate.blocksStorage(default 50Gi for testnet4 full node + indexes);stargate.storageClasscan set a class. Expanding an existing 1Gi claim requires StorageClass volume expansion or a new PVC. stargate.storage:sqlite(default),postgres,memory, orfilesystemstargate.dataDir: in-container data root (default/data); SQLite files at{dataDir}/sqlite/{mcp,api_keys,ingestions,blocks}.dbstargate.pgDsn: DSN for Postgres mode (postgres://stargate:stargate@stargate-postgres:5432/stargate?sslmode=disable)- Postgres → SQLite migration: build
backend/cmd/migrate-pg-to-sqlitein stargate, run against the live PG DSN with--target-dir /data/sqlite(on the PVC), verify, then setstargate.storage=sqliteandpostgres.enabled=falseand upgrade. stargate.proxyBase: optional external proxy base (default empty; kept for operator override viaSTARGATE_PROXY_BASE)stargate.bitcoinNetwork: Bitcoin network (testnet4default; alsotestnet,signet,mainnet)- btcd full node (no mining) — Stargate manages
btcdin the same container (see stargate ADR 0006):stargate.btcd.mode:managed(default) |external|offstargate.btcd.bin: path to btcd binary (image ships/usr/local/bin/btcd)stargate.btcd.dataDir: empty →{dataDir}/btcdon the data PVC (must persist)stargate.btcd.rpcHost/rpcUser/rpcPass: empty uses network defaults + auto auth filestargate.btcd.p2pPort/p2pListen: testnet4 default48333; setp2pServiceEnabled: trueto expose on the ClusterIP Serviceingress.btcdP2p.*: optional LoadBalancer/NodePort (stargate-btcd-p2p) for inbound peers (mirrorsingress.ipfsSwarm); setenabled: trueand ensurep2pPort> 0stargate.btcd.txIndex/addrIndex: defaulttrue(required for historical txs / address UTXOs)stargate.btcd.allowMainnet: defaultfalse(mainnet needs large disk + explicit opt-in)stargate.probes.startup.failureThreshold: default60(~10m) so managed btcd RPC wait does not trip restarts
- Stego detection (native Path A — Trin/GGUF in-process):
stargate.starlightGguf: optional local GGUF path override; empty uses data dir + Hugging Facestargate.starlightHfRepo: HF repo (defaultmacroadster/starlight-prod)stargate.starlightHfFile: model filename (defaultstarlight.gguf)stargate.starlightHfRevision: HF revision (defaultmain)- On first use the model is auto-downloaded under
/data(STARGATE_DATA_DIR=/data)
stargate.ipfs.*: IPFS uploads mirroring configuration (see values for defaults)stargate.ipfs.mirrorEnabled: enable IPFS mirror (defaultfalse)stargate.ipfs.mirrorUploadEnabled: publish local uploads to IPFS (defaulttrue)stargate.ipfs.mirrorDownloadEnabled: fetch uploads announced by peers (defaulttrue)stargate.ipfs.apiUrl: IPFS HTTP API base URL (defaulthttp://stargate-ipfs:5001)stargate.ipfs.mirrorTopic: PubSub topic for sync announcements (defaultstargate-uploads)stargate.ipfs.mirrorPollIntervalSec: local scan interval in seconds (default10)stargate.ipfs.mirrorPublishIntervalSec: manifest publish interval in seconds (default30)stargate.ipfs.mirrorMaxFiles: max files in manifest (default2000)stargate.ipfs.httpTimeoutSec: IPFS HTTP timeout in seconds (default30)stargate.ipfs.ingestSyncEnabled: create ingestion records from mirrored stego uploads (defaultfalse)stargate.ipfs.ingestSyncIntervalSec: poll interval for ingestion sync (default60)stargate.ipfs.ingestSyncManifest: legacy manifest filename (currently unused; defaultstargate-uploads-manifest.json)stargate.ipfs.ingestSyncMaxEntries: max manifest entries processed per tick (default5000)stargate.ipfs.stegoTopic: PubSub topic for stego announcements (defaultstargate-stego)stargate.ipfs.stegoAnnounceEnabled: publish stego announcements on approval (defaulttrue)stargate.ipfs.stegoSyncEnabled: subscribe + reconcile stego announcements (defaulttrue)stargate.ipfs.stegoSyncIntervalSec: retry interval for stego pubsub sync (default10)
stargate.stego.*: stego approval/reconcile config (see values for defaults)stargate.stego.approvalEnabled: publish stego + IPFS payload on approval (defaultfalse)stargate.stego.method: stego method (defaultlsb)stargate.stego.issuer: manifest issuer label (default empty -> hostname)stargate.stego.ingestTimeoutSec: wait for stego ingestion (default30)stargate.stego.ingestPollSec: poll interval for ingestion (default2)stargate.stego.inscribeTimeoutSec: inscribe timeout (default60)stargate.stego.scanTimeoutSec: scan timeout (default30)
ipfs.*: optional Kubo (IPFS) deployment for mirroringipfs.enabled: deploy Kubo service (defaulttrue)ipfs.enablePubsub: enable pubsub experiment for Kubo (defaulttrue)ipfs.apiPort/gatewayPort/swarmPort: IPFS ports (defaults5001/8080/4001)ipfs.storage: PVC size for IPFS repo (default5Gi)ipfs.storageClass: optional storage class for IPFS PVC
stargate.claimTtlHours: claim expiry window exposed to clients (default72)stargate.seedFixtures: whether to load seed contracts/tasks on startup (defaultfalse)stargate.apiKey: optional API key required via headerX-API-Keystargate.enableIngestSync: enable ingestion sync (defaulttrue)stargate.enableFundingSync: enable funding sync (defaulttrue)stargate.fundingProvider: funding provider (defaultblockstream)stargate.fundingApiBase: funding API base URLstargate.ingestSyncInterval: ingest sync interval (default30s)ingress.enabled: optional Ingress (defaults: frontendstarlight.local, backendstargate.local; setingress.className/annotations/tlsas needed)resources.*: set requests/limits for components (defaults provided)hpa.stargate: optional HPA for Stargate (disabled by default)secrets.*: optionally create/use a secret (stargate-stack-secretswith keys:stargate-api-key,stargate-ingest-token)
cd stargate
docker build -t stargate:latest .cd starlight-helm
TIMESTAMP=$(date +%s)
RANDOM=$(openssl rand -hex 8)
kubectl create secret generic stargate-stack-secrets \
--from-literal=stargate-api-key="stargate-api-$TIMESTAMP-$RANDOM" \
--from-literal=stargate-ingest-token="stargate-ingest-$TIMESTAMP-$RANDOM"
helm install stargate-stack . \
--set secrets.createDefault=false \
--set secrets.name=stargate-stack-secrets \
--set secrets.stargateApiKey=true \
--set secrets.stargateIngestToken=truehelm install stargate-stack . \
--set secrets.createDefault=true \
--set secrets.name=stargate-stack-secrets \
--set secrets.stargateApiKey="demo-api-key" \
--set secrets.stargateIngestToken=""| Secret Key | Used By | Purpose |
|---|---|---|
stargate-api-key |
Stargate | API key via header X-API-Key |
stargate-ingest-token |
Stargate | Token for ingestion endpoints |
helm install stargate-stack . \
--set stargate.apiKey="demo-api-key"cd starlight-helm
# Basic installation
helm install stargate-stack . \
--set image.stargate.repository=stargate \
--set image.stargate.tag=latest
# Production installation with secrets
helm install stargate-stack . \
--set secrets.createDefault=false \
--set secrets.name=stargate-stack-secrets \
--set secrets.stargateApiKey=true \
--set secrets.stargateIngestToken=true
# For testnet deployment
helm install stargate-stack . \
--set stargate.bitcoinNetwork=testnet \
--set secrets.createDefault=false \
--set secrets.name=stargate-stack-secrets \
--set secrets.stargateApiKey=true \
--set secrets.stargateIngestToken=true
# Enable ingress (example; update hosts/tls for your cluster)
helm upgrade --install stargate-stack . \
--set ingress.enabled=true \
--set ingress.className=nginx
# For local ingress testing (docker-desktop/minikube with ingress-nginx), add to /etc/hosts:
# 127.0.0.1 starlight.local stargate.local
# TLS: default values expect a secret `stargate-stack-tls` with SANs starlight.local, stargate.local
# kubectl create secret tls stargate-stack-tls --cert=stargate-stack.crt --key=stargate-stack.key
# Then hit:
# curl -kI https://starlight.local/
# curl -kI https://stargate.local/
# Observability
# - Metrics: https://stargate.local/metrics (prometheus format)
# - Service annotations included for Prometheus auto-scrape (prometheus.io/scrape=true)# Check pod status
kubectl get pods
# Check services
kubectl get svc stargate stargate-postgres
# Port forward for testing
kubectl port-forward svc/stargate 3001:3001 &
# Test health endpoint
curl http://localhost:3001/api/healthChart 0.2.0 removes the separate starlight-api Deployment/Service. Detection is in-process in Stargate.
When upgrading an existing cluster:
# After helm upgrade, remove the old resources if they remain
kubectl delete deployment starlight-api --ignore-not-found
kubectl delete service starlight-api --ignore-not-found
kubectl delete hpa starlight-api --ignore-not-found
kubectl delete pdb starlight-api-pdb --ignore-not-found
kubectl delete configmap opencode-config --ignore-not-found
# Optional: drop unused secret keys from an existing secret
# (stargate only needs stargate-api-key and stargate-ingest-token)Also clear any old stargate.proxyBase that pointed at http://starlight-api:8080 (default is now empty).
Set stargate.seedFixtures: true to load demo contracts/tasks when tables are empty (see stargate/backend/mcp/fixtures.go).
- Insert pending records into
starlight_ingestionswith status"pending". - Use Markdown proposals in ingestion metadata as needed.
- Optional env defaults:
STARGATE_DEFAULT_BUDGET_SATSSTARGATE_DEFAULT_FUNDING_ADDRESS
# Confirm API key in secret and pod env
kubectl get secret stargate-stack-secrets -o jsonpath='{.data.stargate-api-key}' | base64 -d; echo
kubectl exec deployment/stargate -- env | grep STARGATE_API_KEY
# Restart after secret changes
kubectl rollout restart deployment/stargatekubectl get secret stargate-stack-secrets -o jsonpath='{.data.stargate-ingest-token}' | base64 -d; echo
kubectl exec deployment/stargate -- env | grep STARGATE_INGEST_TOKEN
kubectl rollout restart deployment/stargate# Confirm HF env and data dir
kubectl exec deployment/stargate -- env | grep -E 'STARLIGHT_|STARGATE_DATA_DIR'
# Model cache lands under /data (PVC stargate-blocks-pvc)
kubectl exec deployment/stargate -- ls -la /data || truekubectl get secret stargate-stack-secrets -o jsonpath='{.data.stargate-api-key}' | base64 -d; echo
kubectl get secret stargate-stack-secrets -o jsonpath='{.data.stargate-ingest-token}' | base64 -d; echokubectl patch secret stargate-stack-secrets --patch='{"data":{"stargate-api-key":"'$(echo -n 'new-api-key' | base64)'"}}'
kubectl rollout restart deployment/stargateTIMESTAMP=$(date +%s)
RANDOM=$(openssl rand -hex 8)
kubectl create secret generic stargate-stack-secrets-new \
--from-literal=stargate-api-key="stargate-api-$TIMESTAMP-$RANDOM" \
--from-literal=stargate-ingest-token="stargate-ingest-$TIMESTAMP-$RANDOM"
kubectl delete secret stargate-stack-secrets
kubectl get secret stargate-stack-secrets-new -o yaml | sed 's/name: stargate-stack-secrets-new/name: stargate-stack-secrets/' | kubectl apply -f -
kubectl delete secret stargate-stack-secrets-new
kubectl rollout restart deployment/stargatehelm uninstall stargate-stack
kubectl delete secret stargate-stack-secrets # Optional: remove secrets