tinqs/ci

CI toolchain for Tinqs Studio — composite Gitea Actions and the Lambda dispatcher that orchestrates Spot runners.

Architecture

Push → Gitea webhook → Lambda (tinqs-ci-dispatch) → EC2 Spot instance → act_runner → job → self-terminate

Runners are ephemeral: one job per instance, self-terminates on completion. Actions are pre-cached on the runner to avoid repeated clones.

Actions

Action What it does
tinqs/ci/checkout@v1 Clone a repo from tinqs.com (supports sparse checkout, depth control, token auth)
tinqs/ci/setup-go@v1 Install Go (skips if pre-baked in AMI)
tinqs/ci/setup-node@v1 Install Node.js + pnpm (skips if pre-baked)
tinqs/ci/setup-aws@v1 Install AWS CLI + optional ECR login
steps:
  - uses: tinqs/ci/checkout@v1
    with:
      sparse: 'cmd/tstudio'
  - uses: tinqs/ci/setup-go@v1
  - uses: tinqs/ci/setup-aws@v1
    with:
      ecr-login: 'true'

Dispatcher (Lambda)

orchestrator/dispatch/main.go — receives Gitea webhooks, evaluates workflow triggers, launches Spot instances with the right label.

Label Instance Use
go t3.small Go builds (tstudio, proxy, docgen)
docker t3.medium Docker image builds (platform, bot)
deploy t3.micro S3 sync, ECS update
node t3.medium Frontend builds
godot t3.medium Game exports (future)

Runner Images

Dockerfiles in images/ — lean, purpose-built. Push to ECR with images/build-all.sh.

Deploying

The dispatcher Lambda can't CI itself — deploy manually:

cd orchestrator/dispatch

# Build
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bootstrap -ldflags "-s -w" .

# Zip (PowerShell on Windows, zip on Mac/Linux)
# Windows:
powershell -Command "Compress-Archive -Path bootstrap -DestinationPath function.zip -Force"
# Mac/Linux:
zip -j function.zip bootstrap

# Deploy
aws lambda update-function-code --region eu-west-1 \
  --function-name tinqs-ci-dispatch \
  --zip-file fileb://function.zip

# Verify
aws lambda invoke --region eu-west-1 --function-name tinqs-ci-dispatch \
  --payload '{}' /dev/null --query 'StatusCode'

Lambda env vars (configured in AWS, not in code):

Var Purpose
GITEA_URL https://tinqs.com
GITEA_TOKEN API token for fetching workflows and runner git auth
RUNNER_TOKEN act_runner registration token
RUNNER_AMI Pre-baked AMI with Go, Node, Docker, act_runner
SUBNET VPC subnet for Spot instances
SECURITY_GROUP SG allowing outbound HTTPS
DDB_TABLE DynamoDB table for run tracking
INSTANCE_PROFILE IAM role for runner instances

Contributing

This repo is private. Only Tinqs team members contribute.

Adding a new action

  1. Create <action-name>/action.yml (composite, shell: bash)
  2. Keep it simple — no Node.js runtime, just bash
  3. Add to the table in this README
  4. Push to main — actions are resolved via @v1 (main branch)

Modifying the dispatcher

  1. Edit orchestrator/dispatch/main.go
  2. Test locally: go build . && echo '{}' | ./dispatch (dry run)
  3. Deploy manually (see Deploying above)
  4. Verify: push a change to tinqs/studio and check the pipeline

Runner images

  1. Edit images/<name>/Dockerfile
  2. Build: cd images && ./build-all.sh v1
  3. Requires Docker + ECR login (aws ecr get-login-password | docker login ...)

Monitoring

# Check for zombie runners (should be 0 except during active builds)
aws ec2 describe-instances --region eu-west-1 \
  --filters "Name=tag:tinqs-ci,Values=true" "Name=instance-state-name,Values=running" \
  --query 'Reservations[].Instances[].InstanceId'

# Lambda dispatch logs
MSYS_NO_PATHCONV=1 aws logs tail '/aws/lambda/tinqs-ci-dispatch' --region eu-west-1

# Build logs (via Gitea API)
curl -s "https://tinqs.com/api/v1/repos/tinqs/studio/actions/jobs/<ID>/logs" \
  -H "Authorization: token $TOKEN"

Full debug guide: tinqs/docs/.cursor/skills/ci-pipeline-discipline/SKILL.md

S
Description
Tinqs CI - composite actions and runner base image
Readme 115 MiB
Languages
Go 79.8%
Dockerfile 13.2%
Shell 7%