arkaos 4.30.0 → 4.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/THE-ARKAOS-GUIDE.md +1 -1
- package/VERSION +1 -1
- package/arka/SKILL.md +1 -1
- package/config/claude-agents/brand-director.md +1 -1
- package/config/claude-agents/content-strategist.md +1 -1
- package/config/claude-agents/frontend-dev.md +1 -1
- package/config/claude-agents/marketing-director.md +1 -1
- package/config/claude-agents/scriptwriter.md +1 -1
- package/config/claude-agents/trends-analyst.md +1 -1
- package/config/claude-agents/video-producer.md +1 -1
- package/config/skills-curated.yaml +2 -1
- package/config/skills-provenance.yaml +6 -0
- package/core/governance/evidence_checks.py +185 -1
- package/core/keys.py +17 -5
- package/departments/brand/agents/brand-director.yaml +1 -0
- package/departments/brand/skills/design-review/SKILL.md +6 -0
- package/departments/brand/skills/ux-audit/SKILL.md +4 -1
- package/departments/content/agents/content-strategist.yaml +1 -0
- package/departments/content/agents/production/trends-analyst.yaml +1 -0
- package/departments/content/agents/production/video-producer.yaml +1 -0
- package/departments/content/agents/scriptwriter.yaml +1 -0
- package/departments/dev/agents/frontend-dev.yaml +1 -0
- package/departments/dev/skills/animated-website/SKILL.md +14 -1
- package/departments/dev/skills/watch/SKILL.md +162 -0
- package/departments/dev/skills/watch/references/claude-video.LICENSE +21 -0
- package/departments/dev/skills/watch/scripts/config.py +145 -0
- package/departments/dev/skills/watch/scripts/download.py +179 -0
- package/departments/dev/skills/watch/scripts/frames.py +762 -0
- package/departments/dev/skills/watch/scripts/setup.py +373 -0
- package/departments/dev/skills/watch/scripts/transcribe.py +95 -0
- package/departments/dev/skills/watch/scripts/watch.py +531 -0
- package/departments/dev/skills/watch/scripts/whisper.py +466 -0
- package/departments/marketing/agents/marketing-director.yaml +1 -0
- package/departments/marketing/skills/ad-creative/SKILL.md +5 -0
- package/harness/codex/AGENTS.md +1 -1
- package/harness/copilot/copilot-instructions.md +1 -1
- package/harness/cursor/rules/arkaos.mdc +2 -2
- package/harness/gemini/GEMINI.md +1 -1
- package/harness/opencode/AGENTS.md +1 -1
- package/harness/zed/.rules +1 -1
- package/installer/doctor.js +38 -4
- package/installer/frontend-tooling.js +36 -0
- package/knowledge/agents-registry-v2.json +8 -1
- package/knowledge/skills-manifest.json +14 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/README.md
CHANGED
package/THE-ARKAOS-GUIDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The ArkaOS Guide
|
|
2
2
|
|
|
3
|
-
> v4.
|
|
3
|
+
> v4.32.0 — 89 agents, 17 departments, 330 skills, 297 commands, 16 ADRs.
|
|
4
4
|
> One file, everything you need to start. Generated by `scripts/guide_gen.py` — never hand-edited.
|
|
5
5
|
|
|
6
6
|
## What it is
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.
|
|
1
|
+
4.32.0
|
package/arka/SKILL.md
CHANGED
|
@@ -47,7 +47,7 @@ complementary, not alternatives.
|
|
|
47
47
|
# ArkaOS — Main Orchestrator
|
|
48
48
|
|
|
49
49
|
> **The Operating System for AI Agent Teams**
|
|
50
|
-
> 89 agents. 17 departments.
|
|
50
|
+
> 89 agents. 17 departments. 330 skills. Multi-runtime. Dashboard. Knowledge RAG.
|
|
51
51
|
|
|
52
52
|
## ⛔ Evidence flow — 4 gates (NON-NEGOTIABLE)
|
|
53
53
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: brand-director
|
|
3
3
|
description: >
|
|
4
|
-
Valentina — Creative Director (brand squad). Executes: brand identity creation, visual design direction, UX/UI strategy
|
|
4
|
+
Valentina — Creative Director (brand squad). Executes: brand identity creation, reference-video visual analysis via dev/watch (complete frames + transcript — motion and art direction judged on evidence, never on screenshots), visual design direction, UX/UI strategy.
|
|
5
5
|
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: content-strategist
|
|
3
3
|
description: >
|
|
4
|
-
Rafael — Content Strategist (content squad). Executes: viral content design, hook writing & packaging, script structure
|
|
4
|
+
Rafael — Content Strategist (content squad). Executes: viral content design, reference-video analysis via dev/watch (frames + timestamped transcript before judging any video), hook writing & packaging, script structure.
|
|
5
5
|
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: frontend-dev
|
|
3
3
|
description: >
|
|
4
|
-
Diana — Senior Frontend Developer (dev squad). Executes: Vue 3 (Composition API), Nuxt 3, React 19 / Next.js 15
|
|
4
|
+
Diana — Senior Frontend Developer (dev squad). Executes: Vue 3 (Composition API), motion-reference analysis via dev/watch (scroll/animation benchmarks from frames + transcript before implementing), Nuxt 3, React 19 / Next.js 15.
|
|
5
5
|
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: marketing-director
|
|
3
3
|
description: >
|
|
4
|
-
Luna — Marketing Director (marketing squad). Executes: growth strategy, content marketing, SEO
|
|
4
|
+
Luna — Marketing Director (marketing squad). Executes: growth strategy, video-ad teardown via dev/watch (hook, pacing and spoken-copy evidence from frames + transcript), content marketing, SEO.
|
|
5
5
|
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: scriptwriter
|
|
3
3
|
description: >
|
|
4
|
-
Joana — Scriptwriter (content squad). Executes: video scriptwriting (YouTube, Reels, TikTok), cinematic narrative for short and long-form, storyboard-ready scene writing (scene/shot/VO/on-screen-text columns)
|
|
4
|
+
Joana — Scriptwriter (content squad). Executes: video scriptwriting (YouTube, Reels, TikTok), reference-video teardown via dev/watch (hook, pacing and beat analysis from frames + transcript), cinematic narrative for short and long-form, storyboard-ready scene writing (scene/shot/VO/on-screen-text columns).
|
|
5
5
|
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: trends-analyst
|
|
3
3
|
description: >
|
|
4
|
-
Margarida — Trends & Niche Analyst (content squad). Executes: trend detection across platforms (Agent-Reach: X, Reddit, YouTube, RSS, Exa), niche viability scoring (audience size, competition density, monetization path, brand fit), platform algorithm shift monitoring
|
|
4
|
+
Margarida — Trends & Niche Analyst (content squad). Executes: trend detection across platforms (Agent-Reach: X, Reddit, YouTube, RSS, Exa), viral-video deconstruction via dev/watch (scene-aware frames + transcript, timestamp-cited), niche viability scoring (audience size, competition density, monetization path, brand fit), platform algorithm shift monitoring.
|
|
5
5
|
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: video-producer
|
|
3
3
|
description: >
|
|
4
|
-
Simão — Video Producer & Production Lead (content squad). Executes: video production pipelines (script → storyboard → assets → edit → render), Hyperframes video-as-code editing (HTML/CSS/JS + GSAP → MP4), Higgsfield generation orchestration (image, video, audio, motion control, upscale, reframe)
|
|
4
|
+
Simão — Video Producer & Production Lead (content squad). Executes: video production pipelines (script → storyboard → assets → edit → render), cut review via dev/watch (frame + transcript evidence on own renders before the Quality Gate), Hyperframes video-as-code editing (HTML/CSS/JS + GSAP → MP4), Higgsfield generation orchestration (image, video, audio, motion control, upscale, reframe).
|
|
5
5
|
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -24,7 +24,8 @@ curated_subskills:
|
|
|
24
24
|
community: [moderation]
|
|
25
25
|
content: [calendar, hook-write]
|
|
26
26
|
dev: [api-design, architecture-design, clean-code-review, code-review,
|
|
27
|
-
db-design, refactor-plan, runbook, security-audit, spec, tdd-cycle
|
|
27
|
+
db-design, refactor-plan, runbook, security-audit, spec, tdd-cycle,
|
|
28
|
+
watch]
|
|
28
29
|
ecom: [cart-recovery, store-audit]
|
|
29
30
|
finance: [financial-model, unit-economics]
|
|
30
31
|
kb: [search-kb, zettelkasten-process]
|
|
@@ -91,6 +91,12 @@ derived:
|
|
|
91
91
|
origin: community
|
|
92
92
|
source: https://github.com/nutlope/hallmark
|
|
93
93
|
license: MIT
|
|
94
|
+
# Watch absorption campaign — video-input primitive derived from
|
|
95
|
+
# bradautomates/claude-video v0.2.0 (MIT), maintained natively.
|
|
96
|
+
departments/dev/skills/watch:
|
|
97
|
+
origin: community
|
|
98
|
+
source: https://github.com/bradautomates/claude-video
|
|
99
|
+
license: MIT
|
|
94
100
|
# Marketing skills integration campaign — derived from
|
|
95
101
|
# coreyhaines31/marketingskills (MIT). Frontmatter metadata must match
|
|
96
102
|
# each entry field-for-field (test_registry_matches_frontmatter_field_for_field).
|
|
@@ -42,7 +42,7 @@ TIMEOUT_SECONDS = 300
|
|
|
42
42
|
COVERAGE_THRESHOLD = 80.0
|
|
43
43
|
ALL_CHECKS: tuple[str, ...] = (
|
|
44
44
|
"lint", "typecheck", "tests", "coverage", "security-grep", "spellcheck",
|
|
45
|
-
"ui-screenshot",
|
|
45
|
+
"ui-screenshot", "design-slop",
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
# ui-screenshot artifact contract (Excellence Reform PR-D3): captures land
|
|
@@ -52,6 +52,26 @@ UI_EVIDENCE_DIR = Path(".arka") / "evidence" / "ui"
|
|
|
52
52
|
UI_SCREENSHOT_WINDOW_HOURS = 24
|
|
53
53
|
UI_SCREENSHOT_MIN_BYTES = 10 * 1024
|
|
54
54
|
|
|
55
|
+
# design-slop: the deterministic static half of the visual-review loop.
|
|
56
|
+
# Shells the external `impeccable` npm CLI (46 anti-pattern rules, no
|
|
57
|
+
# LLM) over the CHANGED UI files only — never a whole-tree scan. The
|
|
58
|
+
# gate never installs anything (supply-chain: `npx --no-install`).
|
|
59
|
+
# Modes via ``governance.designSlop`` in ``~/.arkaos/config.json``:
|
|
60
|
+
# off → skip · warn (default) → advisory summary, never fails ·
|
|
61
|
+
# hard → `warning` findings fail; `advisory` findings never fail.
|
|
62
|
+
DESIGN_SLOP_TIMEOUT = 120
|
|
63
|
+
_DESIGN_SLOP_MIN_NODE = (22, 12)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _design_slop_config_path() -> Path:
|
|
67
|
+
"""Resolved at call time so tests can redirect HOME (never baked)."""
|
|
68
|
+
return Path.home() / ".arkaos" / "config.json"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _design_slop_telemetry_path() -> Path:
|
|
72
|
+
"""Resolved at call time so tests can redirect HOME (never baked)."""
|
|
73
|
+
return Path.home() / ".arkaos" / "telemetry" / "design-slop.jsonl"
|
|
74
|
+
|
|
55
75
|
_MAX_SUMMARY_CHARS = 800
|
|
56
76
|
_MAX_GREP_HITS = 20
|
|
57
77
|
|
|
@@ -661,6 +681,169 @@ def _check_ui_screenshot(
|
|
|
661
681
|
)
|
|
662
682
|
|
|
663
683
|
|
|
684
|
+
def _design_slop_mode() -> str:
|
|
685
|
+
"""Resolve ``governance.designSlop`` to 'off' | 'warn' | 'hard'."""
|
|
686
|
+
config = _design_slop_config_path()
|
|
687
|
+
if not config.exists():
|
|
688
|
+
return "warn"
|
|
689
|
+
try:
|
|
690
|
+
data = json.loads(config.read_text(encoding="utf-8"))
|
|
691
|
+
except (json.JSONDecodeError, OSError):
|
|
692
|
+
return "warn"
|
|
693
|
+
raw = data.get("governance", {}).get("designSlop", "warn")
|
|
694
|
+
if raw in (False, "off", "false"):
|
|
695
|
+
return "off"
|
|
696
|
+
if raw in (True, "hard", "true"):
|
|
697
|
+
return "hard"
|
|
698
|
+
return "warn"
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
def _resolve_detector(project_dir: Path) -> list[str] | None:
|
|
702
|
+
"""Locate the impeccable CLI without ever installing it."""
|
|
703
|
+
direct = shutil.which("impeccable")
|
|
704
|
+
if direct:
|
|
705
|
+
return [direct]
|
|
706
|
+
local = project_dir / "node_modules" / ".bin" / "impeccable"
|
|
707
|
+
if local.is_file():
|
|
708
|
+
return [str(local)]
|
|
709
|
+
if shutil.which("npx"):
|
|
710
|
+
return ["npx", "--no-install", "impeccable"]
|
|
711
|
+
return None
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def _node_supports_detector() -> bool:
|
|
715
|
+
"""True when `node --version` meets the detector's floor (22.12)."""
|
|
716
|
+
node = shutil.which("node")
|
|
717
|
+
if not node:
|
|
718
|
+
return False
|
|
719
|
+
try:
|
|
720
|
+
proc = subprocess.run(
|
|
721
|
+
[node, "--version"], capture_output=True, text=True, timeout=10,
|
|
722
|
+
)
|
|
723
|
+
major, minor = proc.stdout.strip().lstrip("v").split(".")[:2]
|
|
724
|
+
return (int(major), int(minor)) >= _DESIGN_SLOP_MIN_NODE
|
|
725
|
+
except (OSError, ValueError, subprocess.TimeoutExpired):
|
|
726
|
+
return False
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
def _record_design_slop(payload: dict) -> None:
|
|
730
|
+
"""Best-effort telemetry append; never raises into the gate."""
|
|
731
|
+
try:
|
|
732
|
+
target = _design_slop_telemetry_path()
|
|
733
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
734
|
+
with target.open("a", encoding="utf-8") as fh:
|
|
735
|
+
fh.write(json.dumps({"ts": time.time(), **payload}) + "\n")
|
|
736
|
+
except OSError:
|
|
737
|
+
pass
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
def _design_slop_verdict(
|
|
741
|
+
findings: list[dict], mode: str, n_files: int, command_str: str,
|
|
742
|
+
) -> CheckResult:
|
|
743
|
+
"""Turn parsed detector findings into the check verdict."""
|
|
744
|
+
warnings = [f for f in findings if f.get("severity") != "advisory"]
|
|
745
|
+
advisories = [f for f in findings if f.get("severity") == "advisory"]
|
|
746
|
+
top = "; ".join(
|
|
747
|
+
f"{f.get('file', '?')}:{f.get('line', '?')} {f.get('antipattern', '?')}"
|
|
748
|
+
for f in (warnings + advisories)[:10]
|
|
749
|
+
)
|
|
750
|
+
counts = (
|
|
751
|
+
f"{len(warnings)} warning(s), {len(advisories)} advisory finding(s)"
|
|
752
|
+
)
|
|
753
|
+
if warnings and mode == "hard":
|
|
754
|
+
summary = f"{counts} across {n_files} changed UI file(s): {top}"
|
|
755
|
+
passed = False
|
|
756
|
+
elif findings:
|
|
757
|
+
# Only warning-severity findings ever fail (and only in hard
|
|
758
|
+
# mode) — never promise a hard failure for advisory-only runs.
|
|
759
|
+
escalation = (
|
|
760
|
+
" — fails when governance.designSlop=hard" if warnings else ""
|
|
761
|
+
)
|
|
762
|
+
summary = (
|
|
763
|
+
f"ADVISORY: {counts} across {n_files} changed UI "
|
|
764
|
+
f"file(s){escalation}: {top}"
|
|
765
|
+
)
|
|
766
|
+
passed = True
|
|
767
|
+
else:
|
|
768
|
+
summary = f"0 findings across {n_files} changed UI file(s)"
|
|
769
|
+
passed = True
|
|
770
|
+
return CheckResult(
|
|
771
|
+
check="design-slop", ran=True, passed=passed,
|
|
772
|
+
command=command_str, exit_code=2 if findings else 0,
|
|
773
|
+
summary=summary[:_MAX_SUMMARY_CHARS],
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
def _check_design_slop(
|
|
778
|
+
project_dir: Path, changed: list[str] | None,
|
|
779
|
+
test_command: str | None, timeout: int,
|
|
780
|
+
) -> CheckResult:
|
|
781
|
+
"""Deterministic AI-design-slop detection over changed UI files.
|
|
782
|
+
|
|
783
|
+
Composition: ``frontend_gate`` is the pre-edit nudge (PreToolUse),
|
|
784
|
+
this check is the static deterministic half, ``ui-screenshot`` is
|
|
785
|
+
the pixel-artifact half, and Francisca supplies judgment. Fail-open
|
|
786
|
+
by design: a missing detector, an old node, a timeout or unreadable
|
|
787
|
+
output SKIP with a note — the gate never blocks on tooling absence
|
|
788
|
+
and never installs anything.
|
|
789
|
+
"""
|
|
790
|
+
mode = _design_slop_mode()
|
|
791
|
+
if mode == "off":
|
|
792
|
+
return _skip("design-slop", "disabled by governance.designSlop flag")
|
|
793
|
+
if not changed:
|
|
794
|
+
return _skip("design-slop", "no changed files provided")
|
|
795
|
+
try:
|
|
796
|
+
from core.workflow.frontend_gate import is_ui_file
|
|
797
|
+
except Exception:
|
|
798
|
+
return _skip("design-slop", "frontend_gate unavailable")
|
|
799
|
+
ui_changed = [
|
|
800
|
+
f for f in changed
|
|
801
|
+
if is_ui_file(f) and (project_dir / f).is_file()
|
|
802
|
+
]
|
|
803
|
+
if not ui_changed:
|
|
804
|
+
return _skip("design-slop", "no UI files changed")
|
|
805
|
+
detector = _resolve_detector(project_dir)
|
|
806
|
+
if detector is None:
|
|
807
|
+
return _skip(
|
|
808
|
+
"design-slop",
|
|
809
|
+
"impeccable CLI not installed (npm i -D impeccable, or re-run "
|
|
810
|
+
"the ArkaOS installer) — skipped",
|
|
811
|
+
)
|
|
812
|
+
if not _node_supports_detector():
|
|
813
|
+
return _skip("design-slop", "node >= 22.12 required by the detector")
|
|
814
|
+
argv = [*detector, "detect", *ui_changed, "--json"]
|
|
815
|
+
command_str = shlex.join(argv)
|
|
816
|
+
try:
|
|
817
|
+
proc = subprocess.run(
|
|
818
|
+
argv, cwd=project_dir, capture_output=True, text=True,
|
|
819
|
+
timeout=min(timeout, DESIGN_SLOP_TIMEOUT),
|
|
820
|
+
)
|
|
821
|
+
except subprocess.TimeoutExpired:
|
|
822
|
+
return CheckResult(
|
|
823
|
+
check="design-slop", ran=True, passed=None,
|
|
824
|
+
command=command_str, exit_code=None, summary="timeout",
|
|
825
|
+
)
|
|
826
|
+
except (OSError, FileNotFoundError):
|
|
827
|
+
return _skip("design-slop", "detector could not be executed")
|
|
828
|
+
if proc.returncode not in (0, 2):
|
|
829
|
+
tail = (proc.stderr or proc.stdout or "").strip()[-200:]
|
|
830
|
+
return _skip("design-slop", f"detector error (exit {proc.returncode}): {tail}")
|
|
831
|
+
try:
|
|
832
|
+
findings = json.loads(proc.stdout or "[]")
|
|
833
|
+
assert isinstance(findings, list)
|
|
834
|
+
except (json.JSONDecodeError, AssertionError):
|
|
835
|
+
return _skip("design-slop", "unparseable detector output — skipped")
|
|
836
|
+
result = _design_slop_verdict(findings, mode, len(ui_changed), command_str)
|
|
837
|
+
_record_design_slop({
|
|
838
|
+
"project_dir": str(project_dir), "mode": mode,
|
|
839
|
+
"ui_files": len(ui_changed),
|
|
840
|
+
"warnings": sum(1 for f in findings if f.get("severity") != "advisory"),
|
|
841
|
+
"advisories": sum(1 for f in findings if f.get("severity") == "advisory"),
|
|
842
|
+
"outcome": "fail" if result.passed is False else "pass",
|
|
843
|
+
})
|
|
844
|
+
return result
|
|
845
|
+
|
|
846
|
+
|
|
664
847
|
_CHECK_DISPATCH = {
|
|
665
848
|
"lint": _check_lint,
|
|
666
849
|
"typecheck": _check_typecheck,
|
|
@@ -669,6 +852,7 @@ _CHECK_DISPATCH = {
|
|
|
669
852
|
"security-grep": _check_security_grep,
|
|
670
853
|
"spellcheck": _check_spellcheck,
|
|
671
854
|
"ui-screenshot": _check_ui_screenshot,
|
|
855
|
+
"design-slop": _check_design_slop,
|
|
672
856
|
}
|
|
673
857
|
|
|
674
858
|
|
package/core/keys.py
CHANGED
|
@@ -7,15 +7,27 @@ import json
|
|
|
7
7
|
import os
|
|
8
8
|
import stat
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from typing import Optional
|
|
11
10
|
|
|
12
11
|
KEYS_PATH = Path.home() / ".arkaos" / "keys.json"
|
|
13
12
|
|
|
14
13
|
# Known providers with descriptions
|
|
15
14
|
PROVIDERS = {
|
|
16
|
-
"OPENAI_API_KEY": {
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
"OPENAI_API_KEY": {
|
|
16
|
+
"name": "OpenAI",
|
|
17
|
+
"used_for": "Whisper transcription (/watch fallback), embeddings, GPT",
|
|
18
|
+
},
|
|
19
|
+
"GOOGLE_API_KEY": {
|
|
20
|
+
"name": "Google",
|
|
21
|
+
"used_for": "Gemini API, Nano Banana, Google Cloud AI",
|
|
22
|
+
},
|
|
23
|
+
"FAL_API_KEY": {
|
|
24
|
+
"name": "fal.ai",
|
|
25
|
+
"used_for": "Image generation, video generation",
|
|
26
|
+
},
|
|
27
|
+
"GROQ_API_KEY": {
|
|
28
|
+
"name": "Groq",
|
|
29
|
+
"used_for": "Whisper transcription for /watch (whisper-large-v3 — cheaper, faster)",
|
|
30
|
+
},
|
|
19
31
|
}
|
|
20
32
|
|
|
21
33
|
|
|
@@ -31,7 +43,7 @@ def _save(keys: dict[str, str]) -> None:
|
|
|
31
43
|
os.chmod(KEYS_PATH, stat.S_IRUSR | stat.S_IWUSR) # 600
|
|
32
44
|
|
|
33
45
|
|
|
34
|
-
def get_key(name: str) ->
|
|
46
|
+
def get_key(name: str) -> str | None:
|
|
35
47
|
"""Get an API key by name. Also checks environment variables."""
|
|
36
48
|
env_val = os.environ.get(name)
|
|
37
49
|
if env_val:
|
|
@@ -52,6 +52,7 @@ authority:
|
|
|
52
52
|
expertise:
|
|
53
53
|
domains:
|
|
54
54
|
- brand identity creation
|
|
55
|
+
- reference-video visual analysis via dev/watch (complete frames + transcript — motion and art direction judged on evidence, never on screenshots)
|
|
55
56
|
- visual design direction
|
|
56
57
|
- UX/UI strategy
|
|
57
58
|
- design systems
|
|
@@ -112,6 +112,12 @@ For every captured surface, annotate deviations with exact values
|
|
|
112
112
|
- **Benchmark contrast** — for each major finding, one line on what the
|
|
113
113
|
named benchmark does instead.
|
|
114
114
|
|
|
115
|
+
> The deterministic half of this review also runs mechanically as the
|
|
116
|
+
> QG evidence check `design-slop` (`core.governance.evidence_checks` —
|
|
117
|
+
> the external `impeccable` detector over changed UI files, fail-open);
|
|
118
|
+
> cite its finding `antipattern` ids in verdicts when the report
|
|
119
|
+
> carries them.
|
|
120
|
+
|
|
115
121
|
## Slop gates (pre-verdict — MANDATORY)
|
|
116
122
|
|
|
117
123
|
Before issuing any verdict, run the reviewed surfaces through
|
|
@@ -103,7 +103,10 @@ benchmark contrast, concrete fix.
|
|
|
103
103
|
— no memory-based auditing.
|
|
104
104
|
4. **Slop pass** — run the 58 gates (`slop-test.md`) and name every hit
|
|
105
105
|
from `anti-patterns.md`; check reflex-reject violations against the
|
|
106
|
-
squad reference §11 and design-law breaches against §12.
|
|
106
|
+
squad reference §11 and design-law breaches against §12. The
|
|
107
|
+
deterministic half runs mechanically as the QG check `design-slop`
|
|
108
|
+
(external `impeccable` detector, fail-open) — cite its `antipattern`
|
|
109
|
+
ids when its report is on record.
|
|
107
110
|
5. **Accessibility pass** — keyboard-only run, focus visibility,
|
|
108
111
|
contrast (AA), `prefers-reduced-motion`, semantic landmarks.
|
|
109
112
|
6. **Responsive pass** — 390 / 768 / 1440; layout integrity, target
|
|
@@ -45,6 +45,7 @@ authority:
|
|
|
45
45
|
expertise:
|
|
46
46
|
domains:
|
|
47
47
|
- "trend detection across platforms (Agent-Reach: X, Reddit, YouTube, RSS, Exa)"
|
|
48
|
+
- viral-video deconstruction via dev/watch (scene-aware frames + transcript, timestamp-cited)
|
|
48
49
|
- niche viability scoring (audience size, competition density, monetization path, brand fit)
|
|
49
50
|
- platform algorithm shift monitoring
|
|
50
51
|
- whitespace analysis for new channels and formats
|
|
@@ -51,6 +51,7 @@ authority:
|
|
|
51
51
|
expertise:
|
|
52
52
|
domains:
|
|
53
53
|
- video production pipelines (script → storyboard → assets → edit → render)
|
|
54
|
+
- cut review via dev/watch (frame + transcript evidence on own renders before the Quality Gate)
|
|
54
55
|
- Hyperframes video-as-code editing (HTML/CSS/JS + GSAP → MP4)
|
|
55
56
|
- Higgsfield generation orchestration (image, video, audio, motion control, upscale, reframe)
|
|
56
57
|
- shot lists and EDLs (scene/shot/VO/on-screen-text columns)
|
|
@@ -43,6 +43,7 @@ authority:
|
|
|
43
43
|
expertise:
|
|
44
44
|
domains:
|
|
45
45
|
- video scriptwriting (YouTube, Reels, TikTok)
|
|
46
|
+
- reference-video teardown via dev/watch (hook, pacing and beat analysis from frames + transcript)
|
|
46
47
|
- cinematic narrative for short and long-form
|
|
47
48
|
- storyboard-ready scene writing (scene/shot/VO/on-screen-text columns)
|
|
48
49
|
- narrative structure (hook-bridge-body-CTA; beat sheets; story circles)
|
|
@@ -76,7 +76,20 @@ If the user gives just a video path and a vague concept, ask ONE clarifying ques
|
|
|
76
76
|
|
|
77
77
|
### Step 1: Analyze the Video
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
**See the content first (dev/watch primitive).** Before any design decision,
|
|
80
|
+
watch the source with the native `dev/watch` skill so overlay copy, section
|
|
81
|
+
pacing and dwell points are grounded in what is actually on screen — the
|
|
82
|
+
"complete frames" doctrine, never screenshots or guesses:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
PY="$HOME/.arkaos/bin/arka-py"; command -v "$PY" >/dev/null || PY=python3
|
|
86
|
+
"$PY" ~/.claude/skills/arka-watch/scripts/watch.py "/path/to/video.mp4" --no-whisper
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Read every frame the report lists, note the key visual beats (`t=MM:SS`) —
|
|
90
|
+
they become section boundaries and dwell points in Step 4.
|
|
91
|
+
|
|
92
|
+
Then probe the technical metadata:
|
|
80
93
|
|
|
81
94
|
```bash
|
|
82
95
|
ffprobe -v quiet -print_format json -show_format -show_streams "/path/to/video.mp4"
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dev/watch
|
|
3
|
+
description: >
|
|
4
|
+
Watch a video (URL or local file) so the agent can answer questions about
|
|
5
|
+
what is on screen and what is said. Downloads with yt-dlp, extracts
|
|
6
|
+
auto-scaled frames with ffmpeg (scene-aware or fast keyframes, near-duplicate
|
|
7
|
+
dedup), pulls a timestamped transcript (native captions first, Whisper API
|
|
8
|
+
fallback), and prints frame paths for the agent to Read. TRIGGER: a video
|
|
9
|
+
URL (YouTube, Loom, TikTok, X, Vimeo…) or local video file plus a question;
|
|
10
|
+
"vê este vídeo", "analisa este vídeo", "watch this video", "o que acontece
|
|
11
|
+
em/aos X min", reference-video analysis before design work, video deliverable
|
|
12
|
+
review in the Quality Gate, screen-recording bug reports, "/dev watch".
|
|
13
|
+
SKIP: video PRODUCTION or generation -> content/video-produce or Higgsfield;
|
|
14
|
+
turning a video into a scroll site -> dev/animated-website (it calls this
|
|
15
|
+
skill for its analysis phase); audio-only transcription of a podcast with no
|
|
16
|
+
visual questions -> run --detail transcript and summarize.
|
|
17
|
+
allowed-tools: [Read, Bash, AskUserQuestion]
|
|
18
|
+
metadata:
|
|
19
|
+
origin: community
|
|
20
|
+
source: https://github.com/bradautomates/claude-video
|
|
21
|
+
license: MIT
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
<!-- arka:kb-first-prefix begin -->
|
|
25
|
+
> **KB-first:** query `mcp__obsidian__search_notes` (and
|
|
26
|
+
> `mcp__graphify__query_graph` when configured) and cite `[[wikilinks]]`
|
|
27
|
+
> or graph nodes — or declare the gap — BEFORE any external research.
|
|
28
|
+
> Full doctrine: `arka/SKILL.md` (KB-First Research).
|
|
29
|
+
<!-- arka:kb-first-prefix end -->
|
|
30
|
+
|
|
31
|
+
# /watch — video input for ArkaOS agents
|
|
32
|
+
|
|
33
|
+
You don't have a video input; this skill gives you one. A bundled Python
|
|
34
|
+
pipeline gets captions first, downloads only what it needs, extracts frames
|
|
35
|
+
as JPEGs, produces a timestamped transcript, and prints frame paths. You then
|
|
36
|
+
`Read` each frame to see the video and answer grounded in evidence — the way
|
|
37
|
+
the "frames COMPLETOS" doctrine requires for reference-video analysis.
|
|
38
|
+
|
|
39
|
+
Absorbed from `bradautomates/claude-video` v0.2.0 (MIT) and maintained
|
|
40
|
+
natively by ArkaOS. ArkaOS-specific behavior: config lives in
|
|
41
|
+
`~/.arkaos/watch.env`, API keys resolve from `/arka keys`
|
|
42
|
+
(`~/.arkaos/keys.json`) before any .env file, and every run appends a usage
|
|
43
|
+
record to `~/.arkaos/telemetry/watch-usage.jsonl` (frames + estimated image
|
|
44
|
+
tokens) so CostGovernor sees video analysis cost.
|
|
45
|
+
|
|
46
|
+
## Resolve `SKILL_DIR` (before any command)
|
|
47
|
+
|
|
48
|
+
Set `SKILL_DIR` to the absolute path of the directory containing THIS
|
|
49
|
+
SKILL.md (your harness showed it when you Read this file). The scripts are at
|
|
50
|
+
`SKILL_DIR/scripts/`. Guard once:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
[ -f "$SKILL_DIR/scripts/watch.py" ] || { echo "watch.py not under $SKILL_DIR" >&2; exit 1; }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Run scripts with the canonical ArkaOS interpreter when present, else python3:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
PY="$HOME/.arkaos/bin/arka-py"; command -v "$PY" >/dev/null || PY=python3
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Step 0 — preflight (silent on success)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
"$PY" "${SKILL_DIR}/scripts/setup.py" --check
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Exit 0 → proceed without comment (keyless-after-setup counts as ready — do
|
|
69
|
+
NOT announce that setup is complete). Non-zero:
|
|
70
|
+
|
|
71
|
+
| Exit | Meaning | Action |
|
|
72
|
+
|------|---------|--------|
|
|
73
|
+
| 2 | ffmpeg / ffprobe / yt-dlp missing or broken (a binary that dies at load counts as missing) | run `"$PY" "${SKILL_DIR}/scripts/setup.py"` — auto-installs via brew on macOS, prints commands elsewhere |
|
|
74
|
+
| 3 | genuine first run, no Whisper key | encourage a key (see Keys); user may decline → proceed with `--no-whisper` |
|
|
75
|
+
| 4 | both | installer, then key |
|
|
76
|
+
|
|
77
|
+
`--json` gives the structured status (`status`, `can_proceed`, `first_run`,
|
|
78
|
+
`missing_binaries`, `whisper_backend`, `watch_detail`, `config_file`).
|
|
79
|
+
First-run flow: install binaries first, let the installer scaffold
|
|
80
|
+
`~/.arkaos/watch.env`, then ask the detail preference below.
|
|
81
|
+
|
|
82
|
+
**Keys (Whisper fallback):** preferred home is `/arka keys` —
|
|
83
|
+
`OPENAI_API_KEY` (whisper-1) or `GROQ_API_KEY` (whisper-large-v3, cheaper —
|
|
84
|
+
preferred when both exist). Resolution order: environment →
|
|
85
|
+
`~/.arkaos/keys.json` → `~/.arkaos/watch.env` → `./.env`. A missing key is
|
|
86
|
+
encouraged, never a blocker: captions cover most public videos free.
|
|
87
|
+
|
|
88
|
+
**First-run detail preference:** ask once via `AskUserQuestion` (order
|
|
89
|
+
lightest→heaviest, keep "(recommended)" on balanced): `transcript` (no
|
|
90
|
+
frames) · `efficient` (keyframes, cap 50) · `balanced` (recommended —
|
|
91
|
+
scene-aware, cap 100) · `token-burner` (uncapped). Write the bare
|
|
92
|
+
`WATCH_DETAIL=<value>` line (no inline comment) into `~/.arkaos/watch.env`,
|
|
93
|
+
then `SETUP_COMPLETE=true`.
|
|
94
|
+
|
|
95
|
+
## Invoke
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
"$PY" "${SKILL_DIR}/scripts/watch.py" "<url-or-path>"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Flags: `--detail transcript|efficient|balanced|token-burner` ·
|
|
102
|
+
`--start T` / `--end T` (SS, MM:SS, HH:MM:SS — focused mode, denser fps) ·
|
|
103
|
+
`--timestamps T1,T2,…` (pin frames at transcript-flagged moments) ·
|
|
104
|
+
`--max-frames N` · `--resolution W` (default 512; 1024 only to read on-screen
|
|
105
|
+
text — ~4× image tokens) · `--fps F` (≤2) · `--out-dir DIR` ·
|
|
106
|
+
`--whisper groq|openai` · `--no-whisper` · `--no-dedup`.
|
|
107
|
+
|
|
108
|
+
Then: **Read every frame path the report lists, in one parallel batch.**
|
|
109
|
+
Frames carry `t=MM:SS` absolute timestamps aligned with the transcript.
|
|
110
|
+
Answer citing timestamps; with no question, summarize structure, key moments,
|
|
111
|
+
and spoken content. At `transcript` detail, still synthesize a summary — never
|
|
112
|
+
paste the raw transcript.
|
|
113
|
+
|
|
114
|
+
Cleanup: the report prints the work dir — `rm -rf` it unless follow-ups are
|
|
115
|
+
likely. Follow-ups reuse what is already in context; do NOT re-run.
|
|
116
|
+
|
|
117
|
+
## Frame budget discipline
|
|
118
|
+
|
|
119
|
+
Cost is dominated by frames (~197 image tokens each at 512px). Full-video
|
|
120
|
+
budgets by duration: ≤30s ~30 · ≤1min ~40 · ≤3min ~60 · ≤10min ~80 · >10min
|
|
121
|
+
sparse (warning printed). When the user names a moment or the video exceeds
|
|
122
|
+
~10 minutes, prefer focused mode (`--start`/`--end` — up to 2 fps) over a
|
|
123
|
+
sparse full scan. Dedup collapses held slides and static recordings before
|
|
124
|
+
the cap so the budget buys distinct content.
|
|
125
|
+
|
|
126
|
+
**Transcript-cue frames:** scene selection misses deictic moments ("look
|
|
127
|
+
here", "as you can see") because pointing is low visual change. Read the
|
|
128
|
+
transcript, judge which cues matter (ignore rhetorical "look…"), re-run with
|
|
129
|
+
`--timestamps 4:32,7:10` pointed at the downloaded file in the work dir.
|
|
130
|
+
|
|
131
|
+
## KB write-back (summaries become notes)
|
|
132
|
+
|
|
133
|
+
When the user asks to keep the analysis ("summarize this to a note",
|
|
134
|
+
"guarda isto na KB") — or when the analysis is reference research worth
|
|
135
|
+
keeping (competitor teardown, course/talk notes) — write the summary to the
|
|
136
|
+
Obsidian vault via `mcp__obsidian__write_note`: YAML frontmatter (`type:
|
|
137
|
+
video-analysis`, source URL, duration, transcript source), key moments as a
|
|
138
|
+
timestamped list, and `[[wikilinks]]` to related notes. One note per video;
|
|
139
|
+
a playlist becomes a set of notes plus a MOC. Ask before writing when the
|
|
140
|
+
user did not request persistence.
|
|
141
|
+
|
|
142
|
+
## Failure modes
|
|
143
|
+
|
|
144
|
+
- Download fails (login/region-locked) → tell the user plainly; don't retry.
|
|
145
|
+
- No captions AND no key → frames-only, say so, offer `/arka keys`.
|
|
146
|
+
- Whisper chunk failures → transcript is partial; noted on stderr; retry with
|
|
147
|
+
the other backend if needed.
|
|
148
|
+
- Long-video warning → acknowledge it and offer a focused re-run.
|
|
149
|
+
- Client-confidential recordings → run `--no-whisper` (audio must not leave
|
|
150
|
+
the machine; only extracted audio ever goes to a Whisper API, and only
|
|
151
|
+
when captions are missing).
|
|
152
|
+
|
|
153
|
+
## Security
|
|
154
|
+
|
|
155
|
+
Local-only except: extracted mono audio → `api.groq.com` /
|
|
156
|
+
`api.openai.com`, only on Whisper fallback. yt-dlp requests public data; no
|
|
157
|
+
accounts, no cookies. Keys are never logged or echoed. Working files stay in
|
|
158
|
+
the work dir; config/keys in `~/.arkaos/` (0600).
|
|
159
|
+
|
|
160
|
+
Scripts: `watch.py` (entry) · `download.py` (yt-dlp) · `frames.py` (ffmpeg +
|
|
161
|
+
dedup) · `transcribe.py` (captions) · `whisper.py` (Groq/OpenAI clients) ·
|
|
162
|
+
`setup.py` (preflight/installer) · `config.py` (paths, keys, telemetry).
|