Sling
Sign in with GitHub

Sling — Operator & API Reference

How to use Sling → see /onboarding (10-min walkthrough), per-role pages at /producer · /engineer · /exec, or the deeper /guide. This page is the operator + API reference: routes, env vars, schema, runbooks.

Start here

If you're an engineer adding a new repo to Sling, work through these in order:

  1. Add a block to config/repositories.json
  2. Make sure the right GitHub App is installed on the repo (svenlabs-ci-app for SvenLabs-owned repos, gdt-ci-app for GDT)
  3. Set the corresponding env vars on the Sling server (App ID + private-key path + webhook secret)
  4. Restart Sling: pm2 restart sling --update-env
  5. Open a labelled test issue and confirm the next Night Shift cron picks it up

Public routes

What's served and where. All routes below are mounted on https://sling.svenlabs.ai.

Onboarding + presentation (EPIC #441)

RouteAuthPurpose
GET /onboardingpublic10-minute walkthrough — pinnable in Slack
GET /onboarding/:rolepublicproducer | engineer | exec deep dives
GET /onboarding/demopublicSynthetic-ticket replay (canned trace, no live AI calls)
GET /onboarding/deckpublicSlide-deck mode; ?print=1 + ?notes=1
GET /onboarding/sharepublicCopy-pasteable Slack/email/DM templates
GET /og/onboarding.svgpublicSVG OG card for the universal onboarding page
GET /og/onboarding/:variant.svgpublicSVG variants: producer / engineer / exec
GET /og/onboarding.pngpublicPNG OG card (Slack-friendly, rasterized via @resvg/resvg-js)
GET /og/onboarding/:variant.pngpublicPNG variants

Operator surfaces

RouteAuthPurpose
GET /publicPublic homepage with live stats
GET /docspublicThis page
GET /guidepublicRole-based reference guide
GET /workflowpublicWorkflow PDF implementation map (history)
GET /status-pageauthWorker pool depth, recent failures
GET /dashboardauth + orgLive state of every Sling task
GET /dashboard/personalauth + orgPer-user dashboard
GET /dashboard/teamauth + orgTeam dashboard
GET /createauth + orgBrief intake form (creates issues from natural-language briefs)
GET /ticket/:owner/:repo/:issueauth + orgPer-ticket timeline (lifecycle + cost + phases)
GET /e2eauthE2E artifact dashboard
GET /admin/onboarding-statsauth + orgPer-section onboarding telemetry funnel

Webhook + ingest endpoints

RouteAuthNotes
POST /webhook/githubHMAC sigGitHub App + repo webhooks. Per-tenant routing via installation_id.
POST /webhook/slack/eventsSlack sigSlack Events API for AIA bot
POST /webhook/slack/interactionsSlack sigSlack interactivity (buttons in UAT messages)
POST /webhook/cloudwatchAWS CloudWatch alarm webhook
POST /webhook/stripeStripe sigBilling events
POST /api/intentos/ingestHMAC bearerIntentOS spec ingest → creates GitHub issue
POST /api/autodev/ingestHMAC bearerAutoDev specification bundle → creates issue with auto-implement
POST /api/onboarding/eventpublic, DNT-respectOnboarding telemetry beacon (B8)

Comment commands (PR + issue)

Sling reads slash-commands from issue comments and PR comments. The webhook handler dispatches to the matching governance / pipeline action.

CommandStatusEffect
/approveshippedClear governance gate for tasks awaiting human approval
/rejectshippedReject a pending task — it will not run
/retryshipped (#401)Re-enter the pipeline using the latest issue body + comment thread; reclaims the existing task_issue_map
/reviseshipped (alias of /retry)Same effect as /retry
/update <text>shippedInject a free-text producer change request and re-enter the pipeline. Targeted alternative to /retry's full thread replay.
/qashippedFind the open PR linked to this issue, run the E2E harness, post results back as a comment. Triggers the same pipeline as the post-PR auto-run.
/cancelshipped (#426)Stop in-flight worker processes for this issue (SIGTERM → SIGKILL after 3s for direct mode + tmux kill-session for tmux mode), reject the governance task, and clear the task_issue_map row so the issue can be re-tried later
/skip <phase>partialApply the matching skip-* label and re-enter the pipeline. /skip tests is honoured today (skip-tests label). /skip quality and /skip review are accepted and labelled but the runner does not yet honour them.

config/repositories.json schema

One entry per repo Sling manages. Minimal example with the most common fields:

{
  "id": "workos",
  "github_repo": "svenlabsllc/workos",
  "github_app": "svenlabs-ci-app",
  "branch": "develop",
  "productionBranch": "main",
  "sourceBranch": "main",
  "execution_mode": "claude-code",
  "language": "typescript",
  "test_command": "pnpm test",
  "labels": ["auto-implement", "sling"],
  "max_concurrent_tasks": 1,
  "claude_model": "auto",
  "hipaa_mode": false,
  "governance": { ... },
  "staging":   { ... },
  "uat":       { ... }
}
FieldTypeDescription
idstringUnique identifier for this repo entry
github_repostringFull owner/repo on GitHub
github_appstringsvenlabs-ci-app | gdt-ci-app — overrides the tenant default (sling#308)
branchstringPR merge target. Default develop for features.
productionBranchstringPR target for hotfixes (labels hotfix, critical, showstopper, or bug+priority:high)
sourceBranchstring(#403) Branch to cut from. Lets feature branches be cut from main while still merging to develop, so PR diffs are clean per-issue.
execution_modestringstiv | claude-code | claude-code-tmux | cloud
languagestringnodejs | typescript | php | python | go | rust
test_commandstringShell command to run the test suite
lint_commandstringOptional lint command
labelsstring[]Trigger labels Sling listens for on issues
max_concurrent_tasksnumberPer-repo concurrency cap
claude_modelstringModel override (auto picks per phase)
anthropic_credential_idstringOptional per-repo Claude Max credential routing (see credential-home.js)
hipaa_modebooleanStricter blocked-paths + data-handling rules
governanceobjectPer-repo overrides for risk tiers and blocked paths
reviewobjectAI auto-review thresholds + custom rules
stagingobjectStaging deploy + E2E config
uatobjectUAT Slack channel, GitHub Projects mappings, push-to-prod thresholds
projectStatusobjectGitHub Projects v2 mapping (project ID, status field, status mappings)

Branching model

Three orthogonal fields control the branch lifecycle. The split (#403) lets us merge to develop while cutting from main, so PRs don't carry unrelated divergence as their base.

FieldRoleDefault
branchPR merge target for features/fixesdevelop
productionBranchPR merge target for hotfixesmain
sourceBranchBranch the new feature/fix branch is cut fromsame as branch

Branch naming: {type}/auto-{issue}/{slug} where typefeat | fix | hotfix | chore | refactor | docs.

Environment variables

VariableRequiredPurpose
OPENROUTER_API_KEYpreferredAI routing for STIV mode
ANTHROPIC_API_KEYfallbackUsed only when OpenRouter is absent
GITHUB_TOKENyes (legacy fallback)Global PAT — used for repos without a configured App
GITHUB_APP_IDyes (gdt-ci-app)App ID for the default GitHub App
GITHUB_APP_PRIVATE_KEY_PATHyesPath to gdt-ci-app's .pem
GITHUB_WEBHOOK_SECRETyesHMAC secret for the default App
SVENLABS_GITHUB_APP_IDfor SvenLabs reposApp ID for svenlabs-ci-app (e.g. workos)
SVENLABS_GITHUB_APP_PRIVATE_KEY_PATHfor SvenLabs reposPath to svenlabs-ci-app's .pem
SVENLABS_GITHUB_WEBHOOK_SECRETfor SvenLabs reposHMAC secret for svenlabs-ci-app
AUTODEVMINI_WORKER_COUNTnoWorker pool size (default 3)
WORKER_MODELnoDefault model for STIV workers
OPENROUTER_TRIAGE_MODELnoCheap model for intent classification
AUTODEV_INGEST_SECRETfor /api/autodev/ingestHMAC bearer
INTENTOS_WEBHOOK_SECRETfor /api/intentos/ingestHMAC bearer
CLAUDE_CODE_MODELnoOverride for Claude Code (default: CLI default)
CLAUDE_CODE_MAX_TURNSnoMax turns per Claude Code run (default 80)
CLAUDE_CODE_TIMEOUT_MSnoRun timeout (default 3 600 000)
SCTXT_URL / SCTXT_API_KEYnoSharedContext (sctxt.ai) integration
SLING_TICKET_BUDGET_USDnoPer-ticket cost cap (default $25)
SLING_AI_ISSUE_CREATIONnotrue to allow AI-originated issue creation (default blocked)
PR_REVIEW_DEDUP_HOURSnoSkip re-review when same head_sha was reviewed within N hours (default 24)
PR_REVIEW_QUORUMnoRun AI reviewer N times in parallel; keep findings flagged by ≥ ceil(N/2) (default 1)
SLACK_BOT_TOKENyesAIA bot posts via this token
ONBOARDING_VIDEO_*noSlot-based screencast IDs (B6); empty slots render placeholders

Execution modes

Mode resolution priority: task label → repo config (execution_mode) → task property (executionMode) → default stiv.

ModeTriggerHow it worksBest for
stivdefaultSpec → Test → Implement → Validate, iterativeWell-scoped, TDD-friendly tickets
claude-codeLabel or repo configDirect spawn of Claude Code CLI; flat-rate Max plan; prompt piped via stdinMulti-file changes; recommended over STIV for most repos today
claude-code-tmuxLabel claude-code-tmuxSame as above + tmux session for live tmux attach -t claude-{issue}Debugging complex tasks live
cloudrepo execution_mode: cloudRuns on Anthropic infra via claude --remote; auto-creates PRHigh-parallelism blitzes

STIV pipeline + checkpointing

Phases written to PostgreSQL task_steps. On retry, completed phases are skipped (sling#291 resilience).

  1. workspace — clones repo, checks out sourceBranch, creates feature branch
  2. spec — turns the issue into structured ACs
  3. tests — generates tests for each AC (skipped on skip-tests)
  4. implement — writes code; up to 3 attempts per file
  5. quality — lint + types + existing test suite
  6. review — AI auto-review, score 0-10
  7. push + pr — pushes branch, opens PR with rolling comment

Workspace + branch are reused across retries. Heavy subprocesses run with nice -n 15 ionice -c2 -n7; default cap is 2 concurrent tasks.

Project lifecycle state machine

src/utils/lifecycle-store.js is the source of truth for where a ticket sits in the producer / BO / release loop (workflow PDF steps 11 + 13).

spec_review
  → building
    → ready_for_uat
      → uat_in_review
        → back_in_engineering ⇆ building
        → push_to_production | push_to_production_immediately
          → in_production
            → reverted

Two tables back it: project_lifecycle (current state per task) and project_lifecycle_history (audit trail with actor + reason). Use transitionAsync() for fire-and-forget calls; illegal transitions warn but never throw.

UAT + push to production

The UAT Slack message offers BOs three branches:

ButtonApproval gateCI gateUse when
Request Changesn/a — resets approvalsn/aMarks Back in Engineering
Push to ProductionConfigured requiredApprovals thresholdStandard CI + branch protectionNormal release
Push to Production NowSingle approver onlyCI + branch protection still applyUrgent fixes

The urgent path records urgent = true + triggered_by = <slack user> on the releases row and prefixes the Slack message with :rotating_light: URGENT. It does not bypass branch protection — those are enforced by GitHub at merge time.

E2E testing

The post-PR pipeline runs Playwright E2E and downloads videos / traces / screenshots on every build, including every /retry re-entry. Artifacts are stored at /data/sling-artifacts/{owner}/{repo}/pr-{N}/{timestamp}/ with 30-day retention.

QA video + trace are forced ON via --trace=on --video=on appended to the default Playwright command. Opt out per-repo:

"staging": {
  "e2e": { "qaVideo": false, "qaTrace": false }
}

When the repo provides its own testCmd, Sling does not modify it — pass the flags yourself.

Auto-review noise controls (EPIC #413 / #419)

KnobDefaultEffect
PR_REVIEW_DEDUP_HOURS24Skip re-review when the same head_sha was reviewed within this many hours
PR_REVIEW_QUORUM1Run reviewer N times in parallel; keep findings flagged by ≥ ceil(N/2)
PR label force-rereviewOne-shot bypass of the SHA-dedup gate; auto-removed after a run

The auto-review comment is rolled in place: first run creates a comment, every subsequent run edits it with a <sub>_Last updated …_</sub> footer.

Governance

Risk tiers determine whether a task auto-runs, requires human approval, or is rejected outright. Per-repo overrides live under governance in repositories.json.

TierExamplesDisposition
0Docs, comments, config tweaksAuto-approved
1Non-critical bug fixes, tests, refactorsAuto-approved (PR-only)
2API changes, DB migrationsRequires human /approve
3Auth, payments, HIPAA pathsRejected — implement by hand

EPIC protection (#399)

Issues labelled epic are excluded from auto-split. Sling will not break an EPIC into child issues automatically.

AI issue creation (#397 + #400)

AI-originated issue creation is blocked by default; SLING_AI_ISSUE_CREATION=true opts in. When enabled, dedup-candidate + product-repo-map signals are surfaced on every proposal. See I1 / I5 / I6 under infra#384.

Night Shift cron

Runs every 5 min via node-cron. Fetches eligible issues across all configured repos via getOctokitForRepo (sling#468), routes them through governance, queues them to workers. Stale task_issue_map rows reclaim themselves when their PR is closed-without-merge (sling#291).

API endpoints (operators)

POST /api/autodev/ingest

Receives AutoDev specification bundles from IntentOS. Auth: Authorization: Bearer <HMAC> with AUTODEV_INGEST_SECRET. Target repo resolved from X-Target-Repo header, or AUTODEV_DEFAULT_OWNER/_REPO.

curl -X POST https://sling.svenlabs.ai/api/autodev/ingest \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <hmac>" \
  -H "X-Target-Repo: svenlabsllc/workos" \
  -d '{ "title": "...", "requirements": [...], "constraints": [...], "acceptance": [...] }'

POST /api/intentos/ingest

IntentOS webhook for spec ingestion. Same HMAC pattern, separate secret (INTENTOS_WEBHOOK_SECRET).

POST /api/onboarding/event

Public beacon for B8 telemetry. Always 204. Validates a small whitelist (page, event_type, section, browser family); silently drops anything else. DNT-respecting on the client side.

Runbooks

Operator playbooks live under docs/runbooks/ in the Sling repo:

Source: src/handlers/docs.js. Update this file whenever a public route, env var, or repositories.json field is added.