Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Implement audit logging for Kling AI operations for compliance and security. Use when tracking API usage or preparing for audits. Trigger with phrases like 'klingai audit', 'kling ai audit log', 'klingai compliance log', 'video generation audit trail'.
.claude/skills/jeremylongshore-klingai-audit-logging/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 32% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 80% | 0% |
| case-14 | ✗→✓ | ▲ Improved | -18% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 61% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 98% | 0% |
Compliance-grade audit logging for Kling AI API operations. Every task submission, status change, and credential usage is captured in tamper-evident structured logs.
pythonimport json import hashlib import time from datetime import datetime from pathlib import Path class AuditLogger: """Append-only audit log with integrity checksums.""" def __init__(self, log_dir: str = "audit"): self.log_dir = Path(log_dir) self.log_dir.mkdir(exist_ok=True) self._prev_hash = "genesis" def _compute_hash(self, entry: dict) -> str: raw = json.dumps(entry, sort_keys=True) + self._prev_hash return hashlib.sha256(raw.encode()).hexdigest()[:16] def log(self, event_type: str, actor: str, details: dict): """Write a tamper-evident audit entry.""" entry = { "timestamp": datetime.utcnow().isoformat() + "Z", "event_type": event_type, "actor": actor, "details": details, "prev_hash": self._prev_hash, } entry["hash"] = self._compute_hash(entry) self._prev_hash = entry["hash"] date = datetime.utcnow().strftime("%Y-%m-%d") filepath = self.log_dir / f"audit-{date}.jsonl" with open(filepath, "a") as f: f.write(json.dumps(entry) + "\n") return entry["hash"]
pythonclass KlingAuditClient: """Kling client with full audit trail.""" def __init__(self, base_client, audit: AuditLogger, actor: str = "system"): self.client = base_client self.audit = audit self.actor = actor def text_to_video(self, prompt: str, **kwargs): # Log submission self.audit.log("task_submitted", self.actor, { "action": "text_to_video", "model": kwargs.get("model", "kling-v2-master"), "duration": kwargs.get("duration", 5), "mode": kwargs.get("mode", "standard"), "prompt_hash": hashlib.sha256(prompt.encode()).hexdigest()[:16], "prompt_length": len(prompt), }) result = self.client.text_to_video(prompt, **kwargs) # Log completion self.audit.log("task_completed", self.actor, { "action": "text_to_video", "status": "succeed", "video_count": len(result.get("videos", [])), }) return result def log_auth_event(self, event: str, success: bool): self.audit.log("auth_event", self.actor, { "event": event, "success": success, "access_key_prefix": self.client.config.access_key[:8] + "...", })
pythondef verify_audit_chain(log_file: str) -> bool: """Verify tamper-evidence of audit log chain.""" prev_hash = "genesis" entries = [] with open(log_file) as f: for line_num, line in enumerate(f, 1): entry = json.loads(line) entries.append(entry) if entry["prev_hash"] != prev_hash: print(f"Chain broken at line {line_num}: " f"expected prev_hash={prev_hash}, got {entry['prev_hash']}") return False # Recompute hash check_entry = {k: v for k, v in entry.items() if k != "hash"} raw = json.dumps(check_entry, sort_keys=True) + prev_hash expected_hash = hashlib.sha256(raw.encode()).hexdigest()[:16] if entry["hash"] != expected_hash: print(f"Hash mismatch at line {line_num}") return False prev_hash = entry["hash"] print(f"Verified {len(entries)} entries -- chain intact") return True
pythondef generate_audit_report(log_dir: str = "audit", days: int = 30) -> dict: """Generate compliance audit report.""" from collections import Counter from datetime import timedelta log_path = Path(log_dir) events = [] cutoff = datetime.utcnow() - timedelta(days=days) for filepath in sorted(log_path.glob("audit-*.jsonl")): with open(filepath) as f: for line in f: entry = json.loads(line) if entry["timestamp"] >= cutoff.isoformat(): events.append(entry) event_types = Counter(e["event_type"] for e in events) actors = Counter(e["actor"] for e in events) report = { "period_days": days, "total_events": len(events), "event_types": dict(event_types), "unique_actors": len(actors), "actors": dict(actors), "first_event": events[0]["timestamp"] if events else None, "last_event": events[-1]["timestamp"] if events else None, } print(f"\n=== Audit Report ({days} days) ===") print(f"Total events: {report['total_events']}") for event_type, count in event_types.most_common(): print(f" {event_type}: {count}") print(f"Actors: {', '.join(actors.keys())}") return report
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-04 | fail→pass | 26,631 | 21,610 | -19% | 1 | 1 | 0% | 4,673 | 6,158 | +32% | 0 | 0 | — |
case-01 | fail→fail | 39,751 | 29,790 | -25% | 1 | 1 | 0% | 7,468 | 6,658 | -11% | 0 | 0 | — |
case-02 | fail→fail | 24,955 | 19,067 | -24% | 1 | 1 | 0% | 3,751 | 4,790 | +28% | 0 | 0 | — |
case-03 | fail→fail | 27,405 | 21,553 | -21% | 1 | 1 | 0% | 3,849 | 4,997 | +30% | 0 | 0 | — |
case-05 | fail→pass | 21,934 | 31,383 | +43% | 1 | 1 | 0% | 3,315 | 5,960 | +80% | 0 | 0 | — |
case-06 | fail→fail | 19,230 | 22,368 | +16% | 1 | 1 | 0% | 2,761 | 4,979 | +80% | 0 | 0 | — |
case-07 | fail→fail | 13,865 | 10,076 | -27% | 1 | 1 | 0% | 2,790 | 3,578 | +28% | 0 | 0 | — |
case-08 | fail→fail | 16,935 | 23,486 | +39% | 1 | 1 | 0% | 3,297 | 5,302 | +61% | 0 | 0 | — |
case-09 | fail→fail | 19,845 | 23,024 | +16% | 1 | 1 | 0% | 3,033 | 5,441 | +79% | 0 | 0 | — |
case-10 | pass→pass | 20,252 | 11,109 | -45% | 1 | 1 | 0% | 2,900 | 3,700 | +28% | 0 | 0 | — |
case-11 | pass→pass | 21,590 | 20,256 | -6% | 1 | 1 | 0% | 3,011 | 4,586 | +52% | 0 | 0 | — |
case-12 | fail→fail | 17,038 | 18,265 | +7% | 1 | 1 | 0% | 2,848 | 5,138 | +80% | 0 | 0 | — |
case-13 | fail→fail | 25,192 | 19,474 | -23% | 1 | 1 | 0% | 4,105 | 5,790 | +41% | 0 | 0 | — |
case-14 | fail→pass | 16,459 | 4,895 | -70% | 1 | 1 | 0% | 2,800 | 2,307 | -18% | 0 | 0 | — |
case-15 | fail→pass | 7,502 | 4,550 | -39% | 1 | 1 | 0% | 1,405 | 2,261 | +61% | 0 | 0 | — |
case-16 | fail→pass | 12,622 | 21,439 | +70% | 1 | 1 | 0% | 2,659 | 5,278 | +98% | 0 | 0 | — |
case-17 | fail→pass | 18,487 | 5,798 | -69% | 1 | 1 | 0% | 2,512 | 2,496 | -1% | 0 | 0 | — |
case-18 | fail→pass | 10,962 | 2,382 | -78% | 1 | 1 | 0% | 1,867 | 2,051 | +10% | 0 | 0 | — |
case-19 | fail→pass | 14,730 | 18,483 | +25% | 1 | 1 | 0% | 3,017 | 4,370 | +45% | 0 | 0 | — |
case-20 | pass→pass | 15,135 | 9,822 | -35% | 1 | 1 | 0% | 2,166 | 3,027 | +40% | 0 | 0 | — |
case-21 | pass→pass | 24,141 | 15,600 | -35% | 1 | 1 | 0% | 3,131 | 4,248 | +36% | 0 | 0 | — |
case-22 | fail→pass | 19,685 | 14,449 | -27% | 1 | 1 | 0% | 2,463 | 2,957 | +20% | 0 | 0 | — |
case-23 | pass→pass | 17,936 | 13,094 | -27% | 1 | 1 | 0% | 2,502 | 4,274 | +71% | 0 | 0 | — |
case-24 | fail→fail | 21,608 | 20,058 | -7% | 1 | 1 | 0% | 3,032 | 4,460 | +47% | 0 | 0 | — |
case-25 | pass→pass | 15,382 | 10,619 | -31% | 1 | 1 | 0% | 2,156 | 3,835 | +78% | 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. 25 cases were attempted. The headline lift of +36 percentage points is the difference between those two pass rates over the 25 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.