arkaos 4.34.0 → 4.36.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.
Files changed (70) hide show
  1. package/THE-ARKAOS-GUIDE.md +1 -1
  2. package/VERSION +1 -1
  3. package/bin/arka-menubar.py +460 -0
  4. package/config/install-profiles.json +75 -0
  5. package/core/runtime/opencode.py +252 -0
  6. package/core/runtime/registry.py +6 -1
  7. package/harness/codex/AGENTS.md +1 -1
  8. package/harness/copilot/copilot-instructions.md +1 -1
  9. package/harness/cursor/rules/arkaos.mdc +2 -2
  10. package/harness/gemini/GEMINI.md +1 -1
  11. package/harness/opencode/AGENTS.md +1 -1
  12. package/harness/opencode/agents/arka-architect-gabriel.md +12 -0
  13. package/harness/opencode/agents/arka-brand-director-valentina.md +12 -0
  14. package/harness/opencode/agents/arka-cfo-helena.md +12 -0
  15. package/harness/opencode/agents/arka-chief-of-staff-afonso.md +12 -0
  16. package/harness/opencode/agents/arka-community-strategist-beatriz.md +12 -0
  17. package/harness/opencode/agents/arka-content-strategist-rafael.md +12 -0
  18. package/harness/opencode/agents/arka-conversion-strategist-ines.md +12 -0
  19. package/harness/opencode/agents/arka-coo-sofia.md +12 -0
  20. package/harness/opencode/agents/arka-copy-director-eduardo.md +12 -0
  21. package/harness/opencode/agents/arka-cqo-marta.md +12 -0
  22. package/harness/opencode/agents/arka-cto-marco.md +12 -0
  23. package/harness/opencode/agents/arka-design-ops-lead-iris.md +12 -0
  24. package/harness/opencode/agents/arka-ecom-director-ricardo.md +12 -0
  25. package/harness/opencode/agents/arka-knowledge-director-clara.md +12 -0
  26. package/harness/opencode/agents/arka-leadership-director-rodrigo.md +12 -0
  27. package/harness/opencode/agents/arka-marketing-director-luna.md +12 -0
  28. package/harness/opencode/agents/arka-ops-lead-daniel.md +12 -0
  29. package/harness/opencode/agents/arka-pm-director-carolina.md +12 -0
  30. package/harness/opencode/agents/arka-revops-lead-vicente.md +12 -0
  31. package/harness/opencode/agents/arka-saas-strategist-tiago.md +12 -0
  32. package/harness/opencode/agents/arka-sales-director-miguel.md +12 -0
  33. package/harness/opencode/agents/arka-strategy-director-tomas.md +12 -0
  34. package/harness/opencode/agents/arka-tech-director-francisca.md +12 -0
  35. package/harness/opencode/agents/arka-tech-lead-paulo.md +12 -0
  36. package/harness/opencode/agents/arka-video-producer-simao.md +12 -0
  37. package/harness/opencode/commands/arka-brand.md +9 -0
  38. package/harness/opencode/commands/arka-community.md +9 -0
  39. package/harness/opencode/commands/arka-content.md +9 -0
  40. package/harness/opencode/commands/arka-dev.md +9 -0
  41. package/harness/opencode/commands/arka-ecom.md +9 -0
  42. package/harness/opencode/commands/arka-fin.md +9 -0
  43. package/harness/opencode/commands/arka-kb.md +9 -0
  44. package/harness/opencode/commands/arka-landing.md +9 -0
  45. package/harness/opencode/commands/arka-lead.md +9 -0
  46. package/harness/opencode/commands/arka-mkt.md +9 -0
  47. package/harness/opencode/commands/arka-ops.md +9 -0
  48. package/harness/opencode/commands/arka-org.md +9 -0
  49. package/harness/opencode/commands/arka-pm.md +9 -0
  50. package/harness/opencode/commands/arka-saas.md +9 -0
  51. package/harness/opencode/commands/arka-sales.md +9 -0
  52. package/harness/opencode/commands/arka-strat.md +9 -0
  53. package/harness/opencode/opencode.json +16 -0
  54. package/harness/zed/.rules +1 -1
  55. package/installer/adapters/opencode.js +118 -0
  56. package/installer/cli.js +31 -1
  57. package/installer/detect-runtime.js +18 -0
  58. package/installer/doctor.js +202 -2
  59. package/installer/index.js +174 -88
  60. package/installer/menubar.js +262 -0
  61. package/installer/product-stats.js +93 -0
  62. package/installer/profile.js +75 -0
  63. package/installer/prompts.js +303 -41
  64. package/installer/services.js +487 -0
  65. package/installer/ui.js +190 -0
  66. package/installer/update.js +212 -95
  67. package/knowledge/skills-manifest.json +1 -1
  68. package/package.json +6 -1
  69. package/pyproject.toml +1 -1
  70. package/scripts/harness_gen.py +98 -1
@@ -1,6 +1,6 @@
1
1
  # The ArkaOS Guide
2
2
 
3
- > v4.34.0 — 89 agents, 17 departments, 331 skills, 297 commands, 16 ADRs.
3
+ > v4.36.0 — 89 agents, 17 departments, 331 skills, 297 commands, 17 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.34.0
1
+ 4.36.0
@@ -0,0 +1,460 @@
1
+ #!/usr/bin/env python3
2
+ """ArkaOS menu bar launcher (Foundation PR-5).
3
+
4
+ A lightweight macOS menu bar app (rumps) that surfaces the ArkaOS
5
+ runtime state and one-click actions:
6
+
7
+ - Check for updates -> scripts/auto-update.sh --force (PR-1 daemon)
8
+ - Open Dashboard -> start-dashboard.sh ensure + open UI port
9
+ - Start Ollama -> open -a Ollama (fallback: ollama serve)
10
+ [local-ai profile only, when stopped]
11
+ - Doctor -> Terminal running `npx arkaos doctor`
12
+ - Auto-update on/off -> npx arkaos autoupdate enable|disable
13
+ - Quit
14
+
15
+ Posture (matches scripts/auto-update.sh): every failure path logs and
16
+ exits 0 — a broken login item must never crash. rumps import is guarded:
17
+ non-macOS, missing rumps, or headless -> clean exit 0 with a hint.
18
+
19
+ State model and menu-visibility logic are PURE functions so tests
20
+ exercise them via the introspection flags without rumps or a display:
21
+
22
+ arka-menubar.py --print-state JSON of read_state()
23
+ arka-menubar.py --print-menu JSON of visible menu item ids
24
+
25
+ Test hooks (env): ARKA_MENUBAR_HOME overrides the ~/.arkaos parent dir;
26
+ ARKA_MENUBAR_OLLAMA (absent|stopped|running) overrides the live probe.
27
+ The probe itself only runs on the local-ai profile (the only profile
28
+ that ever surfaces Start Ollama); other profiles never spawn ollama.
29
+ """
30
+
31
+ # PEP 604 annotations (`Path | None`) are evaluated at def time without
32
+ # this import and raise TypeError on Python < 3.10 — and the plist's
33
+ # last-resort interpreter is the macOS system /usr/bin/python3 (3.9).
34
+ # The future import turns them into strings, importable everywhere.
35
+ from __future__ import annotations
36
+
37
+ import json
38
+ import os
39
+ import shutil
40
+ import subprocess
41
+ import sys
42
+ import threading
43
+ from pathlib import Path
44
+
45
+ VALID_PROFILES = ("essential", "complete", "local-ai")
46
+ REFRESH_SECONDS = 60
47
+ TITLE = "▲" # ▲ — brand wordmark glyph
48
+ TITLE_PENDING = "▲ •" # ▲ • — sync pending badge
49
+ # Contract with installer/menubar.js (optoutPath) and the PR-1 daemon
50
+ # (installer/autoupdate.js optoutPath). menubar.test.js locks parity
51
+ # against the real JS modules — never rename one side alone.
52
+ MENUBAR_OPTOUT_BASENAME = "menubar.optout"
53
+ AUTOUPDATE_OPTOUT_BASENAME = "autoupdate.optout"
54
+
55
+ USAGE = """arka-menubar.py — ArkaOS menu bar launcher (macOS)
56
+ (no args) run the menu bar app (exits 0 when unsupported)
57
+ --print-state JSON snapshot of the runtime state
58
+ --print-menu JSON list of visible menu item ids
59
+ --help this text
60
+ """
61
+
62
+
63
+ def arka_home() -> Path:
64
+ override = os.environ.get("ARKA_MENUBAR_HOME", "")
65
+ base = Path(override) if override else Path.home()
66
+ return base / ".arkaos"
67
+
68
+
69
+ # ── Pure state model ─────────────────────────────────────────────────────
70
+
71
+
72
+ def read_state(home: Path | None = None) -> dict:
73
+ """Read-only snapshot of the runtime state. Never throws."""
74
+ home = home or arka_home()
75
+ state = {
76
+ "version": None,
77
+ "sync_pending": False,
78
+ "profile": "essential",
79
+ "autoupdate_on": True,
80
+ }
81
+ try:
82
+ manifest = json.loads((home / "install-manifest.json").read_text())
83
+ state["version"] = manifest.get("version") or None
84
+ except Exception:
85
+ pass
86
+ try:
87
+ sync = json.loads((home / "sync-state.json").read_text())
88
+ state["sync_pending"] = sync.get("version") == "pending-sync"
89
+ except Exception:
90
+ pass
91
+ try:
92
+ profile = json.loads((home / "profile.json").read_text())
93
+ value = str(profile.get("installProfile", "essential")).strip().lower()
94
+ state["profile"] = value if value in VALID_PROFILES else "essential"
95
+ except Exception:
96
+ pass
97
+ state["autoupdate_on"] = not (home / AUTOUPDATE_OPTOUT_BASENAME).exists()
98
+ return state
99
+
100
+
101
+ def ollama_status() -> str:
102
+ """absent | stopped | running — read-only probes, short timeouts."""
103
+ override = os.environ.get("ARKA_MENUBAR_OLLAMA", "")
104
+ if override in ("absent", "stopped", "running"):
105
+ return override
106
+ if shutil.which("ollama") is None:
107
+ return "absent"
108
+ try:
109
+ subprocess.run(
110
+ ["ollama", "list"], capture_output=True, timeout=2, check=True
111
+ )
112
+ return "running"
113
+ except Exception:
114
+ return "stopped"
115
+
116
+
117
+ def ollama_status_for(state: dict) -> str:
118
+ """Gate the live probe: only the local-ai profile ever surfaces the
119
+ Start Ollama item, so every other profile skips the subprocess."""
120
+ if state.get("profile") != "local-ai":
121
+ return "absent"
122
+ return ollama_status()
123
+
124
+
125
+ def menu_items(state: dict, ollama: str) -> list:
126
+ """Pure: visible menu item ids for a given state."""
127
+ items = ["check_updates", "open_dashboard", "doctor"]
128
+ if state.get("profile") == "local-ai" and ollama == "stopped":
129
+ items.append("start_ollama")
130
+ items.append("autoupdate_toggle")
131
+ items.append("disable")
132
+ items.append("quit")
133
+ return items
134
+
135
+
136
+ def title_for(state: dict) -> str:
137
+ return TITLE_PENDING if state.get("sync_pending") else TITLE
138
+
139
+
140
+ def version_label(state: dict) -> str:
141
+ """User-visible copy — never renders 'vunknown'."""
142
+ version = state.get("version")
143
+ return f"ArkaOS v{version}" if version else "ArkaOS (version unknown)"
144
+
145
+
146
+ # ── Action helpers (subprocess, never blocking the UI thread) ────────────
147
+
148
+
149
+ def stable_script(name: str) -> Path | None:
150
+ """Resolve a scripts/ file: purge-proof ~/.arkaos/lib snapshot first,
151
+ then the .repo-path reference (autoupdate.js::stableRoot parity)."""
152
+ home = arka_home()
153
+ lib = home / "lib" / "scripts" / name
154
+ if lib.exists():
155
+ return lib
156
+ try:
157
+ repo = Path((home / ".repo-path").read_text().strip())
158
+ candidate = repo / "scripts" / name
159
+ if candidate.exists():
160
+ return candidate
161
+ except Exception:
162
+ pass
163
+ return None
164
+
165
+
166
+ def log_line(message: str) -> None:
167
+ try:
168
+ log_dir = arka_home() / "logs"
169
+ log_dir.mkdir(parents=True, exist_ok=True)
170
+ with open(log_dir / "menubar.log", "a", encoding="utf-8") as handle:
171
+ handle.write(message.rstrip() + "\n")
172
+ except Exception:
173
+ pass
174
+
175
+
176
+ def action_check_updates() -> None:
177
+ script = stable_script("auto-update.sh")
178
+ if script is None:
179
+ log_line("check_updates: auto-update.sh not found")
180
+ return
181
+ subprocess.Popen(["/bin/bash", str(script), "--force"])
182
+
183
+
184
+ def action_open_dashboard() -> None:
185
+ script = stable_script("start-dashboard.sh")
186
+ if script is not None:
187
+ try:
188
+ subprocess.run(["/bin/bash", str(script), "ensure"], timeout=120)
189
+ except Exception as err:
190
+ log_line(f"open_dashboard: ensure failed ({err})")
191
+ ui_port = ""
192
+ try:
193
+ for line in (arka_home() / "dashboard.ports").read_text().splitlines():
194
+ if line.startswith("UI_PORT="):
195
+ ui_port = line.split("=", 1)[1].strip()
196
+ except Exception:
197
+ pass
198
+ if ui_port.isdigit():
199
+ subprocess.run(["/usr/bin/open", f"http://localhost:{ui_port}"], timeout=15)
200
+ else:
201
+ log_line(
202
+ "open_dashboard: no UI_PORT after start-dashboard.sh ensure — "
203
+ "check ~/.arkaos/logs for the dashboard startup error"
204
+ )
205
+
206
+
207
+ def action_start_ollama() -> None:
208
+ # Operator decision (PR-5 Phase 0): the app first, `serve` as fallback.
209
+ result = subprocess.run(["/usr/bin/open", "-a", "Ollama"],
210
+ capture_output=True, timeout=15)
211
+ if result.returncode != 0:
212
+ if shutil.which("ollama"):
213
+ subprocess.Popen(
214
+ ["ollama", "serve"],
215
+ stdout=subprocess.DEVNULL,
216
+ stderr=subprocess.DEVNULL,
217
+ )
218
+ else:
219
+ log_line("start_ollama: neither Ollama.app nor ollama binary found")
220
+
221
+
222
+ def action_doctor() -> None:
223
+ subprocess.run([
224
+ "/usr/bin/osascript", "-e",
225
+ 'tell application "Terminal" to activate',
226
+ "-e",
227
+ 'tell application "Terminal" to do script "npx arkaos doctor"',
228
+ ], capture_output=True, timeout=15)
229
+
230
+
231
+ def action_autoupdate(enable: bool) -> None:
232
+ """Runs on a worker thread (npx resolves the registry — slow/offline
233
+ must degrade to a logged line, never a silent no-op)."""
234
+ verb = "enable" if enable else "disable"
235
+ if shutil.which("npx") is None:
236
+ log_line(
237
+ "autoupdate_toggle: npx not on the LaunchAgent PATH — "
238
+ f"run manually: npx arkaos autoupdate {verb}"
239
+ )
240
+ return
241
+ subprocess.run(["npx", "arkaos", "autoupdate", verb],
242
+ capture_output=True, timeout=180)
243
+
244
+
245
+ def action_disable_menubar() -> None:
246
+ """Permanent opt-out from the menu itself (QG M7): writes the marker
247
+ installer/menubar.js honors; the startup guard in run_app makes any
248
+ remaining RunAtLoad an instant no-op until `npx arkaos menubar enable`."""
249
+ marker = arka_home() / MENUBAR_OPTOUT_BASENAME
250
+ marker.parent.mkdir(parents=True, exist_ok=True)
251
+ marker.write_text("disabled from the menu bar\n", encoding="utf-8")
252
+ log_line("disable: opt-out marker written — re-enable: npx arkaos menubar enable")
253
+
254
+
255
+ # ── rumps app (guarded import — never a crashing login item) ─────────────
256
+
257
+
258
+ def run_app() -> int:
259
+ if sys.platform != "darwin":
260
+ print("arka-menubar: macOS only — nothing to do")
261
+ return 0
262
+ # Permanent opt-out (QG M7): the plist may still RunAtLoad until an
263
+ # update removes it — the marker makes that launch an instant no-op.
264
+ if (arka_home() / MENUBAR_OPTOUT_BASENAME).exists():
265
+ print("arka-menubar: user opt-out — exiting (re-enable: npx arkaos menubar enable)")
266
+ return 0
267
+ try:
268
+ import rumps
269
+ except Exception as err: # missing dep, headless session, SIP oddity
270
+ print(
271
+ "arka-menubar: rumps unavailable "
272
+ f"({err}) — install: ~/.arkaos/venv/bin/pip install rumps"
273
+ )
274
+ return 0
275
+
276
+ class ArkaMenuBar(rumps.App):
277
+ def __init__(self):
278
+ super().__init__(TITLE, quit_button=None)
279
+ self._rumps = rumps
280
+ self._pollers = set()
281
+ # QG r2 follow-ups: the ollama probe result is CACHED and
282
+ # refreshed by a worker (the 2s `ollama list` subprocess
283
+ # never runs on the menu runloop); the auto-update toggle
284
+ # is disabled while its worker is in flight.
285
+ self._ollama_cache = "absent"
286
+ self._probe_running = False
287
+ self._toggle_inflight = False
288
+ self.refresh(None)
289
+ self.timer = rumps.Timer(self.refresh, REFRESH_SECONDS)
290
+ self.timer.start()
291
+
292
+ def _schedule_ollama_probe(self):
293
+ """Worker-side probe -> cache; redraw only on change."""
294
+ if self._probe_running:
295
+ return
296
+ self._probe_running = True
297
+ before = self._ollama_cache
298
+
299
+ def probe():
300
+ try:
301
+ self._ollama_cache = ollama_status()
302
+ finally:
303
+ self._probe_running = False
304
+
305
+ worker = threading.Thread(target=probe, daemon=True)
306
+ worker.start()
307
+
308
+ def poll(timer):
309
+ if not worker.is_alive():
310
+ timer.stop()
311
+ self._pollers.discard(timer)
312
+ if self._ollama_cache != before:
313
+ self.refresh(None)
314
+
315
+ poller = self._rumps.Timer(poll, 1)
316
+ self._pollers.add(poller)
317
+ poller.start()
318
+
319
+ def _spawn(self, work, refresh_after=False):
320
+ """Run side-effect work off the AppKit main thread (a blocking
321
+ subprocess in a rumps callback freezes the whole menu bar).
322
+ The worker only runs subprocesses and reads files — ALL rumps
323
+ interaction stays on the main thread: an optional 1s poll timer
324
+ (main thread) refreshes the menu once the worker finishes.
325
+ Worker bodies are exception-guarded to log_line — a missing
326
+ binary must never die silently (QG M5)."""
327
+ def guarded():
328
+ try:
329
+ work()
330
+ except Exception as err:
331
+ log_line(f"action: {err}")
332
+
333
+ worker = threading.Thread(target=guarded, daemon=True)
334
+ worker.start()
335
+ if not refresh_after:
336
+ return
337
+
338
+ def poll(timer):
339
+ if not worker.is_alive():
340
+ timer.stop()
341
+ self._pollers.discard(timer)
342
+ self.refresh(None)
343
+
344
+ poller = self._rumps.Timer(poll, 1)
345
+ self._pollers.add(poller)
346
+ poller.start()
347
+
348
+ def refresh(self, _sender):
349
+ state = read_state()
350
+ if state["profile"] == "local-ai":
351
+ ollama = self._ollama_cache
352
+ self._schedule_ollama_probe()
353
+ else:
354
+ ollama = "absent"
355
+ self.title = title_for(state)
356
+ self.menu.clear()
357
+ info = rumps.MenuItem(version_label(state))
358
+ info.set_callback(None) # informational, not clickable
359
+ entries = [info]
360
+ if state["sync_pending"]:
361
+ pending = rumps.MenuItem("Sync pending — open a Claude session")
362
+ pending.set_callback(None)
363
+ entries.append(pending)
364
+ entries.append(rumps.separator)
365
+ visible = menu_items(state, ollama)
366
+ labels = {
367
+ "check_updates": ("Check for updates", self.on_check_updates),
368
+ "open_dashboard": ("Open Dashboard", self.on_open_dashboard),
369
+ "doctor": ("Run Doctor", self.on_doctor),
370
+ "start_ollama": ("Start Ollama", self.on_start_ollama),
371
+ "autoupdate_toggle": (
372
+ "Auto-update: switching…" if self._toggle_inflight
373
+ else ("Auto-update: on" if state["autoupdate_on"] else "Auto-update: off"),
374
+ None if self._toggle_inflight else self.on_autoupdate_toggle,
375
+ ),
376
+ "disable": ("Disable menu bar (permanent)", self.on_disable),
377
+ "quit": ("Quit until next login", self.on_quit),
378
+ }
379
+ for item_id in visible:
380
+ label, callback = labels[item_id]
381
+ entry = rumps.MenuItem(label, callback=callback)
382
+ if item_id == "autoupdate_toggle" and not self._toggle_inflight:
383
+ entry.state = 1 if state["autoupdate_on"] else 0
384
+ if item_id == "disable":
385
+ entries.append(rumps.separator)
386
+ entries.append(entry)
387
+ self.menu.update(entries)
388
+
389
+ def on_check_updates(self, _):
390
+ # Popen is non-blocking, but a fork/exec OSError must not
391
+ # propagate into the rumps callback (QG r2 minor).
392
+ try:
393
+ action_check_updates()
394
+ except Exception as err:
395
+ log_line(f"check_updates: {err}")
396
+
397
+ def on_open_dashboard(self, _):
398
+ self._spawn(action_open_dashboard)
399
+
400
+ def on_doctor(self, _):
401
+ self._spawn(action_doctor)
402
+
403
+ def on_start_ollama(self, _):
404
+ self._spawn(action_start_ollama, refresh_after=True)
405
+
406
+ def on_autoupdate_toggle(self, _):
407
+ # Guard against double-fire while the (up to 180s) npx
408
+ # worker runs — the item is disabled and relabelled until
409
+ # the post-worker refresh (QG r2 minor).
410
+ if self._toggle_inflight:
411
+ return
412
+ self._toggle_inflight = True
413
+ enable = not read_state()["autoupdate_on"]
414
+
415
+ def work():
416
+ try:
417
+ action_autoupdate(enable=enable)
418
+ finally:
419
+ self._toggle_inflight = False
420
+
421
+ self._spawn(work, refresh_after=True)
422
+ self.refresh(None)
423
+
424
+ def on_disable(self, _):
425
+ try:
426
+ action_disable_menubar()
427
+ except Exception as err:
428
+ log_line(f"disable: {err}")
429
+ self._rumps.quit_application()
430
+
431
+ def on_quit(self, _):
432
+ self._rumps.quit_application()
433
+
434
+ try:
435
+ ArkaMenuBar().run()
436
+ except Exception as err:
437
+ log_line(f"fatal: {err}")
438
+ print(f"arka-menubar: exiting cleanly after error ({err})")
439
+ return 0
440
+
441
+
442
+ def main(argv: list) -> int:
443
+ if "--help" in argv or "-h" in argv:
444
+ print(USAGE)
445
+ return 0
446
+ if "--print-state" in argv:
447
+ print(json.dumps(read_state()))
448
+ return 0
449
+ if "--print-menu" in argv:
450
+ state = read_state()
451
+ print(json.dumps(menu_items(state, ollama_status_for(state))))
452
+ return 0
453
+ if argv and argv[0].startswith("-"):
454
+ print(f"arka-menubar: unknown option {argv[0]}\n\n{USAGE}")
455
+ return 2
456
+ return run_app()
457
+
458
+
459
+ if __name__ == "__main__":
460
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,75 @@
1
+ {
2
+ "_meta": {
3
+ "description": "ArkaOS install profiles — data-driven profile→services manifest (Foundation PR-4)",
4
+ "note": "profiles.*.services reference ids under services; extends chains must be acyclic. Consumed by installer/services.js (reconciliation) and installer/doctor.js (per-profile checks). Essential mirrors what a fresh install already guarantees so reconciliation can repair it."
5
+ },
6
+ "profiles": {
7
+ "essential": {
8
+ "label": "Essential",
9
+ "services": ["venv-core", "dashboard-deps", "mcp-infrastructure", "graphify"]
10
+ },
11
+ "complete": {
12
+ "label": "Complete",
13
+ "extends": "essential",
14
+ "services": ["litellm-proxy", "ffmpeg", "whisper"]
15
+ },
16
+ "local-ai": {
17
+ "label": "Local AI",
18
+ "extends": "complete",
19
+ "services": ["ollama", "ollama-execution-model"]
20
+ }
21
+ },
22
+ "services": {
23
+ "venv-core": {
24
+ "label": "Python venv + core deps",
25
+ "kind": "pip",
26
+ "packages": "pyyaml pydantic rich click jinja2",
27
+ "modules": ["yaml", "pydantic"]
28
+ },
29
+ "dashboard-deps": {
30
+ "label": "Dashboard API deps (fastapi, uvicorn)",
31
+ "kind": "pip",
32
+ "packages": "fastapi uvicorn python-multipart",
33
+ "modules": ["fastapi", "uvicorn"]
34
+ },
35
+ "mcp-infrastructure": {
36
+ "label": "MCP infrastructure (registry + servers)",
37
+ "kind": "file",
38
+ "path": "~/.claude/skills/arka/mcps/registry.json",
39
+ "hint": "Run: npx arkaos@latest update (redeploys the MCP bundle)"
40
+ },
41
+ "graphify": {
42
+ "label": "Graphify grounding CLI",
43
+ "kind": "graphify"
44
+ },
45
+ "litellm-proxy": {
46
+ "label": "LiteLLM proxy (gateway prerequisite)",
47
+ "kind": "pip",
48
+ "packages": "litellm[proxy]",
49
+ "modules": ["litellm"]
50
+ },
51
+ "ffmpeg": {
52
+ "label": "FFmpeg (media encode / transcription)",
53
+ "kind": "system-package",
54
+ "consent": true,
55
+ "binary": "ffmpeg",
56
+ "packages": { "brew": "ffmpeg", "apt": "ffmpeg", "winget": "Gyan.FFmpeg", "choco": "ffmpeg" }
57
+ },
58
+ "whisper": {
59
+ "label": "Whisper transcription (faster-whisper)",
60
+ "kind": "pip",
61
+ "packages": "faster-whisper",
62
+ "modules": ["faster_whisper"]
63
+ },
64
+ "ollama": {
65
+ "label": "Ollama runtime (local LLM backend)",
66
+ "kind": "ollama",
67
+ "consent": true
68
+ },
69
+ "ollama-execution-model": {
70
+ "label": "Local execution model (Model Fabric)",
71
+ "kind": "ollama-model",
72
+ "requires": ["ollama"]
73
+ }
74
+ }
75
+ }