Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Implement budget limits, usage alerts, and spending controls for Kling AI. Use when managing costs or preventing overruns. Trigger with phrases like 'klingai cost', 'kling ai budget', 'klingai spending limit', 'video generation costs'.
.claude/skills/jeremylongshore-klingai-cost-controls/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 36% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 3% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 7% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 35% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 36% | 0% |
Prevent unexpected spending with per-request cost estimation, daily budget enforcement, threshold alerts, and usage dashboards. Credits are consumed per task based on duration, mode, and audio.
| Config | Credits | |--------|---------| | 5s standard | 10 | | 5s professional | 35 | | 10s standard | 20 | | 10s professional | 70 | | 5s standard + audio (v2.6) | 50 | | 10s professional + audio (v2.6) | 200 | | Image generation (Kolors) | 1 | | Virtual try-on | 5 |
pythonimport time from dataclasses import dataclass, field @dataclass class BudgetGuard: """Enforce daily credit budget with alerting.""" daily_limit: int = 1000 alert_threshold: float = 0.8 # alert at 80% _used: int = 0 _reset_time: float = field(default_factory=time.time) _alerts_sent: set = field(default_factory=set) def _check_reset(self): if time.time() - self._reset_time > 86400: self._used = 0 self._reset_time = time.time() self._alerts_sent.clear() def estimate_credits(self, duration: int = 5, mode: str = "standard", audio: bool = False) -> int: base = {(5, "standard"): 10, (5, "professional"): 35, (10, "standard"): 20, (10, "professional"): 70} credits = base.get((duration, mode), 10) if audio: credits *= 5 return credits def check(self, credits_needed: int) -> bool: self._check_reset() # Check alert threshold usage_pct = (self._used + credits_needed) / self.daily_limit if usage_pct >= self.alert_threshold and "80pct" not in self._alerts_sent: self._alerts_sent.add("80pct") self._on_alert(f"Budget at {usage_pct:.0%} ({self._used + credits_needed}/{self.daily_limit})") if self._used + credits_needed > self.daily_limit: raise RuntimeError( f"Daily budget exceeded: {self._used} + {credits_needed} > {self.daily_limit} credits" ) return True def record(self, credits: int): self._used += credits def _on_alert(self, message: str): """Override for custom alerting (Slack, email, PagerDuty).""" print(f"ALERT: {message}") @property def remaining(self) -> int: self._check_reset() return max(0, self.daily_limit - self._used) @property def usage_report(self) -> dict: self._check_reset() return { "used": self._used, "limit": self.daily_limit, "remaining": self.remaining, "usage_pct": f"{(self._used / self.daily_limit) * 100:.1f}%", }
pythondef pre_batch_check(prompts: list, budget: BudgetGuard, duration: int = 5, mode: str = "standard"): """Estimate and validate batch cost before submission.""" per_video = budget.estimate_credits(duration, mode) total = len(prompts) * per_video print(f"Batch estimate: {len(prompts)} videos x {per_video} credits = {total} credits") print(f"Budget remaining: {budget.remaining}") if total > budget.remaining: raise RuntimeError( f"Batch needs {total} credits but only {budget.remaining} remaining. " f"Reduce to {budget.remaining // per_video} videos or lower mode." ) return total
pythonclass CostAwareKlingClient: """Kling client that enforces budget on every request.""" def __init__(self, base_client, budget: BudgetGuard): self.client = base_client self.budget = budget def text_to_video(self, prompt: str, **kwargs): credits = self.budget.estimate_credits( kwargs.get("duration", 5), kwargs.get("mode", "standard"), kwargs.get("audio", False), ) self.budget.check(credits) result = self.client.text_to_video(prompt, **kwargs) self.budget.record(credits) return result
| Strategy | Savings | Implementation | |----------|---------|---------------| | Standard for drafts | 3.5x cheaper | mode: "standard" for iterations | | 5s clips, extend later | 50% per clip | Generate 5s, use video-extend selectively | | v2.5 Turbo over v2.6 | Faster (less queue cost) | model: "kling-v2-5-turbo" | | Skip audio, add in post | 5x cheaper | motion_has_audio: false | | Batch off-peak | Faster processing | Schedule overnight | | Cache prompts | Avoid duplicates | Hash prompt + params, check before submitting |
pythonimport json from datetime import datetime class UsageTracker: """Log every generation for cost analysis.""" def __init__(self, log_file: str = "kling_usage.jsonl"): self.log_file = log_file def log(self, task_id: str, credits: int, model: str, duration: int, mode: str, prompt: str): entry = { "timestamp": datetime.utcnow().isoformat(), "task_id": task_id, "credits": credits, "model": model, "duration": duration, "mode": mode, "prompt_preview": prompt[:100], } with open(self.log_file, "a") as f: f.write(json.dumps(entry) + "\n")
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-12 | pass→pass | 14,618 | 9,630 | -34% | 1 | 1 | 0% | 2,760 | 3,459 | +25% | 0 | 0 | — |
case-01 | fail→fail | 14,992 | 20,954 | +40% | 1 | 1 | 0% | 2,860 | 4,829 | +69% | 0 | 0 | — |
case-02 | fail→pass | 22,437 | 17,668 | -21% | 1 | 1 | 0% | 3,047 | 4,134 | +36% | 0 | 0 | — |
case-03 | fail→fail | 22,397 | 31,806 | +42% | 1 | 1 | 0% | 4,769 | 6,236 | +31% | 0 | 0 | — |
case-04 | pass→pass | 15,099 | 23,068 | +53% | 1 | 1 | 0% | 3,091 | 5,327 | +72% | 0 | 0 | — |
case-05 | pass→pass | 23,019 | 25,691 | +12% | 1 | 1 | 0% | 3,637 | 4,229 | +16% | 0 | 0 | — |
case-06 | pass→pass | 42,755 | 14,128 | -67% | 1 | 1 | 0% | 2,994 | 4,680 | +56% | 0 | 0 | — |
case-07 | pass→pass | 17,672 | 8,616 | -51% | 1 | 1 | 0% | 2,537 | 3,501 | +38% | 0 | 0 | — |
case-08 | fail→fail | 13,980 | 10,116 | -28% | 1 | 1 | 0% | 2,120 | 3,649 | +72% | 0 | 0 | — |
case-09 | fail→fail | 14,000 | 11,500 | -18% | 1 | 1 | 0% | 2,264 | 3,865 | +71% | 0 | 0 | — |
case-10 | fail→pass | 21,697 | 6,162 | -72% | 1 | 1 | 0% | 2,942 | 3,030 | +3% | 0 | 0 | — |
case-11 | pass→pass | 21,947 | 22,978 | +5% | 1 | 1 | 0% | 2,511 | 4,513 | +80% | 0 | 0 | — |
case-13 | pass→pass | 12,668 | 4,302 | -66% | 1 | 1 | 0% | 1,499 | 2,455 | +64% | 0 | 0 | — |
case-14 | fail→pass | 13,332 | 6,767 | -49% | 1 | 1 | 0% | 2,718 | 2,919 | +7% | 0 | 0 | — |
case-15 | fail→fail | 26,532 | 15,768 | -41% | 1 | 1 | 0% | 4,045 | 4,727 | +17% | 0 | 0 | — |
case-16 | pass→pass | 23,952 | 23,221 | -3% | 1 | 1 | 0% | 3,497 | 5,390 | +54% | 0 | 0 | — |
case-17 | fail→pass | 12,294 | 8,233 | -33% | 1 | 1 | 0% | 2,390 | 3,215 | +35% | 0 | 0 | — |
case-18 | fail→pass | 14,936 | 6,150 | -59% | 1 | 1 | 0% | 1,993 | 2,702 | +36% | 0 | 0 | — |
case-19 | fail→pass | 7,457 | 9,483 | +27% | 1 | 1 | 0% | 1,189 | 2,433 | +105% | 0 | 0 | — |
case-20 | pass→pass | 18,708 | 8,962 | -52% | 1 | 1 | 0% | 2,296 | 3,197 | +39% | 0 | 0 | — |
case-21 | pass→pass | 15,483 | 6,561 | -58% | 1 | 1 | 0% | 2,178 | 2,835 | +30% | 0 | 0 | — |
case-22 | pass→pass | 18,022 | 10,269 | -43% | 1 | 1 | 0% | 3,407 | 3,661 | +7% | 0 | 0 | — |
case-23 | pass→pass | 14,992 | 8,656 | -42% | 1 | 1 | 0% | 1,715 | 2,139 | +25% | 0 | 0 | — |
case-24 | fail→pass | 15,502 | 7,079 | -54% | 1 | 1 | 0% | 1,522 | 1,977 | +30% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +29 percentage points is the difference between those two pass rates over the 24 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.